-
Notifications
You must be signed in to change notification settings - Fork 36
25장 The Architecture of Scala Collections
Scala Collection은 코드 중복을 최소화했다.
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
}
}
"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]]
지금까지 설명한 것으로 Collection을 하나 만들어 본다.