【发布时间】:2014-12-15 03:11:41
【问题描述】:
以下内容无法使用 Scala 2.11.4 编译:
trait Test {
type A
type F = Function1[A, String]
}
trait Util[T <: Test] {
def compute1( f: T#A => String, a: T#A ): String = f(a)
def compute2( f: T#F, a: T#A ): String = f(a)
// ^
}
调用(^)的参数有编译错误:
type mismatch;
found : a.type (with underlying type T#A) required: _3317.A
我期望 compute1 和 compute2 中的两个 f 参数具有相同的类型;显然不是。
发生了什么事?
正如@Eugene 和@Zim-Zam 所回答的,这里的问题是由于Scala 的路径相关类型。根据他们的建议,我想出了几个替代方案:
trait Test {
type A
type Fa = Function1[A, String] // original question
type Fb = Function1[Test#A, String] // Zim-Zam's suggestion
}
trait TestOps[T <: Test] {
type G = Function1[T#A, String]
}
trait Util[T <: Test] {
def compute1( f: T#A => String, a: T#A ): String = f(a)
// def compute2a( f: T#Fa, a: T#A ): String = f(a)
// type mismatch; found : a.type (with underlying type T#A) required: _1536.A
def compute2b( f: T#Fb, a: T#A ): String = f(a)
}
trait Util1 {
def compute3a(t: Test)( f: t.Fa, a: t.A ): String = f(a)
def compute3b(t: Test)( f: t.Fb, a: t.A ): String = f(a)
}
trait Util2[T <: Test] { tops: TestOps[T] =>
// def compute4a( f: T#Fa, a: T#A ): String = f(a)
// type mismatch; found : a.type (with underlying type T#A) required: _1642.A
def compute4b( f: T#Fb, a: T#A ): String = f(a)
def compute5( f: tops.G, a: T#A ): String = f(a)
}
Util 将原始操作与@Zim-Zam 的建议进行比较
Util1 练习指定 Function1 参数类型的区别:A vs Test#A
Util2 练习将 Function1 类型定义为另一个特征的建议:TestOps
注释掉不进行类型检查的变体,我们得到:
compute1
compute2b
compute3a
compute3b
compute4b
compute5
哪个更适合专门研究这些特征?
为了梳理出不同之处,我做了一个简单的改进:
class U
class TestU extends Test {
override type A = U
}
class UOps extends TestOps[TestU]
结果如下:
trait UtilU extends Util[TestU] {
def get1( f: TestU#A => String, a: TestU#A) = compute1(f, a)
// def get2b( f: TestU#A => String, a: TestU#A) = compute2b(f, a)
// type mismatch; found : A.U ⇒ String required: A.Test#A ⇒ String
}
trait UtilU1 extends Util1 {
val u = new TestU()
def get3a( f: u.A => String, a: u.A) = compute3a(u)(f, a)
// def get3b( f: u.A => String, a: u.A) = compute3b(u)(f, a)
// type mismatch;
// found : UtilU1.this.u.A ⇒ String (which expands to) A.U ⇒ String
// required: UtilU1.this.u.Fb (which expands to) A.Test#A ⇒ String
}
class UtilU2 extends Util2[TestU] with TestOps[TestU] {
// def get4b( f: TestU#A => String, a: TestU#A) = compute4b(f, a)
// type mismatch; found : A.U ⇒ String required: A.Test#A ⇒ String
def get5( f: TestU#A => String, a: TestU#A) = compute5(f, a)
}
所以,我们只剩下 3 个合理的变体:
compute1(无 Function1 类型别名)
compute3a
compute5
对于 Function1 类型的别名,我们只剩下 2 个备选方案:compute3a 和 compute5
描述它们之间差异的正确方法是什么?
【问题讨论】:
标签: scala type-mismatch