tri*_*oid 0 scala type-alias scala-3
在许多 Scala 教程和营销材料中,我发现许多人通过混合“类型别名”和“依赖类型”来滥用术语,而实际上它们并不是同一件事。
例如,在下面的示例中,TakeAlias是依赖类型,而不是类型别名。结果会导致编译失败:
object TrueTypeAlias {
trait Unaliased[+T] {
def take1: List[Seq[(T, T)]]
def take2: List[Seq[(T, T)]]
def take3: List[Seq[(T, T)]]
}
trait Aliased[+T] {
type TakeAlias = List[Seq[(T, T)]]
def take1: TakeAlias
def take2: TakeAlias
def take3: TakeAlias
}
}
/*
TrueTypeAlias.scala:16:10: covariant type T occurs in invariant position in type = List[Seq[(T, T)]] of type TakeAlias
one error found
*/
Run Code Online (Sandbox Code Playgroud)
问题是:如何实现真正的类型别名?我可以使用编译器机制/扩展来使其工作吗?
type TakeAlias = List[Seq[(T, T)]]是一个类型别名,TakeAlias可以用来代替List[Seq[(T, T)]].
同时type TakeAlias = ...也是trait的类型成员。所以x.TakeAlias(for x: Aliased[T]) 是路径依赖类型。尽管这种路径依赖现在很微不足道:对于不同的相同的x.TakeAlias相同,即所有都是。由于是类型成员,因此应用所有方差位置限制。x: Aliased[T]Tx.TakeAliasList[Seq[(T, T)]]type TakeAlias = ...
我会修复此代码,使类型别名通用
trait Aliased[+T] {
type TakeAlias[+S] = List[Seq[(S, S)]]
//type TakeAlias[S] = List[Seq[(S, S)]]
def take1: TakeAlias[T]
def take2: TakeAlias[T]
def take3: TakeAlias[T]
}
Run Code Online (Sandbox Code Playgroud)
或在外部提取类型别名(例如到同伴)
trait Aliased[+T] {
import Aliased.*
def take1: TakeAlias[T]
def take2: TakeAlias[T]
def take3: TakeAlias[T]
}
object Aliased {
type TakeAlias[+S] = List[Seq[(S, S)]]
//type TakeAlias[S] = List[Seq[(S, S)]]
}
Run Code Online (Sandbox Code Playgroud)
规范中的引用:
- 类型别名的右侧始终处于不变位置。
不会检查类的对象私有或对象保护值、类型、变量或方法中的类型参数的引用的差异位置。在这些成员中,类型参数可以出现在任何地方,而不会限制其合法差异注释。
此外,当您确定非法使用不会导致您的用例出现问题时,您可以使用scala.annotation.unchecked.uncheckedVariance
trait Aliased[+T] {
type TakeAlias = List[Seq[(T @uncheckedVariance, T @uncheckedVariance)]]
def take1: TakeAlias
def take2: TakeAlias
def take3: TakeAlias
}
Run Code Online (Sandbox Code Playgroud)
或者
trait Aliased[+T] {
type T1 = T @uncheckedVariance
type TakeAlias = List[Seq[(T1, T1)]]
def take1: TakeAlias
def take2: TakeAlias
def take3: TakeAlias
}
Run Code Online (Sandbox Code Playgroud)