在Scala中,"<:"是什么意思?

65
我正在查看《Scala编程》第二版的469页。有一行代码如下:
type Currency <: AbstractCurrency

我无法理解这是什么意思。


4个回答

72

这意味着定义了一个抽象类型成员(在某个上下文中,例如trait或class),因此该上下文的具体实现必须定义该类型。然而,有个限制,即该类型(Currency)必须实际上是AbstractCurrency子类型。这样,抽象上下文就可以使用Currency,知道它理解AbstractCurrency的每个操作。

trait AbstractCurrency {
  def disappearInGreece(): Unit
}

abstract class Economy {
  type Currency <: AbstractCurrency

  def curr: Currency

  // can call disappear... because `Currency`
  // is an `AbstractCurrency`
  def shake(): Unit = curr.disappearInGreece()
}

尝试定义没有限制的Currency

trait RadioactiveBeef

class NiceTry(val curr: RadioactiveBeef) extends Economy {
  type Currency = RadioactiveBeef
}

失败。有约束条件:

trait Euro extends AbstractCurrency

class Angela(val curr: Euro) extends Economy {
  type Currency = Euro
}

48

它的意思是“必须是子类型”,“必须符合”,“必须扩展”。 大多数情况下,它会出现在泛型参数的限定中,例如:

class Home[P <: Person] 

每个住所都适合某种类型的人,Home[Person] 接受任何人,可能会有 Home[Student]Home[Elderly],但没有 Home[Planet]

type Currency <: AbstractCurrency 在出现它的 class/trait 中引入了一个抽象的类型成员 Currency。后代必须选择一个类型以使它们变得具体化。<: AbstractCurrencies 强制它们选择 AbstractCurrency 的子类型(包括允许的 AbstractCurrency)。

抽象类型成员与类型参数非常接近,就像抽象值成员与构造函数参数一样接近。

如果你有 class A(val x: X){...},你可以使用 new A(myX) 来实例化第一个。如果你有 class A{val x: X; ...},你可以使用 new A{val x = myX } 来实例化。

如果你有 class Market[Currency <: AbstractCurrency],你可以用 Market[SomeCurrencyType] 来实例化该类型。如果你有 Market{type Currency <: AbstractCurrency},你可以使用 Market{type Currency = SomeCurrencyType} 来实例化。不过,Market 是一个有效的类型。这意味着你不知道这个市场使用什么类型的货币(这可能会限制你如何使用它)。

与类型参数相比,使用抽象类型成员可能具有优势,特别是当类型参数未出现在类型的公共接口中时,如果 Market 没有 Currency 作为函数参数或结果(在这个例子中不太可能)。那么客户端就不需要编写 Market[SomeCurrencyType],而是可以直接使用 Market。当然,创建市场时必须知道 CurrencyType,但然后它可以简单地传递为 Market


15

我希望添加一些内容,描述<:符号的可用性优势。

假设您为API定义了以下类:

case class myApiClass[param <: BaseParameter](requestBody: String, parameter: param)

您有一个名为BaseParameter的特性

trait BaseParameter

接下来,您将拥有以下参数:

case object Parameter1 extends BaseParameter
case object Parameter2 extends BaseParameter
case object Parameter3

现在,每当您创建myApiClass实例时,都必须将一个对象作为参数“parameter”传递,该对象的类/本身实现BaseParameter(例如Parameter1和Parameter2)。具体来说,这是一个断言,并且如果您传递Parameter3,则不起作用。


这正是我在寻找的 - 原因,而不仅仅是它能做什么! - TCSGrad
以下代码也会提供相同的行为吗?case class myApiClass(requestBody: String, parameter: BaseParameter) - PRASANNA SARAF

8
这个问题涉及到Scala,但我认为值得一提的是,<: [类型运算符?] 不仅仅在Scala中存在,而是起源于类型理论。例如,在维基百科关于子类型的文章中广泛使用了这个运算符。

事实上,由于它与类型理论有着紧密的联系,<: 不是Scala(优雅地)从中借鉴的唯一东西;例如,term: Type 表示法(例如在 val foo: Foo, def fact(x: Int): Int 中看到)也来自类型理论

1
这并不能回答问题。 - Skeeve

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接