Scala:指定默认的泛型类型,而不是Nothing
我有一对类似这样的课程.有一个Generator可以根据一些类级别的值生成一个值,一个GeneratorFactory构造一个Generator.
case class Generator[T,S](a: T,b: T,c: T) { def generate(implicit bf: CanBuildFrom[S,T,S]): S = bf() += (a,b,c) result } case class GeneratorFactory[T]() { def build[S <% Seq[T]](seq: S) = Generator[T,S](seq(0),seq(1),seq(2)) } 你会注意到GeneratorFactory.build接受一个类型为S的参数,Generator.generate产生一个S型的值,但是Generator没有存储类型S. 我们可以使用这样的类.工厂工作在一系列Char,并且生成一个String,因为build被赋予了一个String. val gb = GeneratorFactory[Char]() val g = gb.build("this string") val o = g.generate 这是很好的,隐式地处理String类型,因为我们使用GeneratorFactory. 问题 现在,当我想要构建一个发电机而不经过工厂时,就会出现问题.我想能够做到这一点: val g2 = Generator('a','b','c') g2.generate // error 但是我得到一个错误,因为g2有类型Generator [Char,Nothing]和Scala“不能使用类型为Nothing的集合来构造一个类型为Not的类型为Not的集合. 我想要的是一种告诉Scala的方式,S的“默认值”类似于Seq [T]而不是Nothing.借用默认参数的语法,我们可以将其看作是: case class Generator[T,S=Seq[T]] 解决方案不足 当然,如果我们明确地告诉生成器它的生成类型应该是什么,但是我认为一个默认选项会更好(我的实际场景更复杂): val g3 = Generator[Char,String]('a','c') val o3 = g3.generate // works fine,o3 has type String 我想到了将Generator.apply重载为具有一个通用类型的版本,但这会导致错误,因为Scala无法区分两个应用定义: object Generator { def apply[T](a: T,c: T) = new Generator[T,Seq[T]](a,c) } val g2 = Generator('a','c') // error: ambiguous reference to overloaded definition 所需输出 我想要的方法是简单地构造一个Generator而不指定类型S,并将其默认为Seq [T],以便我可以做到: val g2 = Generator('a','c') val o2 = g2.generate // o2 is of type Seq[Char] 我认为这将是用户最干净的界面. 有什么想法可以让这个发生吗? 解决方法
有没有理由你不想使用基本特征,然后根据需要在其子类中缩小S?以下例子符合您的要求:
import scala.collection.generic.CanBuildFrom trait Generator[T] { type S def a: T; def b: T; def c: T def generate(implicit bf: CanBuildFrom[S,S]): S = bf() += (a,c) result } object Generator { def apply[T](x: T,y: T,z: T) = new Generator[T] { type S = Seq[T] val (a,c) = (x,y,z) } } case class GeneratorFactory[T]() { def build[U <% Seq[T]](seq: U) = new Generator[T] { type S = U val Seq(a,c,_*) = seq: Seq[T] } } 我使S成为一种抽象类型,以便使用户不再需要它,但是您也可以将其设置为一个类型参数. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |