类型别名中的方差注释

4e6*_*4e6 13 alias scala variance

最近我注意到方差注释可以用在类型别名中.以下示例来自Predef:

type Function[-A, +B] = Function1[A, B]
Run Code Online (Sandbox Code Playgroud)

我开始思考,它可以在哪里使用.显然,您不能将方差更改为相反,或使不变类型表现为共变或逆变.编译器会抛出一个错误,就像这样

scala> type BrokenFunc[+T, -R] = Function1[T, R]
<console>:7: error: covariant type T occurs in contravariant position in type 
  [+T, -R]T => R of type BrokenFunc
Run Code Online (Sandbox Code Playgroud)

但是,你可以使一些变体类型的行为像不变量(至少,编译器不会与此争论).所以,我试着制作一个不变的版本List

scala> type InvList[T] = List[T]
defined type alias InvList
Run Code Online (Sandbox Code Playgroud)

但是这个新的不变量List仍然表现得像它的原始协变版本:

scala> val l: InvList[String] = List("foo")
l: InvList[String] = List(foo)

scala> val anyList: InvList[Any] = l
anyList: InvList[Any] = List(foo)
Run Code Online (Sandbox Code Playgroud)

那么,我错过了什么?类型别名中的方差注释的目的是什么?您能举例说明带有方差注释的类型别名,它与原始类型不同.

Owe*_*wen 8

所以,我不确定,但我会提供一个可能的解释.

Scala中的类型别名相当"弱"; 他们没有完全创建新类型,只是编写旧类型的新方法(以及新的路径依赖类型); 这意味着如果你定义

type InvList[T] = List[T]
Run Code Online (Sandbox Code Playgroud)

InvList[T],就像你写的那样List[T]; 这就是为什么InvList[Int] <: InvList[Any],因为,重写,这只是List[Int] <: List[Any].我实际上并不确定"弱"的Scala类型别名是什么......它们比Haskell强一点,因为路径依赖类型,但比类声明弱.也许其他人可以进一步解释.

那么,为什么Scala允许你在那里放置方差注释,如果只是忽略它们并重写类型呢?它适用于类型成员.这是你可以说的

trait A { type F[+T] }
Run Code Online (Sandbox Code Playgroud)

并要求实现符合+T方差,以便您允许

trait B extends A { type F[+T] = List[T] }
Run Code Online (Sandbox Code Playgroud)

但不是

trait C extends A { type F[T] = Function[T,T] }
Run Code Online (Sandbox Code Playgroud)

或者,从Scala语言规范S4.3的这句话开始.

类型构造函数声明对t可能存在的具体类型施加了额外的限制.除了边界L和U之外,类型参数子句可以强加高阶边界和方差,由类型构造函数的一致性(§3.5.2)控制.