正如这个问题的标题所暗示的那样:我的问题更多的是形式(惯用惯例)而不是功能。简洁地说:
MyCollectionLike
和MyCollection
之间的语义差异是什么?
例如:StringLike
和String
或MapLike
和Map
之间有什么区别。仔细查看Scala API文档,我可以看出XLike
通常是X
的超类型。但是,除此之外,我不清楚这些抽象层之间的语义差异。
在实践中,如果我正在创建一个新的类/特性,当我为所述类选择名称时,理解这种区别会很有帮助。
我遇到的具体问题如下:
我想创建特征:
SurjectiveMap[K, T]
,可以与Map[K, Set[T]]
或MapLike[K, SetLike[T]]
混合使用。鉴于我不知道*Like
和*
之间的语义差异,我不确定该使用哪个。
答案 0 :(得分:3)
与IFoo和Foo,Bar和BarImpl之间的区别相同(除了TraversableLike是包含实现的超级特征的事实):
Scala集合库避免了代码重复并实现了 通过使用通用构造函数和遍历来实现“相同结果类型”原则 在所谓的实现特征中的集合。这些特质是 以Like后缀命名;例如,IndexedSeqLike就是 IndexedSeq的实现特性,类似地,TraversableLike是 Traversable的实现特性。集合类如 Traversable或IndexedSeq继承了他们所有的具体方法 从这些特征中实现。
答案 1 :(得分:1)
我认为使用Like
特征可以优化返回(表示)类型。这涉及更多的工作。比较:
import collection.generic.CanBuildFrom
object FooMap {
type Coll = FooMap[_, _]
implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), FooMap[A, B]] = ???
}
trait FooMap[A, +B] extends Map[A, B] {
def foo = 33
}
def test(f: FooMap[Any, Any]) {
f.map(identity).foo // nope, we ended up with a regular `Map`
}
与
object FooMap extends collection.generic.ImmutableMapFactory[FooMap] {
override type Coll = FooMap[_, _]
implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), FooMap[A, B]] = ???
def empty[A, B]: FooMap[A, B] = ???
}
trait FooMap[A, +B] extends Map[A, B]
with collection.immutable.MapLike[A, B, FooMap[A, B]] {
def foo = 33
override def empty: FooMap[A, B] = FooMap.empty[A, B]
}
def test(f: FooMap[Any, Any]) {
f.map(identity).foo // yes
}
必须在MapLike
特征之后混合Map
特征才能启动正确的返回类型。
你似乎还没有免费获得所有东西,例如你需要覆盖更多的方法:
override def +[B1 >: B](kv: (A, B1)): FooMap[A, B1] // etc.