通过方法类型参数分配给类型成员的值打破类型等效性

问题描述 投票:2回答:2

为什么以下类型等效性成立

trait Foo { type T }
val fa = new Foo { type T = Int }

implicitly[fa.T =:= Int] // OK

但是当通过方法参数T分配类型成员A时,类型等效性不成立

def makeFoo[A]: Foo = new Foo { type T = A }
val fb = makeFoo[Int]

implicitly[fb.T =:= Int] // ERROR

直觉上我希望T = AA = Int然后T = Int

scala type-parameter type-members type-equivalence
2个回答
6
投票

这是因为makeFoo的返回类型仅为Foo,而不是Foo { type T = A }。如果您未明确声明它或对其进行优化,则错误将消失。

def makeFoo[A] = new Foo { type T = A }
val fb = makeFoo[Int]

implicitly[fb.T =:= Int] // No more error

or

def makeFoo2[A]: Foo { type T = A } = new Foo { type T = A }
val fc: Foo { type T = Int } = makeFoo[Int]

implicitly[fc.T =:= Int] // No more error

Scastie

<script src="https://scastie.scala-lang.org/knIfPcXqSQKXXCXJ2teHkg.js"></script>

2
投票

我将添加不指定精确返回类型,而是将其超类型(上限)称为whiteboxity的可能性。

在Scala 2中,可以通过whitebox macros实现>

import scala.language.experimental.macros
import scala.reflect.macros.whitebox

def makeFoo[A]: Foo = macro impl[A]
def impl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
  import c.universe._
  q"new Foo { type T = ${weakTypeOf[A]} }"
}

val fb = makeFoo[Int]
implicitly[fb.T =:= Int] //compiles

在Dotty中,可以通过关键字transparentcurrently)来实现

transparent inline def makeFoo[A]: Foo = new Foo { type T = A }
val fb = makeFoo[Int]
summon[fb.T =:= Int] //compiles

以前的语法是

inline def makeFoo[A] <: Foo = new Foo { type T = A }
© www.soinside.com 2019 - 2024. All rights reserved.