【问题标题】:Is this scala type bounding the same as this java type bounding?这个 scala 类型边界是否与这个 java 类型边界相同?
【发布时间】:2020-10-14 08:29:15
【问题描述】:

这两者之间有什么区别(如果有的话)?是等价的还是比我意识到的更强大?

Scala 类型边界

class AnimalHandler[A <: Animal, F <: Food] {
  def getFood(a: A): F = { ... }
}

Java 类型边界

class AnimalHanlder<A extends Animal, F extends Food> {
  public F getFood(A a) { ... }
}

【问题讨论】:

  • AFAIK:Scala 在这种方式上更强大,您可以指定上限和下限:取自 here:class Parking[A &gt;: Bicycle &lt;: Vehicle]
  • 这些示例都编译为相同的字节码,但我不希望例如推理在两种语言中的工作方式相同。

标签: java scala generics


【解决方案1】:

是的。您可以或多或少地将&lt;: 读作extends&gt;: 读作super

我通常不太喜欢符号,但在这种情况下,我喜欢与熟悉的&lt;&gt; 运算符的相似之处:“嘴巴”最小的一侧“更小”。在类型的情况下,A &lt;: B 表示AB 的子类型(它是extends,更具体)。

【讨论】:

  • 实际上,它们是&lt;&gt;,但添加了:,这样解析器(和读者)就不会感到困惑。如果您将类型视为集合,那么超类型/超集“更大”,因为它们包含来自其子类型=子集的所有值,而子类/子集仅包含超值的一部分类型/超集,因此它们更小。所以它正好是 &lt;&gt; 在偏序中。
  • 这是关联符号的绝妙方式!
【解决方案2】:

您可以在此处比较从 AnimalHandler 在 Scala 和 Java 中生成的字节码:https://www.diffchecker.com/HyAuDYo5

Scala 中的class AnimalHandler[A &lt;: Animal, F &lt;: Food] 在 Java 中将被视为 class AnimalHanlder&lt;A extends Animal, F extends Food&gt;,反之亦然。

A &lt;: B 表示AB 的子类型。在 Java 中创建子类型的唯一方法是继承

class Cow extends Animal
class Grasp extends Food
new AnimalHandler[Cow, Grasp]

(这就是为什么使用关键字 extends 而不是 &lt;:)但是在 Scala 中有很多方法可以创建子类型:

val cow: Cow = new Cow
val grasp: Grasp = new Grasp
new AnimalHandler[cow.type, grasp.type]

type Cow <: Animal
type Grasp <: Food
new AnimalHandler[Cow, Grasp]

trait CowLike
trait GraspLike
new AnimalHandler[Animal with CowLike, Food with GraspLike]

trait Animal {
  type F <: Food
}
trait Food
class Grasp extends Food
class Cow extends Animal {
  override type F <: Grasp
}
new AnimalHandler[Cow, Cow#F]

val cow: Cow = new Cow
new AnimalHandler[cow.type, cow.F]

trait Animal 
class Cow extends Animal
trait Food
class Grasp extends Food
trait GetFoodTypeclass[A <: Animal] {
  type F <: Food
}
object GetFoodTypeclass {
  implicit val cowGrasp: GetFoodTypeclass[Cow] { type F = Grasp } = null 
}
def foo[A <: Animal](implicit getFood: GetFoodTypeclass[A]) = {
  new AnimalHandler[A, getFood.F]
}

因此,Scala 的类型系统比 Java 的类型系统更强大,这就是子类型 (&lt;:) 比子类 (extends) 更强大的原因。

在 Scala 中你也可以有下限

trait Animal
trait Mammal extends Animal
class Cow extends Mammal
class CowHandler[A >: Cow <: Animal]
new CowHandler[Mammal]

但在 Java 中,下限只能与通配符一起使用

interface Animal {}
interface Mammal extends Animal {}
class AnimalHanlder<A extends Animal> {}
void handle(AnimalHanlder<? super Mammal> handler) {}

在 Scala 中你也可以指定方差。

【讨论】:

  • 感谢您的示例和解释。这很有启发性
猜你喜欢
  • 2013-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-24
  • 2020-07-22
  • 2013-05-31
  • 1970-01-01
  • 2011-07-30
相关资源
最近更新 更多