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

Does scala 3 have true type alias? How to implement it?

提问人:tribbloid 提问时间:5/2/2023 更新时间:5/3/2023 访问量:102

问:

在许多 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
*/

问题是:实现真正的类型别名需要什么?是否有编译器机制/扩展可用于使其工作?

scala scala-3 类型别名

评论

6赞 Luis Miguel Mejía Suárez 5/2/2023
这既是类型别名,又是依赖于补丁的类型,两者都与编译错误无关。- 要创建一个类型别名,你只需在对象或顶层使用关键字(仅限 Scala 3type
0赞 sarveshseri 5/2/2023
你是一个特质,实际上是一个 for .这与在命名中具有值相同。而且由于这是...它所引用的类型也是 A,因为它不存在,如果不首先引用 .TakeAliastype-alias memberAliasedtype-aliastypeList[Seq[(T, T)]]Int value memberi10type-aliastraittype-aliaspath dependent typetrait instance

答:

1赞 tribbloid 5/2/2023 #1

找到了一个可能的解决方案:


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] {

    private type TakeAlias = List[Seq[(T, T)]]

    def take1: TakeAlias

    def take2: TakeAlias

    def take3: 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] {

    opaque type TakeAlias = List[Seq[(T, T)]]

    def take1: TakeAlias

    def take2: TakeAlias

    def take3: TakeAlias
  }

  trait Aliased2[+T] extends Aliased[T] {

    def take4: TakeAlias
  }
}

评论

0赞 Dmytro Mitin 5/2/2023
private修复在 2.13 scastie.scala-lang.org/DmytroMitin/iTBIyhmdQNmZLD1QcBJJTg 中不起作用
1赞 Dmytro Mitin 5/2/2023
但工作 scastie.scala-lang.org/DmytroMitin/iTBIyhmdQNmZLD1QcBJJTg/1(如我回答中规范的引用所述)。 在 Scala 3 docs.scala-lang.org/scala3/reference/dropped-features/ 中不存在......private[this]private[this]
1赞 Dmytro Mitin 5/2/2023
也许在 Scala 3 中,即使只对成员来说,方差检查也放宽了。我找不到特定的 PR、文档或问题。也许 github.com/lampepfl/dotty/issues/7567 是相关的private
2赞 Jasper-M 5/3/2023
@DmytroMitin Scala 3 会自动变成 如果成员只被使用 .您可以看到,如果添加 .privateprivate[this]private[this]def foo(a: Aliased[?]): a.TakeAlias
0赞 tribbloid 5/3/2023
非常感谢你们提供的新信息。对不起,刚刚意识到这不属于任何逻辑,因为方差是一个更高层次的概念。将移除相关部分
5赞 Dmytro Mitin 5/2/2023 #2

type TakeAlias = List[Seq[(T, T)]]是可以代替 使用的类型别名。TakeAliasList[Seq[(T, T)]]

同时是特征的类型成员。所以 (for ) 是依赖于路径的类型。虽然这种路径依赖关系现在是微不足道的:对于不同的是相同的,即都是。由于是类型成员,因此应用所有方差位置限制。type TakeAlias = ...x.TakeAliasx: Aliased[T]x.TakeAliasx: 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]

}

或提取外部的类型别名(例如,到 companion)

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)]]
}

规范中的一句话:

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

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

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

此外,当您确定非法使用不会导致您的用例出现问题时,您可以使用scala.annotation.unchecked.uncheckedVariance

trait Aliased[+T] {

  type TakeAlias = List[Seq[(T @uncheckedVariance, T @uncheckedVariance)]]

  def take1: TakeAlias

  def take2: TakeAlias
  
  def take3: TakeAlias

}

trait Aliased[+T] {

  type T1 = T @uncheckedVariance
 
  type TakeAlias = List[Seq[(T1, T1)]]

  def take1: TakeAlias

  def take2: TakeAlias

  def take3: TakeAlias

}