2010-04-08 25 views
35

¿Alguien puede proporcionar algunos detalles sobre el operador <:< en scala. pienso:<: <operador en scala

if(apple <:< fruit) //checks if apple is a subclass of fruit. 

¿Hay otras explicaciones? Veo muchas definiciones en el archivo fuente scala.

+1

¿Se refiere al método de 'Manifest' o la clase definida en' Predef'? –

+62

Eso se conoce como el operador "Madonna vistiendo una camisa con botones". – Syntactic

+3

Ha, lo estoy llamando el operador "Angry Donkey" –

Respuesta

23

<:< es no un operador - es un identificador y por lo tanto es uno de:

  • el nombre de una tipo (clase, rasgo, tipo alias, etc.)
  • el nombre de un método/val o var

En este caso, <:< aparece dos veces en la biblioteca, una vez en Predef como una clase y una vez como un método en Manifest.

Para el método en Manifest, comprueba si el tipo representado por este manifiesto es un subtipo de la representada por el argumento de manifiesto.

Para el tipo en Predef, esto es relativamente nuevo y también estoy un poco confundido porque parece formar parte de un triunvirato de declaraciones idénticas.

class <%<[-From, +To] extends (From) ⇒ To 
class <:<[-From, +To] extends (From) ⇒ To 
class =:=[From, To] extends (From) ⇒ To 
+1

Las que están en 'Predef' son restricciones de tipo generalizadas. Este hilo de la lista de correo abarca algunos de ellos: http://old.nabble.com/-scala--Using-generalised-type-constraints-in-2.8-collections-td26249516.html –

+1

Pero a partir de las declaraciones todos parecen idénticos Entonces, ¿cómo pueden significar cosas diferentes? –

+0

Gracias por el enlace: desafortunadamente todavía estoy luchando por entender cómo se reemplaza ev 'implícito: A => B' con' ev implícito: A <: B' en realidad * does * anything –

7

En realidad, se comprueba si la clase representado por la Manifest Apple es una subclase de la clase representada por el fruto manifiesto.

Por ejemplo:

manifest[java.util.List[String]] <:< manifest[java.util.ArrayList[String]] == false 
manifest[java.util.ArrayList[String]] <:< manifest[java.util.List[String]] == true 
13

Pregunté por ahí, y esta es la explicación que tengo:

<:< se suele utilizar como un parámetro de pruebas. Por ejemplo, en TraversableOnce, toMap se declara como def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U]. Esto expresa la restricción de que el método toMap solo funciona si el traversable contiene 2 tuplas. flatten es otro ejemplo. <:< se usa para expresar la restricción de que solo puedes aplanar una traversable de traversables.

3

Copiar de scala.Predef.Scala:

// Type Constraints -------------------------------------------------------------- 

    // used, for example, in the encoding of generalized constraints 
    // we need a new type constructor `<:<` and evidence `conforms`, as 
    // reusing `Function2` and `identity` leads to ambiguities (any2stringadd is inferred) 
    // to constrain any abstract type T that's in scope in a method's argument list (not just the method's own type parameters) 
    // simply add an implicit argument of type `T <:< U`, where U is the required upper bound (for lower-bounds, use: `U <: T`) 
    // in part contributed by Jason Zaugg 
    sealed abstract class <:<[-From, +To] extends (From => To) 
    implicit def conforms[A]: A <:< A = new (A <:< A) {def apply(x: A) = x} 
30

El tipo <:< se define en Predef.scala junto con los tipos relacionados =:= y <%< como sigue:

// used, for example, in the encoding of generalized constraints 
// we need a new type constructor `<:<` and evidence `conforms`, as 
// reusing `Function2` and `identity` leads to ambiguities (any2stringadd is inferred) 
// to constrain any abstract type T that's in scope in a method's argument list (not just the method's own type parameters) 
// simply add an implicit argument of type `T <:< U`, where U is the required upper bound (for lower-bounds, use: `U <: T`) 
// in part contributed by Jason Zaugg 
sealed abstract class <:<[-From, +To] extends (From => To) 
implicit def conforms[A]: A <:< A = new (A <:< A) {def apply(x: A) = x} // not in the <:< companion object because it is also intended to subsume identity (which is no longer implicit) 

Este utiliza la característica de Scala que un genérico tipo op[T1, T2] puede escribirse T1 op T2. Esto se puede usar, como lo señala aioobe, para proporcionar un parámetro de evidencia para los métodos que solo se aplican a algunas instancias de un tipo genérico (el ejemplo dado es el método toMap que solo se puede usar en un Traversable de Tuple2). Como se señala en el comentario, esto generaliza una restricción de tipo genérico normal para permitir que se refiera a cualquier parámetro de tipo/tipo abstracto dentro del alcance. Usar esto (implicit ev : T1 <:< T2) tiene la ventaja de simplemente usar un parámetro de evidencia como (implicit ev: T1 => T2) en el sentido de que este último puede conducir a valores implícitos no intencionales dentro del alcance que se utilizan para la conversión.

Estoy seguro de que he visto un debate sobre esto en una de las listas de correo de Scala, pero no puedo encontrarlo en este momento.

+0

¿Cuál es la diferencia entre <: Eastsun

+2

@Eastsun '<: <' admite la creación de subclases, mientras que '=: =' no. –

+3

Un parámetro implícito 'ev: T1 <:

2

Para comprender mejor el implementation.

sealed abstract class <:<[-From, +To] extends (From => To) 
implicit def conforms[A]: A <:< A = new (A <:< A) {def apply(x: A) = x} 

Traté de diseñar una implementación más simple. Lo siguiente no funcionó.

sealed class <:<[-From <: To, +To] 
implicit def conforms[A <: B, B]: A <:< B = new (A <:< B) 

Al menos, porque no va a escribir verificación en todos los casos valid use.

case class L[+A](elem: A) 
{ 
    def contains[B](x: B)(implicit ev: A <:< B) = elem == x 
} 

error: type arguments [A,B] do not conform to class <:<'s 
     type parameter bounds [-From <: To,+To] 
def contains[B](x: B)(implicit ev: A <:< B) = elem == x 
            ^