I am trying to 开发者_运维问答find the documentation for the Scala operator method #::
. I believe that it is defined in the Stream
class because of an example I found that uses it.
My question is not particular to this method (although I would like to know where the docs are), but how to search the Scala docs in general. I tried entering #::
in the search box in the upper left of the documentation page (2.8.1), but found nothing.
I suggest using the Reference Index - it's designed specifically to look for any kind of symbol (class, traits, methods, vals, vars) regardless of it's hierarchical position - contrasting with the Scaladoc's left index which doesn't show inner classes, traits or objects.
Unfortunately it's only available in the nightly. You can see the whole thing at nightly Scaladoc. Notice the upper box in the left frame, above the index.
Hope it will be bundled with Scala 2.9.0.
Edit As of 2.9.0, the reference index started to be bundle with Scaladoc. No need to go to the nightly docs now.
As others have already mentioned, #::
is defined on scala.collection.immutable.Stream.ConsWrapper
. I just wanted to take a minute to elaborate on why that is.
In general, to call an operator on an object, that object needs to exist. However, the idea with a Stream is the tail of the stream is not evaluated until it needs to be. So consider the following stream:
def fibs(a:Int,b:Int):Stream[Int] = a #:: fibs(b,a+b)
Ordinarily, we would need to evaluate the recursive fibs
call so that we could call the #::
operator on it. This would lead to runaway recursion. This is NOT what we want. What we want is for the reciever to be a by-name Stream
. Hence the ConsWrapper
:
The constructor for ConsWrapper
is class ConsWrapper[T](tail: => Stream[T])
taking a by-name Stream
, and it's created through an implicit conversion Stream.consWrapper[T](stream: => Stream[T])
, which also takes a by-name Stream
.
Hence, we have performed an implicit conversion on the result of a function that has not yet been called, and we have mimiced the effect of calling #::
with a by-name this
reference.
The problem here is that the scaladoc search does not allow you to look for an inner class/object (i.e. whose parent is not a package). The declaration of #::
is either Stream.#::
or Stream.ConsWrapper.#::
:
object Stream {
//STUFF
/** An extractor that allows to pattern match streams with `#::`.
*/
object #:: {
def unapply[A](xs: Stream[A]): Option[(A, Stream[A])] =
if (xs.isEmpty) None
else Some((xs.head, xs.tail))
}
class ConsWrapper[A](tl: => Stream[A]) {
def #::(hd: A): Stream[A] = new Stream.Cons(hd, tl)
def #:::(prefix: Stream[A]): Stream[A] = prefix append tl
}
//MORE STUFF
}
You could request this as an RFE to the scaladoc tool in trac.
In IntelliJ IDEA's scala plugin, you could have used symbol lookup (CTRL+ ALT+ SHIFT+ N) and typed #::
and this would have brought up both declarations of #::
immediately.
Well, normally, if we see
foo bar baz
then bar is a method, defined for foo, so we first look in the class/object - definition of foo, then the inheritance/trait tree upwards (+ in implicit conversions to and from foo, in the current file, and in (directly) included files).
Except 'bar' ends in a colon, which is the case here. Then it is to be read in reverse order -
foo bar: baz
is not
foo.bar: (baz)
, but
baz.bar: (foo)
So we have to look up in the way described above, but not for foo, but for baz.
That particular method is defined in a nested class inside of Stream
, called scala.collection.immutable.Stream.ConsWrapper
.
And no, I have absolutely no idea how one would go about finding it. I only stumbled across it by accident. And even though I knew where to find it now, when I wanted to post the link to the class here in my answer, I still couldn't find it on the first (and even second and third) try.
精彩评论