25장 The Architecture of Scala Collections - codeport/scala GitHub Wiki
25. The Architecture of Scala Collections
Scala Collection은 코드 중복을 최소화했다.
25.1 Builders
Colleciton Operation은 foreach가 있는 Traversable과 Collection을 만드는 Buidler로 구현된다.
Traversable은 24장에서 다뤘고, Builders가 뭔지는 아래 두 예제를 보면 알 수 있다:
package scala.collection.generic
class Builder[-Elem, +To] {
def +=(elem: Elem): this.type
def result(): To
def clear()
def mapResult(f: To => NewTo): Builder[Elem, NewTo] = ...
}
package scala.collection
class TraversableLike[+Elem, +Repr] {
def newBuilder: Builder[Elem, Repr] // deferred
def foreach[U](f: Elem => U) // deferred
...
def filter(p: Elem => Boolean): Repr = {
val b = newBuilder
foreach { elem => if (p(elem)) b += elem }
b.result
}
}
25.2 Factoring out common operations
"same-result-type" 원칙을 지키고 코드 중복을 회피하는데 사용하려고 implementation trait이라는 걸 사용한다. Like
suffix가 달린 Trait이 Implementation Trait이다. TraversableLike
은 Traversable
의 Implemtation Trait이다. 즉 Traversable
Collection의 Operation은 TraversableLike
에 구현하고 상속 받는다.
아래는 Traversable
과 TraversableLike
의 선언부이다:
trait TraversableLike[+Elem, +Repr] { ... }
trait Traversable[+A] extends TraversableLike[A, Traversable[A]] with GenTraversable[A] with TraversableOnce[A] with GenericTraversableTemplate[A, Traversable] { ...}
TraversableLike
는 여러 Traversable Collection에서 재사용할 수 있도록 엘리먼트 타입(A
)뿐만 아니라 Colection 타입(Traversable[A]
)도 파라미터로 받는다.
책에서 보여주는 예제를 보면 BigSet[Int]의 map 함수는 BigSet[Float]를 반환한다:
scala> val bits = BitSet(1, 2, 3)
bits: scala.collection.immutable.BitSet = BitSet(1, 2, 3)
scala> bits map (_.toFloat)
res14: scala.collection.immutable.Set[Float]
= Set(1.0, 2.0, 3.0)
즉, 타입 파라미터가 3개인 Builder가 필요한데 TraversableLike의 Builder는 타입 파라미터가 두 개다:
def newBuilder: Builder[Elem, Repr]
그래서 Scala는 타입 파라미터가 2개인 Builder를 생성하는 타입 파라미터 3개인 CanBuildFrom을 implicit 파라미터로 넘겨 받는다:
def map[B, That](p: Elem => B)
(implicit bf: CanBuildFrom[B, That, This]): That = {
val b = bf(this)
for (x <- this) b += f(x)
b.result
}
CanBuildFrom의 생김새:
package scala.collection.generic
trait CanBuildFrom[-From, -Elem, +To] {
// Creates a new builder
def apply(from: From): Builder[Elem, To]
}
CanBuildFrom의 쓰임새:
CanBuildFrom[Set[_], A, Set[A]]
25.3 Integrating new collections
지금까지 설명한 것으로 Collection을 하나 만들어 본다.