gpt4 book ai didi

scala - 为什么类型字段的上限在转换后丢失(参见描述中的示例)?

转载 作者:行者123 更新时间:2023-12-01 09:37:17 25 4
gpt4 key购买 nike

定义如下:

abstract class A {
type T
def print(p: T) = println(p.toString)
}

trait B extends A {
type T <: String
}

正如预期的那样,我们不能使用 T = Int 创建对象:

scala> val a = new A with B {type T = Int}
<console>:9: error: overriding type T in trait B with bounds >: Nothing <: String;
type T has incompatible type
val a = new A with B {type T = Int}
^

正如预期的那样,我们可以使用 T = String 创建一个对象:

scala> val a = new A with B {type T = String}
a: A with B{type T = String} = $anon$1@692dec

scala> a.print("test")
test

将我们的值 a 转换为类型 A with B 后,调用 print 方法时出现错误。似乎类型字段 T 丢失了有关类型 (?) 的信息。

scala> val b = a.asInstanceOf[A with B]
b: A with B = $anon$1@1927275

scala> b.print("test")
<console>:15: error: type mismatch;
found : java.lang.String("test")
required: b.T
b.print("test")
^

问题一:为什么转换后类型字段T的信息丢失了?

好的,所以我们再试一次,明确地将类型字段 T 设置为 String 类型:

scala> val c = a.asInstanceOf[A with B {type T = String}]
c: A with B{type T = String} = $anon$1@1927275

scala> c.print("test")
test

好的,这很有效。

现在让我们尝试一些疯狂的事情:

scala> val d = a.asInstanceOf[A with B {type T = Int}]
d: A with T{type T = Int} = $anon$1@1927275

scala> d.print(3)
3

问题 2::嗯?特征 B 将类型 T 限制为 String 的子类型,但现在 print 方法适用于整数。为什么会这样?

最佳答案

问题 1 — “将我们的值 a 转换为带有 B 的类型 A 后,调用 print 方法时出现错误。” T有哪些信息 Actor 后有吗?这正是 B 中的内容:

type T <: String

因此类型未知,只是它的上限。下面显示了为什么 print调用A with B被禁止:

trait X
trait Y extends X { def hallo() = () }

trait A {
type T
def test(t: T) = ()
}

trait B extends A {
type T <: X
}

val y = new A with B { type T = Y; override def test(t: T): Unit = t.hallo() }
y.test(new X {}) // refused -- rightfully
y.test(new Y {}) // ok

val yc = y: A with B // note how we can cast type safe this way!
yc.test(new X {}) // refused -- rightfully (would try to call inexistent 'hallo')

所以这是一个出现在逆变(方法参数)位置的类型会发生什么的问题。你有没有定义 B通过缩小下限,即 type T >: X , 可以调用 test即使T没有固定。


问题 2 — 当然可以。您可以使编译器允许使用类型转换进行任何调用。在你转换到 A with B {type T = Int} 之后,你强制编译器接受 T = Int .现在 toString您调用的方法是为 java.lang.Object 定义的,并且由于 A 的通用结构, 你的 Int装在 java.lang.Integer 中,因此您在调用 toString 时不会遇到任何运行时问题.

但是认为你在这里做的事情是正确的是错误的。例如:

abstract class A {
type T
def print(p: T) = println(p.toString)
}

trait B extends A {
type T <: String
override def print(p: T) = println(p.toUpperCase) // !
}

val a = new A with B { type T = String }
val b = a.asInstanceOf[A with B { type T = Int }]
b.print(33) // bang -- runtime class cast exception

关于scala - 为什么类型字段的上限在转换后丢失(参见描述中的示例)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11286279/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com