Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/77.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 类型稳定参数多态性_Scala_Generics_Polymorphism_Type Parameter_Return Current Type - Fatal编程技术网

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时强制转换到子类型,例如

我不明白为什么下面的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
时强制转换到子类型,例如使用
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