Scala中_>:与<:参数类型是什么?泛型样例类代码咨询
嘿,我来帮你把Scala里的<:和_>:这俩泛型约束符号说清楚,再结合你的代码场景聊聊怎么用~
<:和_>:到底是什么? 这俩都是Scala里用来约束泛型类型范围的语法,核心是帮编译器确定哪些类型是合法的,避免类型错误:
<:(上界约束):表示泛型类型必须是指定类型的子类(或自身)。比如写T <: Serializable,意思就是T要么是Serializable本身,要么是它的子类。_>:(下界约束):表示泛型类型必须是指定类型的父类(或自身)。比如T _>: TypeA,就是说T得是TypeA的父类,或者就是TypeA自己。
简单来说,上界是“不能比某个类型更泛化”,下界是“不能比某个类型更具体”,两者都是用来缩小泛型的合法范围,让代码更安全。
先看你的样例类:
case class TypeA(user_id: String, device_id: String) extends Serializable case class TypeB(user_id: String, device_id: String, org_id: String, app_name: String) extends Serializable
这俩都是Serializable的子类,而且样例类默认会继承Product trait(用来实现类的结构化操作)。
再看你的代码片段:s._2.read[TypeA]((Encoders.product[TypeA].sche...,这里的read方法应该是一个泛型方法,用来读取数据集并转换成指定的样例类类型。这种场景下,**上界约束<:**会非常有用——你可以给read方法加上约束,限定它只能处理Product with Serializable类型(刚好匹配你的TypeA、TypeB):
// 举个read方法的定义例子 def read[T <: Product with Serializable](schema: Schema): Dataset[T] = { // 内部逻辑可以放心用Encoders.product[T],因为T是Product子类 spark.read.schema(schema).load().as[T](Encoders.product[T]) }
这个约束能确保传入的T一定是可序列化的、结构化的样例类,编译器会帮你过滤掉不符合的类型,避免运行时错误。
那什么时候会用到_>:呢?比如你有一个方法需要接收TypeA的父类类型(比如Serializable或者AnyRef),这时用下界约束可以确保类型兼容。不过在你的“读取数据集转样例类”场景里,上界约束会更常用。
从你的代码片段看,你用Map+模式匹配来区分不同类型的读取逻辑,这里可以通过统一的 trait 来规范readHandlersMap的类型,让代码更符合类型安全:
// 先定义一个统一的Handler trait,带上界约束 trait DataHandler[T <: Product with Serializable] { def read(schema: Schema): Dataset[T] } // 分别实现TypeA和TypeB的Handler class TypeAHandler extends DataHandler[TypeA] { override def read(schema: Schema): Dataset[TypeA] = { spark.read.schema(schema).load().as[TypeA](Encoders.product[TypeA]) } } class TypeBHandler extends DataHandler[TypeB] { override def read(schema: Schema): Dataset[TypeB] = { spark.read.schema(schema).load().as[TypeB](Encoders.product[TypeB]) } } // 定义Map时统一类型,编译器能更好地推断类型 val readHandlersMap: Map[String, DataHandler[_ <: Product with Serializable]] = Map( "a" -> new TypeAHandler, "b" -> new TypeBHandler )
这样后续模式匹配的时候,代码会更清晰,也不容易出现类型不兼容的问题。
内容的提问来源于stack exchange,提问作者sparkonhdfs

