scala 3 有真正的类型别名吗?如何实施?

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)

问题是:如何实现真正的类型别名?我可以使用编译器机制/扩展来使其工作吗?

Dmy*_*tin 5

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)

规范中的引用:

https://scala-lang.org/files/archive/spec/2.13/04-basic-declarations-and-definitions.html#variance-annotations

  • 类型别名的右侧始终处于不变位置。

不会检查类的对象私有或对象保护值、类型、变量或方法中的类型参数的引用的差异位置。在这些成员中,类型参数可以出现在任何地方,而不会限制其合法差异注释。

此外,当您确定非法使用不会导致您的用例出现问题时,您可以使用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)