我试图定义"不可变的setter traits",以及那些的通用函数。
我有一个有效的实施方案,但我对#34;未经检查"有点不安。模式匹配的警告。我不确定我能做些什么。
type Point = (Double, Double)
trait Sizable[A] {
this: A =>
def size: Point
/* immutable object value setter, returns a new of the same object*/
def size(point: Point): A with Sizable[A]
}
def partitionToSizable[T](elements: List[T]):
(List[T], List[T with Sizable[T]]) =
elements.foldLeft((List[T](), List[T with Sizable[T]]()))((p, c) =>
c match {
case a: T with Sizable[T] => (p._1, p._2 ++ List(a))
case a => (p._1 ++ List(a), p._2)
})
上面的代码演示了这个问题。
我甚至不确定T被取消选中有多大问题,因为列表中的所有元素都有一个T类型,模式匹配的点不是确定它是否&# 39; s类型是T,因为我们已经知道了。
理论上,Sizable总是会有T的类型,因为它具有附带功能的特征。
如果没有其他解决方案,我至少要抑制警告。 @unchecked注释似乎没有抑制警告。
如果我修改了案例a:T,带有大小[T],大小写为:大小[_],它将无法编译,因为结果类型显然不会向T确认。
ClassTags或TypeTags可能会解决警告,但我怀疑它们并不是必需的。 (也可能有性能开销,TypeT标不适用于Scala.js)
答案 0 :(得分:1)
我认为只有case a: Sizable[T @unchecked] => a.size((15,20))
才有效。
答案 1 :(得分:1)
这里的主要问题是partitionToSizable
。它需要List[T]
,然后尝试将其分为List[T]
和 a List[T with Sizable[T]]
。您正在获取单个类型的列表,然后说一种类型T
实际上是两种不同的类型T
和T with Sizable[T]
。这表示您的类型设计存在问题。我建议先解决这个问题。
一种解决方案可能是认识到大尺寸的东西和不大的东西应该表示为两种不同的类型。然后您可以使用以下签名:
def partitionToSizable[T1, T2 <: Sizable[T2]](
elements: List[Either[T1, T2]]): (List[T1], List[T2])
然后你不需要施放;您可以在Either
上进行模式匹配或折叠。