<:< operator in scala

前端 未结 7 1034
说谎
说谎 2020-11-29 21:34

Can anybody provide some details on <:< operator in scala. I think:

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


        
相关标签:
7条回答
  • 2020-11-29 22:08

    The <:< type is defined in Predef.scala along with the related types =:= and <%< as follows:

    // 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)
    

    This uses the Scala feature that a generic type op[T1, T2] can be written T1 op T2. This can be used, as noted by aioobe, to provide an evidence parameter for methods that only apply to some instances of a generic type (the example given is the toMap method that can only be used on a Traversable of Tuple2). As noted in the comment, this generalizes a normal generic type constraint to allow it to refer to any in-scope abstract type/type parameter. Using this (implicit ev : T1 <:< T2) has the advantage over simply using an evidence parameter like (implicit ev: T1 => T2) in that the latter can lead to unintended in-scope implicit values being used for the conversion.

    I'm sure I'd seen some discussion on this on one of the Scala mailing lists, but can't find it at the moment.

    0 讨论(0)
  • 2020-11-29 22:09

    To better understand the implementation.

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

    I tried to devise a simpler implementation. The following did not work.

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

    At least because it won't type check in all valid use cases.

    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
                                         ^
    
    0 讨论(0)
  • 2020-11-29 22:15

    Actually, it checks if the class represented by the Manifest apple is a subclass of the class represented by the manifest fruit.

    For instance:

    manifest[java.util.List[String]] <:< manifest[java.util.ArrayList[String]] == false
    manifest[java.util.ArrayList[String]] <:< manifest[java.util.List[String]] == true
    
    0 讨论(0)
  • 2020-11-29 22:16

    <:< is not an operator - it is an identifier and is therefore one of:

    • the name of a type (class, trait, type alias etc)
    • the name of a method/val or var

    In this case, <:< appears twice in the library, once in Predef as a class and once as a method on Manifest.

    For the method on Manifest, it checks whether the type represented by this manifest is a subtype of that represented by the manifest argument.

    For the type in Predef, this is relatively new and I am also slightly confused about it because it seems to be part of a triumvirate of identical declarations!

    class <%<[-From, +To] extends (From) ⇒ To
    class <:<[-From, +To] extends (From) ⇒ To
    class =:=[From, To] extends (From) ⇒ To
    
    0 讨论(0)
  • 2020-11-29 22:20

    Copy from 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}
    
    0 讨论(0)
  • 2020-11-29 22:26

    I asked around, and this is the explanation I got:

    <:< is typically used as an evidence parameter. For example in TraversableOnce, toMap is declared as def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U]. This expresses the constraint that the toMap method only works if the traversable contains 2-tuples. flatten is another example. <:< is used to express the constraint that you can only flatten a traversable of traversables.

    0 讨论(0)
提交回复
热议问题