How to interpret ::: from the Scala API for List?

2019-09-12 15:19发布

问题:

I am trying to use the ::: method (is this an operator method?) from List. Okay I know what it is doing now after typing in two lists in the REPL and seeing what was going on. However the API definition of the ::: method was hard to read and understand. I only "got it" by reading what it "returns".

def :::[B >: A](prefix: List[B]): List[B]
    Adds the elements of a given list in front of this list.
    prefix  The list elements to prepend.
    returns list resulting from the concatenation of the given list prefix and this list.
    Example:  List(1, 2) ::: List(3, 4) = List(3, 4).:::(List(1, 2)) = List(1, 2, 3, 4)

In particular what does this part mean: [B >: A](prefix: List[B]). I mean I was able to understand what the method returns by reading what the method returns and playing with it. For the future, I would like to be able to read the API for a different method and try to understand everything. That is why I am asking this question.

回答1:

The two answers are both correct. You only have to remember that A is the type parameter of your current list, and B is the type parameter of the list you are supplying to :::

If you are not yet confident, you can try your own definition of List

  class MyList[+A]{
    def :::[B >: A](prefix: MyList[B]): MyList[B] = new MyList[B]()
  }

  class Animal
  class Dog extends Animal
  class Pig extends Animal
  class Rock 

And now you can test in the REPL:

scala>  new MyList[Dog]
res0: Test.AkkaTest.MyList[Test.AkkaTest.Dog] = Test.AkkaTest$MyList@190a0d51

scala>  new MyList[Pig]
res1: Test.AkkaTest.MyList[Test.AkkaTest.Pig] = Test.AkkaTest$MyList@1db5d2b2

scala>  res0:::res1
res2: Test.AkkaTest.MyList[Test.AkkaTest.Animal] = Test.AkkaTest$MyList@25927275

scala>  new MyList[Rock]
res3: Test.AkkaTest.MyList[Test.AkkaTest.Rock] = Test.AkkaTest$MyList@49f85a86

scala>  res3:::res0
res4: Test.AkkaTest.MyList[ScalaObject] = Test.AkkaTest$MyList@42130c2

scala>  res0:::res3
res5: Test.AkkaTest.MyList[ScalaObject] = Test.AkkaTest$MyList@6f24d504

So you know should have understood that the ::: concatenates two list and creates a list whose generic type is the first common ancestor. This is because the type list is covariant, so for example you might think that, in case of res3 and res0 the compiler does the following:

  • A is Rock B is Dog, B is not a parent class of A, maybe I should throw compiler error?
  • But since MyList is covariant, MyList[Dog] is a subclass of MyList[ScalaObject].
  • Cool, ScalaObject is a parent class of Rock, so I will create a list of ScalaObject


回答2:

[B >: A] means that the method is generic and takes one type argument called B that must be a supertype of A. (prefix : List[B]) means that it takes one actual argument called prefix of type List[B].



回答3:

If it wasn't for subtypes this would be written def :::(prefix: List[A]): List[A], the [B >: A] just lets you, say, prefix a List[Animal] onto a List[Cat], getting a larger List[Animal].



标签: scala