Scala 类型稳定参数多态性
我不明白为什么下面的scala代码没有编译:Scala 类型稳定参数多态性,scala,generics,polymorphism,type-parameter,return-current-type,Scala,Generics,Polymorphism,Type Parameter,Return Current Type,我不明白为什么下面的scala代码没有编译: sealed trait A case class B() extends A { def funcB: B = this } case class C() extends A { def funcC: C = this } def f[T <: A](s:T): T = s match { case s: B => s.funcB case s: C => s.funcC } 然后在调用f时强制转换到子类型,例如
sealed trait A
case class B() extends A {
def funcB: B = this
}
case class C() extends A {
def funcC: C = this
}
def f[T <: A](s:T): T = s match {
case s: B => s.funcB
case s: C => s.funcC
}
然后在调用f
时强制转换到子类型,例如使用asInstanceOf
。但是我希望能够构造一个函数,它统一了一些以前定义的方法,并且使它们是类型稳定的。谁能解释一下吗
另外,请注意以下f
也可编译:
def f[T <: A](s:T): T = s match {
case s: B => s
case s: C => s
}
def[ts
案例s:C=>s
}
是什么让它起作用的?
特别是在Scala 3中,可以使用匹配类型
scala> type Foo[T <: A] = T match {
| case B => B
| case C => C
| }
|
| def f[T <: A](s:T): Foo[T] = s match {
| case s: B => s.funcB
| case s: C => s.funcC
| }
def f[T <: A](s: T): Foo[T]
scala> f(B())
val res0: B = B()
scala> f(C())
val res1: C = C()
必须键入特定的T
。现在让我们尝试键入我们的expr
s match {
case s: B => s.funcB
case s: C => s.funcC
}
类型
case s: B => s.funcB
case s: C => s.funcC
是B
,以及
case s: B => s.funcB
case s: C => s.funcC
是C
。考虑到我们有B
和C
,现在编译器必须取两者中的最小上界,即A
。但是A
肯定不总是T
。因此类型检查失败
现在让我们做同样的练习
def f[T <: A](s: T): A
以前我们得到的类型是“代码> B/<代码>和<代码> C/<代码>,所以编译器取的是超类型<代码> A/<代码>的上界。这确实是我们指定的返回类型。所以TyTQuin成功了。然而,尽管成功了,但是编译时我们丢失了一些类型信息,因为编译器将不再考虑所有的信息。在调用站点传递特定的
T
,但仅通过其超类型A
提供信息。例如,如果T
的成员不在A
中,则我们将无法调用它
避免什么?
关于作为
的安装,这是告诉编译器停止帮助我们,因为我们将冒着大雨。有两组人倾向于在Scala中使用它来工作,一组是库作者,另一组是从其他更动态类型的语言转换过来的人。然而,在大多数应用程序级代码中,这被认为是不好的做法 来回答为什么它不起作用的问题。
f
返回语句s match{…}
的结果
该语句的类型是A
(有时返回B
,有时返回C
),而不是应该的T
。T
有时是C
,有时是B
,s匹配{…}
决不是这两种类型中的任何一种。它是它们的超类型,即A
关于这一点:
s match {
case s: B => s
case s: C => s
}
这句话的类型显然是
T
,因为s
是T
。当然,不管@jwvh可能会说什么:)这一切都归结于我们的老朋友(恶魔?)编译时/运行时的障碍。(而且这两种情况都不会遇到。)
T
在调用站点的编译时解析。当编译器看到f(B)
时,则T
表示B
,当编译器看到f(C)
时,则T
变为C
但是匹配{case…
在运行时解析。编译器不知道将选择哪个case
分支。从编译器的角度来看,所有case
选项都是同样可能的。因此,如果t
解析为B
,但代码可能采用C
分支……那么,编译器不允许这样做
查看编译的内容:
def[T s.funcB//B是一个子类型
案例s:C=>s.func//C是一个子类型
}//好的,一切都好
你的第二个“同样有效”的例子没有为我编译。编译器无法知道
s
将是A
类型。在某些情况下,这是有效的,但我不记得规则。通常,更简单的方法是使用A。
s match {
case s: B => s.funcB
case s: C => s.funcC
}
s match {
case s: B => s
case s: C => s
}
def f[T <: A](s:T): A = s match { //f() returns an A
case s: B => s.funcB //B is an A sub-type
case s: C => s.funcC //C is an A sub-type
} //OK, all is good