Подтвердить что ты не робот

Что означает "<:" в Scala?

Я смотрю на стр. 469 "Программирование в Scala" Второе издание. Существует строка кода, которая гласит:

type Currency <: AbstractCurrency

Я не могу расшифровать, что это значит.

4b9b3361

Ответ 1

Это означает, что элемент абстрактного типа определен (внутри некоторого контекста, например, признака или класса), так что конкретные реализации этого контекста должны определять этот тип. Однако существует ограничение, что этот тип (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
}

Не удается. С ограничениями ok:

trait Euro extends AbstractCurrency

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

Ответ 2

Это означает, что "должен быть подтип", "должен соответствовать", "должен распространяться". В большинстве случаев это выглядит как привязка к общему параметру, например

class Home[P <: Person] 

Каждый дом подходит для определенного типа человека, Home[Person] принимает любого человека, может быть Home[Student], Home[Elderly], но не Home[Planet].

type Currency <: AbstractCurrency вводит абстрактный type элемент Currency в class/trait, где он появляется. Потомкам придется выбирать тип, чтобы они могли быть конкретными. The <: AbstractCurrencies заставляют их выбирать подтип AbstractCurrency (включая AbstractCurrency, который разрешен).

Элемент абстрактного типа очень близок к параметру типа, так же как элемент абстрактного значения близок к параметру конструктора.

Если у вас class A(val x: X){...}, вы инициируете первый с помощью new A(myX). Если у вас есть class A{val x: X; ...}, вы создаете новый 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.

Ответ 3

Этот вопрос касается Scala, но я думаю, что стоит упомянуть, что <: [type operatator?] не уникален для Scala и вместо этого возникает в Теории типов; см., например, статью о Subtyping в Википедии, которая широко использует этот оператор.

На самом деле, из-за его сильных связей с теорией типов <: - это не единственное Scala (элегантно), заимствованное из него; например, обозначение term: Type (см., например, val foo: Foo, def fact(x: Int): Int) также получено из Теория типов.