scala – 简化类型注释
我创建了一个pimp方法,整理,可以从任何Traversable或任何可以被强制转换为可遍历的类型中使用,如下例所示:
val ints = List(0,9,4,5,-3,-5,6,-2,1,-2) val results = ints collate { case i: Int if(i < 0) => i.floatValue } andThen { case i: Int if(i>5) => i.toString } andThen { case i: Int if(i==0) => i } toTuple /* results: (List[Float],List[java.lang.String],List[Int],List[Int]) = (List(-3.0,-5.0,-2.0,-3.0,-2.0),List(9,6),List(0,0),List(4,1)) */ 如果你愿意的话,可以把它想象成一个联盟’twixt收集和分区的邪恶产生. 它的定义如下: import collection.generic.CanBuildFrom class Collatable[Repr <% Traversable[T],T](xs: Repr) { // Results handling stuff,bit like a poor-man's HList,feel free to skip... trait Results { def remainder: Repr type Append[That] <: Results def append[That](tup: (That,Repr)): Append[That] def andThen[R,That](pf: PartialFunction[T,R]) (implicit matchesBuilder: CanBuildFrom[Repr,R,That],remainderBuilder: CanBuildFrom[Repr,T,Repr] ) = { val more = (new Collatable[Repr,T](remainder)).collateOne[R,That](pf) append(more) } } case class Results9[M1,M2,M3,M4,M5,M6,M7,M8,M9]( m1: M1,m2: M2,m3: M3,m4: M4,m5: M5,m6: M6,m7: M7,m8: M8,m9: M9,remainder: Repr) extends Results { implicit def toTuple = (m1,m2,m3,m4,m5,m6,m7,m8,m9,remainder) def append[That](tup: (That,Repr)) = error("too many") } // ... skip a bit,still in results logic ... case class Results2[M1,M2]( m1: M1,remainder) type Append[That] = Results3[M1,That] def append[That](tup: (That,Repr)) = Results3(m1,tup._1,tup._2) } case class Results1[M1](matches: M1,remainder: Repr) extends Results { implicit def toTuple = (matches,remainder) type Append[That] = Results2[M1,Repr)) = Results2(matches,tup._2) } // and now... Our feature presentation! def collateOne[R,R]) (implicit matchesBuilder: CanBuildFrom[Repr,Repr] ) = { val matches = matchesBuilder(xs) val remainder = remainderBuilder(xs) for (x <- xs) if (pf.isDefinedAt(x)) matches += pf(x) else remainder += x (matches.result,remainder.result) } def collate[R,Repr] ): Results1[That] = { val tup = collateOne[R,That](pf) Results1(tup._1,tup._2) } } object Collatable { def apply[Repr,T](xs: Repr)(implicit witness: Repr => Traversable[T]) = { new Collatable[Repr,T](xs) } } implicit def traversableIsCollatable[CC[X] <: Traversable[X],A](xs: CC[A]) = Collatable[CC[A],A](xs) implicit def stringIsCollatable(xs: String) = Collatable[String,Char](xs) 从概念上讲,一旦你理解了CanBuildFrom是如何工作的,那并不是那么令人生畏,但我发现它已经被样板所淹没 – 特别是有了暗示. 我知道我可以通过使用HList来大大简化ResultX逻辑,这是我可能会做的事情,所以这段代码并不特别让我担心. 我也知道如果我能够将Repr限制为Traversable的子类型,我可以让我的生活变得更加容易.但我拒绝这样做,因为它不能用于对抗Strings.出于同样的原因,我也想避免强制部分函数返回T的子类型 – 虽然这不是一个问题,因为我总是可以将我的逻辑分解为不同的整理和映射操作. 更值得关注的是CanBuildFrom [Repr,Repr],我似乎不断重复,并且从我的方法签名中隐藏了重要的东西.这是我认为可以在课程级别定义一次的东西,但我还没有找到使其工作的方法. 有任何想法吗? 解决方法
只需定义类型:
class Collatable[Repr <% Traversable[T],feel free to skip... type With[-Elem] = CanBuildFrom[Repr,Elem,Repr] type CanBuild[-Elem,+To] = CanBuildFrom[Repr,To] trait Results { def remainder: Repr type Append[That] <: Results def append[That](tup: (That,R]) (implicit matchesBuilder: CanBuild[R,remainderBuilder: With[T] ) = { val more = (new Collatable[Repr,That](pf) append(more) } } def collateOne[R,R]) (implicit matchesBuilder: CanBuild[R,remainderBuilder: With[T] ) = { val matches = matchesBuilder(xs) val remainder = remainderBuilder(xs) for (x <- xs) if (pf.isDefinedAt(x)) matches += pf(x) else remainder += x (matches.result,remainder.result) } } 另一方面,我只是注意到整个Collat??able在Repr和T上进行了参数化,那么为什么不在该级别获得隐式的preserveBuilder呢?编辑因为还没有推断出T.现在,我不知道如何摆脱额外的暗示. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |