2011-07-26 19 views
31

Estoy viendo la p. 469 de "Programación en Scala" Segunda edición. Hay una línea de código que dice:¿Qué significa "<:" en Scala?

type Currency <: AbstractCurrency 

No puedo descifrar lo que esto significa.

+5

Ver también [¿Qué significa "rasgo A <: B" significa?] (Http://stackoverflow.com/questions/2123663/what-does-trait-a-b-mean) – Jonas

Respuesta

46

Significa que se define un miembro de tipo abstracto (dentro de algún contexto, por ejemplo, un rasgo o clase), de modo que las implementaciones concretas de ese contexto deben definir ese tipo. Sin embargo, existe una restricción de que este tipo (Currency) debe ser realmente un subtipo de AbstractCurrency. De esta forma, el contexto abstracto puede operar con Currency, sabiendo que comprende todas las operaciones de 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() 
} 

Tratar de definir Currency sin limitaciones:

trait RadioactiveBeef 

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

falla.Con las limitaciones ok:

trait Euro extends AbstractCurrency 

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

Significa "debe ser un subtipo de", "debe ajustarse a", "debe extenderse". mayoría de las veces, parecería como dependiente en un parámetro genérico, como

class Home[P <: Person] 

Cada hogar es apto para un cierto tipo de persona, un Home[Person] acepta cualquier persona, puede haber Home[Student], Home[Elderly], pero no Home[Planet].

type Currency <: AbstractCurrency presenta un resumen type miembro de Currency en el class/trait donde aparece. Los descendientes tendrán que elegir un tipo para que puedan ser concretos. El <: AbstractCurrencies los obliga a elegir un subtipo de AbstractCurrency (incluido AbstractCurrency, que está permitido).

Un miembro de tipo abstracto está muy cerca de un parámetro de tipo, del mismo modo que un miembro de valor abstracto está cerca de un parámetro de constructor.

Si tiene class A(val x: X){...}, usted instancia el primero con new A(myX). Si tiene class A{val x: X; ...}, lo instancia con el nuevo A{val x = myX }.

Si tiene class Market[Currency <: AbstractCurrency], usted instancia el tipo con Market[SomeCurrencyType]. Si tiene Market{type Currency <: AbstractCurrency}, crea instancias con Market{type Currency = SomeCurrencyType}. Sin embargo, Market es un tipo válido. Significa que no sabe qué tipo de moneda utiliza este mercado (que puede restringir cómo puede usarlo).

El uso de un miembro de tipo abstracto en lugar de un parámetro de tipo puede tener beneficios, sobre todo si el parámetro de tipo no aparece en la interfaz pública del tipo, si Market no tiene Currency que aparece como un parámetro de la función o el resultado (no muy probable en este ejemplo). Entonces el cliente no necesita escribir Market[SomeCurrencyType], Market lo hará. Por supuesto, el CurrencyType tendrá que conocerse cuando se crea un mercado, pero luego se puede pasar simplemente como Market.

3

Esta pregunta es sobre Scala, pero creo que vale la pena mencionar que el <: [? Operatator tipo] no es exclusivo de Scala y en su lugar se origina en la teoría de tipos; ver por ejemplo el artículo sobre Subtyping en Wikipedia que hace un uso extenso de este operador.

De hecho, debido a sus fuertes conexiones con la teoría de tipos <: no es lo único que Scala (elegantemente) tomó prestado de ella; por ejemplo, la notación term: Type (que se ve en, por ejemplo, val foo: Foo, def fact(x: Int): Int) también viene del Type Theory.

0

Quiero agregar algunos puntos que describirán los beneficios de usabilidad de la notación < :.

Digamos, se definen las siguientes clases para su API:

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

Usted tiene una característica llamada BaseParameter

trait BaseParameter 

Entonces, usted tiene los siguientes parámetros:

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

Ahora, cada vez que crea una instancia de myApiClass, debe pasar un objeto como argumento "parameter", cuya clase/que implementa a su vez BaseParameter (p. Parámetro1 y Parámetro2). Concretamente, esta es una afirmación, y no funcionaría si pasa el parámetro3.