diff --git a/ko/overviews/collections/introduction.md b/ko/overviews/collections/introduction.md new file mode 100644 index 0000000000..9c3c05e6f1 --- /dev/null +++ b/ko/overviews/collections/introduction.md @@ -0,0 +1,42 @@ +--- +layout: overview-large +title: 들어가며.. + +disqus: true + +partof: collections +num: 1 +language: ko +--- + +**Martin Odersky, and Lex Spoon** + +많은 사람들이 보기에, 스칼라 2.8의 가장 눈에 띄는 변화는 바로 새로운 컬렉션 프레임워크이다. 사실, 이전에도 스칼라에 컬렉션이 있었지만 2.8 버전부터 컬렉션을 일관되고 통일성 있게 제공하는 프레임워크로 자리매김하게 되었다. (이전 버전과 대부분 호환됨) + +비록 처음에 컬렉션에 추가된 변화가 미미해보일지라도, 프로그래밍 스타일에 큰 변화를 가져올 수 있다. 컬렉션 각각의 요소를 이용한 것이 아닌 컬렉션 전체를 이용함으로써, 마치 더 고차원적인 프로그램을 작성하는 것처럼 느낄 것이다. 이 새로운 스타일에 익숙해지기 위한 시간이 필요하지만, 다행히 새로운 컬렉션의 특징 덕분에 쉽게 적응할 수 있다. 새로운 컬렉션은 쉽게 사용할 수 있고, 짧게 사용할 수 있으며, 안전하고, 빠르고, 통일성이 있다. + +**편리함:** 20-50개의 메소드로 구성된 몇가지 간단한 작업만으로 대부분의 컬렉션 문제를 풀기에 충분하다. 복잡한 루프 구조나 재귀적인 방법을 사용할 필요가 없다. 영속적인(persistent) 컬렉션들과 부작용없는 연산들(operations)은 새로운 데이터로 인한 컬렉션의 갑작스러운 손상을 걱정하지 않게 해준다. 이터레이터와 컬렉션 사이의 간섭은 사라지게 되었다. + +**간결함:** 단어 하나만으로 하나 이상의 루프를 표현할 수 있다. 또한, 큰 노력 없이도 간단한 구문과 연산들의 조합을 통해서 대수학을 커스터마이징하듯이 함수 연산들을 작성할 수 있다. + +**안전함:** 이는 실제로 경험해보지 않으면 알기 어렵다. 스칼라 컬렉션의 정적타입과 함수형이라는 특성은 대부분의 에러가 컴파일 시점에 잡힐 수 있음을 의미한다. 이러한 주장에 대해 다음과 같은 근거를 들 수 있다. + +(1) 프로그램은 대량의 컬렉션 연산을 통해서 충분히 테스트된다.
+(2) 컬렉션 연산은 입력과 출력을 함수 파라미터와 연산 결과에 대응시킨다.
+(3) 입력과 출력값들은 모두 정적 타입 검사를 수행한다. + +결론적으로, 대다수의 잘못된 사용은 타입 에러를 내게 한다. 한 번에 몇 백줄의 코드를 실행시킬 수 있는 것은 더이상 특이한 경우가 아니다. + +**빠름:** 컬렉션 연산들은 라이브러리들 안에서 튜닝되고 최적화된다. 그렇기 때문에 컬렉션을 사용하는 것은 꽤 효율적이다. 신중하게 직접 수정한 자료구조와 연산을 통해서 좀 더 나아질 수도 있지만 이를 구현하는 과정에서 최적화된 방법으로 구현되지 않은 몇몇 코드들이 더 나아지지 못하게하는 걸림돌이 될 수 있다. 게다가 컬렉션은 최근에 멀티 코어에서의 병렬처리 기능을 적용했다. 병렬처리를 지원하는 컬렉션은 일반적인 컬렉션과 같은 연산(operation)을 사용하기 때문에 새로운 연산을 배울 필요도 없고, 코드를 새로 작성할 필요도 없다. 그저 `par` 메소드를 사용하는 것만으로 병렬처리 기능을 사용할 수 있다. + +**통일성:** 컬렉션은 어떤 타입에 대해서도 같은 연산을 제공한다. 이를 통해 적은 어휘로 표현된 연산으로 많은 기능을 구현할 수 있다. 예를 들어, string은 개념적으로 문자들의 시퀀스이다. 따라서, 스칼라에서의 string은 모든 시퀀스 연산을 제공한다. 이는 배열에도 똑같이 적용된다. + +**예시:** 다음은 스칼리 컬렉션의 많은 장점을 한줄로 표현한 코드이다. + + val (minors, adults) = people partition (_.age < 18) + +보자마자 이 연산이 어떤 기능을 하는지 단번에 알 수 있다. 이 연산은 `people` 컬렉션을 그들의 age에 따라서 `minor`와 `adults`로 나눈다. `partition` 메소드가 루트 컬렉션 타입인 `TraversableLike`에 정의되어 있기 때문에, 이 코드는 배열을 포함한 어떤 종류의 컬렉션에서도 작동할 수 있다. 결과값인 `minor`와 `adults`도 `people` 컬렉션과 같은 타입을 갖는다. + +이 코드는 기존에 3개의 루프를 필요로 하는 기존의 컬렉션 프로세싱보다 훨씬 더 간결하다. (기존의 컬렉션 프로세싱은 중간 결과를 임시 저장하기 위해 3개의 루프를 사용하게 된다.) 기본적인 컬렉션 어휘들을 한번 배운 적이 있다면, 이 코드가 기존의 루프를 사용한 방법보다 훨씬 더 쉽고 안전하다는 것을 알 수 있다. 게다가 `partition` 연산은 꽤 빠르고 멀티코어와 병렬 컬렉션에서는 더 빠른 결과를 제공할 수 있다. (병렬 컬렉션은 스칼리 2.9의 한 부분으로 릴리즈되었다.) + +이 문서는 사용자 관점에서 스칼라 컬렉션 라이브러리 API에 대해 자세하게 설명한다. 모든 기본적인 클래스와 메소드들을 알아보자. \ No newline at end of file diff --git a/ko/overviews/core/architecture-of-scala-collections.md b/ko/overviews/core/architecture-of-scala-collections.md new file mode 100644 index 0000000000..c3cdd833fb --- /dev/null +++ b/ko/overviews/core/architecture-of-scala-collections.md @@ -0,0 +1,1040 @@ +--- +layout: overview +title: The Architecture of Scala Collections +overview: architecture-of-scala-collections +disqus: true +language: ko +--- + +**Martin Odersky and Lex Spoon** + +These pages describe the architecture of the Scala collections +framework in detail. Compared to +[the Scala 2.8 Collections API]({{ site.baseurl }}/overviews/collections/introduction.html) you +will find out more about the internal workings of the framework. You +will also learn how this architecture helps you define your own +collections in a few lines of code, while reusing the overwhelming +part of collection functionality from the framework. + +[The Scala 2.8 Collections API]({{ site.baseurl }}/overviews/collections/introduction.html) +contains a large number of collection +operations, which exist uniformly on many different collection +implementations. Implementing every collection operation anew for +every collection type would lead to an enormous amount of code, most +of which would be copied from somewhere else. Such code duplication +could lead to inconsistencies over time, when an operation is added or +modified in one part of the collection library but not in others. The +principal design objective of the new collections framework was to +avoid any duplication, defining every operation in as few places as +possible. (Ideally, everything should be defined in one place only, +but there are a few exceptions where things needed to be redefined.) +The design approach was to implement most operations in collection +"templates" that can be flexibly inherited from individual base +classes and implementations. The following pages explain these +templates and other classes and traits that constitute the "building +blocks" of the framework, as well as the construction principles they +support. + +## Builders ## + +An outline of the `Builder` trait: + + package scala.collection.mutable + + trait Builder[-Elem, +To] { + def +=(elem: Elem): this.type + def result(): To + def clear(): Unit + def mapResult[NewTo](f: To => NewTo): Builder[Elem, NewTo] = ... + } + +Almost all collection operations are implemented in terms of +*traversals* and *builders*. Traversals are handled by `Traversable`'s +`foreach` method, and building new collections is handled by instances +of class `Builder`. The listing above presents a slightly abbreviated +outline of this trait. + +You can add an element `x` to a builder `b` with `b += x`. There's also +syntax to add more than one element at once, for instance `b += (x, y)`. +Adding another collection with `b ++= xs` works as for buffers (in fact, +buffers are an enriched +version of builders). The `result()` method returns a collection from a +builder. The state of the builder is undefined after taking its +result, but it can be reset into a new empty state using +`clear()`. Builders are generic in both the element type, `Elem`, and in +the type, `To`, of collections they return. + +Often, a builder can refer to some other builder for assembling the +elements of a collection, but then would like to transform the result +of the other builder, for example to give it a different type. This +task is simplified by method `mapResult` in class `Builder`. Suppose for +instance you have an array buffer `buf`. Array buffers are builders for +themselves, so taking the `result()` of an array buffer will return the +same buffer. If you want to use this buffer to produce a builder that +builds arrays, you can use `mapResult` like this: + + scala> val buf = new ArrayBuffer[Int] + buf: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer() + + scala> val bldr = buf mapResult (_.toArray) + bldr: scala.collection.mutable.Builder[Int,Array[Int]] + = ArrayBuffer() + +The result value, `bldr`, is a builder that uses the array buffer, `buf`, +to collect elements. When a result is demanded from `bldr`, the result +of `buf` is computed, which yields the array buffer `buf` itself. This +array buffer is then mapped with `_.toArray` to an array. So the end +result is that `bldr` is a builder for arrays. + +## Factoring out common operations ## + +### Outline of trait TraversableLike ### + + package scala.collection + + trait TraversableLike[+Elem, +Repr] { + def newBuilder: Builder[Elem, Repr] // deferred + def foreach[U](f: Elem => U): Unit // deferred + ... + def filter(p: Elem => Boolean): Repr = { + val b = newBuilder + foreach { elem => if (p(elem)) b += elem } + b.result + } + } + +The main design objectives of the collection library redesign were to +have, at the same time, natural types and maximal sharing of +implementation code. In particular, Scala's collections follow the +"same-result-type" principle: wherever possible, a transformation +method on a collection will yield a collection of the same type. For +instance, the `filter` operation should yield, on every collection type, +an instance of the same collection type. Applying `filter` on a `List` +should give a `List`; applying it on a `Map` should give a `Map`, and so +on. In the rest of this section, you will find out how this is +achieved. + +The Scala collection library avoids code duplication and achieves the +"same-result-type" principle by using generic builders and traversals +over collections in so-called *implementation traits*. These traits are +named with a `Like` suffix; for instance, `IndexedSeqLike` is the +implementation trait for `IndexedSeq`, and similarly, `TraversableLike` is +the implementation trait for `Traversable`. Collection traits such as +`Traversable` or `IndexedSeq` inherit all their concrete method +implementations from these traits. Implementation traits have two type +parameters instead of one for normal collections. They parameterize +not only over the collection's element type, but also over the +collection's *representation type*, i.e., the type of the underlying +collection, such as `Seq[T]` or `List[T]`. For instance, here is the +header of trait `TraversableLike`: + + trait TraversableLike[+Elem, +Repr] { ... } + +The type parameter, `Elem`, stands for the element type of the +traversable whereas the type parameter `Repr` stands for its +representation. There are no constraints on `Repr`. In particular `Repr` +might be instantiated to a type that is itself not a subtype of +`Traversable`. That way, classes outside the collections hierarchy such +as `String` and `Array` can still make use of all operations defined in a +collection implementation trait. + +Taking `filter` as an example, this operation is defined once for all +collection classes in the trait `TraversableLike`. An outline of the +relevant code is shown in the above [outline of trait +`TraversableLike`](#outline-of-trait-traversablelike). The trait declares +two abstract methods, `newBuilder` +and `foreach`, which are implemented in concrete collection classes. The +`filter` operation is implemented in the same way for all collections +using these methods. It first constructs a new builder for the +representation type `Repr`, using `newBuilder`. It then traverses all +elements of the current collection, using `foreach`. If an element `x` +satisfies the given predicate `p` (i.e., `p(x)` is `true`), it is added to +the builder. Finally, the elements collected in the builder are +returned as an instance of the `Repr` collection type by calling the +builder's `result` method. + +A bit more complicated is the `map` operation on collections. For +instance, if `f` is a function from `String` to `Int`, and `xs` is a +`List[String]`, then `xs map f` should give a `List[Int]`. Likewise, +if `ys` is an `Array[String]`, then `ys map f` should give an +`Array[Int]`. The question is how do we achieve that without duplicating +the definition of the `map` method in lists and arrays. The +`newBuilder`/`foreach` framework shown in +[trait `TraversableLike`](#outline-of-trait-traversablelike) is +not sufficient for this because it only allows creation of new +instances of the same collection *type* whereas `map` needs an +instance of the same collection *type constructor*, but possibly with +a different element type. + +What's more, even the result type constructor of a function like `map` +might depend in non-trivial ways on the other argument types. Here is +an example: + + scala> import collection.immutable.BitSet + import collection.immutable.BitSet + + scala> val bits = BitSet(1, 2, 3) + bits: scala.collection.immutable.BitSet = BitSet(1, 2, 3) + + scala> bits map (_ * 2) + res13: scala.collection.immutable.BitSet = BitSet(2, 4, 6) + + scala> bits map (_.toFloat) + res14: scala.collection.immutable.Set[Float] + = Set(1.0, 2.0, 3.0) + +If you `map` the doubling function `_ * 2` over a bit set you obtain +another bit set. However, if you map the function `(_.toFloat)` over the +same bit set, the result is a general `Set[Float]`. Of course, it can't +be a bit set because bit sets contain `Int`s, not `Float`s. + +Note that `map`'s result type depends on the type of function that's +passed to it. If the result type of that function argument is again an +`Int`, the result of `map` is a `BitSet`, but if the result type of the +function argument is something else, the result of `map` is just a +`Set`. You'll find out soon how this type-flexibility is achieved in +Scala. + +The problem with `BitSet` is not an isolated case. Here are two more +interactions with the interpreter that both map a function over a `Map`: + + scala> Map("a" -> 1, "b" -> 2) map { case (x, y) => (y, x) } + res3: scala.collection.immutable.Map[Int,java.lang.String] + = Map(1 -> a, 2 -> b) + + scala> Map("a" -> 1, "b" -> 2) map { case (x, y) => y } + res4: scala.collection.immutable.Iterable[Int] + = List(1, 2) + +The first function swaps two arguments of a key/value pair. The result +of mapping this function is again a map, but now going in the other +direction. In fact, the first expression yields the inverse of the +original map, provided it is invertible. The second function, however, +maps the key/value pair to an integer, namely its value component. In +that case, we cannot form a `Map` from the results, but we can still +form an `Iterable`, a supertrait of `Map`. + +You might ask, why not restrict `map` so that it can always return the +same kind of collection? For instance, on bit sets `map` could accept +only `Int`-to-`Int` functions and on `Map`s it could only accept +pair-to-pair functions. Not only are such restrictions undesirable +from an object-oriented modelling point of view, they are illegal +because they would violate the Liskov substitution principle: A `Map` *is* +an `Iterable`. So every operation that's legal on an `Iterable` must also +be legal on a `Map`. + +Scala solves this problem instead with overloading: not the simple +form of overloading inherited by Java (that would not be flexible +enough), but the more systematic form of overloading that's provided +by implicit parameters. + +Implementation of `map` in `TraversableLike`: + + def map[B, That](f: Elem => B) + (implicit bf: CanBuildFrom[Repr, B, That]): That = { + val b = bf(this) + this.foreach(x => b += f(x)) + b.result + } + +The listing above shows trait `TraversableLike`'s implementation of +`map`. It's quite similar to the implementation of `filter` shown in [trait +`TraversableLike`](#outline-of-trait-traversablelike). +The principal difference is that where `filter` used +the `newBuilder` method, which is abstract in `TraversableLike`, `map` +uses a *builder factory* that's passed as an additional implicit +parameter of type `CanBuildFrom`. + +The `CanBuildFrom` trait: + + package scala.collection.generic + + trait CanBuildFrom[-From, -Elem, +To] { + // Creates a new builder + def apply(from: From): Builder[Elem, To] + } + +The listing above shows the definition of the trait `CanBuildFrom`, +which represents builder factories. It has three type parameters: `From` indicates +the type for which this builder factory applies, `Elem` indicates the element +type of the collection to be built, and `To` indicates the type of +collection to build. By defining the right implicit +definitions of builder factories, you can tailor the right typing +behavior as needed. Take class `BitSet` as an example. Its companion +object would contain a builder factory of type `CanBuildFrom[BitSet, Int, BitSet]`. +This means that when operating on a `BitSet` you can +construct another `BitSet` provided the element type of the collection to build +is `Int`. If this is not the case, the compiler will check the superclasses, and +fall back to the implicit builder factory defined in +`mutable.Set`'s companion object. The type of this more general builder +factory, where `A` is a generic type parameter, is: + + CanBuildFrom[Set[_], A, Set[A]] + +This means that when operating on an arbitrary `Set` (expressed by the +existential type `Set[_]`) you can build a `Set` again, no matter what the +element type `A` is. Given these two implicit instances of `CanBuildFrom`, +you can then rely on Scala's rules for implicit resolution to pick the +one that's appropriate and maximally specific. + +So implicit resolution provides the correct static types for tricky +collection operations such as `map`. But what about the dynamic types? +Specifically, say you map some function over a `List` value that has +`Iterable` as its static type: + + scala> val xs: Iterable[Int] = List(1, 2, 3) + xs: Iterable[Int] = List(1, 2, 3) + + scala> val ys = xs map (x => x * x) + ys: Iterable[Int] = List(1, 4, 9) + +The static type of `ys` above is `Iterable`, as expected. But its dynamic +type is (and should still be) `List`! This behavior is achieved by one +more indirection. The `apply` method in `CanBuildFrom` is passed the +source collection as argument. Most builder factories for generic +traversables (in fact all except builder factories for leaf classes) +forward the call to a method `genericBuilder` of a collection. The +`genericBuilder` method in turn calls the builder that belongs to the +collection in which it is defined. So Scala uses static implicit +resolution to resolve constraints on the types of `map`, and virtual +dispatch to pick the best dynamic type that corresponds to these +constraints. + +In the current example, the static implicit resolution will pick the +`Iterable`'s `CanBuildFrom`, which calls `genericBuilder` on the value it +received as argument. But at runtime, because of virtual dispatch, it is +`List.genericBuilder` that gets called rather than `Iterable.genericBuilder`, +and so map builds a `List`. + +## Integrating a new collection: RNA sequences ## + +What needs to be done if you want to integrate a new collection class, +so that it can profit from all predefined operations with the right +types? In the next few sections you'll be walked through two examples +that do this, namely sequences of RNA bases and prefix maps implemented +with Patricia tries. + +To start with the first example, we define the four RNA Bases: + + abstract class Base + case object A extends Base + case object U extends Base + case object G extends Base + case object C extends Base + + object Base { + val fromInt: Int => Base = Array(A, U, G, C) + val toInt: Base => Int = Map(A -> 0, U -> 1, G -> 2, C -> 3) + } + +Say you want to create a new sequence type for RNA strands, which are +sequences of bases A (adenine), U (uracil), G (guanine), and C +(cytosine). The definitions for bases are easily set up as shown in the +listing of RNA bases above. + +Every base is defined as a case object that inherits from a common +abstract class `Base`. The `Base` class has a companion object that +defines two functions that map between bases and the integers 0 to +3. You can see in the examples two different ways to use collections +to implement these functions. The `toInt` function is implemented as a +`Map` from `Base` values to integers. The reverse function, `fromInt`, is +implemented as an array. This makes use of the fact that both maps and +arrays *are* functions because they inherit from the `Function1` trait. + +The next task is to define a class for strands of RNA. Conceptually, a +strand of RNA is simply a `Seq[Base]`. However, RNA strands can get +quite long, so it makes sense to invest some work in a compact +representation. Because there are only four bases, a base can be +identified with two bits, and you can therefore store sixteen bases as +two-bit values in an integer. The idea, then, is to construct a +specialized subclass of `Seq[Base]`, which uses this packed +representation. + +### First version of RNA strands class ### + + import collection.IndexedSeqLike + import collection.mutable.{Builder, ArrayBuffer} + import collection.generic.CanBuildFrom + + final class RNA1 private (val groups: Array[Int], + val length: Int) extends IndexedSeq[Base] { + + import RNA1._ + + def apply(idx: Int): Base = { + if (idx < 0 || length <= idx) + throw new IndexOutOfBoundsException + Base.fromInt(groups(idx / N) >> (idx % N * S) & M) + } + } + + object RNA1 { + + // Number of bits necessary to represent group + private val S = 2 + + // Number of groups that fit in an Int + private val N = 32 / S + + // Bitmask to isolate a group + private val M = (1 << S) - 1 + + def fromSeq(buf: Seq[Base]): RNA1 = { + val groups = new Array[Int]((buf.length + N - 1) / N) + for (i <- 0 until buf.length) + groups(i / N) |= Base.toInt(buf(i)) << (i % N * S) + new RNA1(groups, buf.length) + } + + def apply(bases: Base*) = fromSeq(bases) + } + +The [RNA strands class listing](#first-version-of-rna-strands-class) above +presents the first version of this +class. It will be refined later. The class `RNA1` has a constructor that +takes an array of `Int`s as its first argument. This array contains the +packed RNA data, with sixteen bases in each element, except for the +last array element, which might be partially filled. The second +argument, `length`, specifies the total number of bases on the array +(and in the sequence). Class `RNA1` extends `IndexedSeq[Base]`. Trait +`IndexedSeq`, which comes from package `scala.collection.immutable`, +defines two abstract methods, `length` and `apply`. These need to be +implemented in concrete subclasses. Class `RNA1` implements `length` +automatically by defining a parametric field of the same name. It +implements the indexing method `apply` with the code given in [class +`RNA1`](#first-version-of-rna-strands-class). Essentially, `apply` first +extracts an integer value from the +`groups` array, then extracts the correct two-bit number from that +integer using right shift (`>>`) and mask (`&`). The private constants `S`, +`N`, and `M` come from the `RNA1` companion object. `S` specifies the size of +each packet (i.e., two); `N` specifies the number of two-bit packets per +integer; and `M` is a bit mask that isolates the lowest `S` bits in a +word. + +Note that the constructor of class `RNA1` is `private`. This means that +clients cannot create `RNA1` sequences by calling `new`, which makes +sense, because it hides the representation of `RNA1` sequences in terms +of packed arrays from the user. If clients cannot see what the +representation details of RNA sequences are, it becomes possible to +change these representation details at any point in the future without +affecting client code. In other words, this design achieves a good +decoupling of the interface of RNA sequences and its +implementation. However, if constructing an RNA sequence with `new` is +impossible, there must be some other way to create new RNA sequences, +else the whole class would be rather useless. In fact there are two +alternatives for RNA sequence creation, both provided by the `RNA1` +companion object. The first way is method `fromSeq`, which converts a +given sequence of bases (i.e., a value of type `Seq[Base]`) into an +instance of class `RNA1`. The `fromSeq` method does this by packing all +the bases contained in its argument sequence into an array, then +calling `RNA1`'s private constructor with that array and the length of +the original sequence as arguments. This makes use of the fact that a +private constructor of a class is visible in the class's companion +object. + +The second way to create an `RNA1` value is provided by the `apply` method +in the `RNA1` object. It takes a variable number of `Base` arguments and +simply forwards them as a sequence to `fromSeq`. Here are the two +creation schemes in action: + + scala> val xs = List(A, G, U, A) + xs: List[Product with Serializable with Base] = List(A, G, U, A) + + scala> RNA1.fromSeq(xs) + res1: RNA1 = RNA1(A, G, U, A) + + scala> val rna1 = RNA1(A, U, G, G, C) + rna1: RNA1 = RNA1(A, U, G, G, C) + +### Adapting the result type of RNA methods ### + +Here are some more interactions with the `RNA1` abstraction: + + scala> rna1.length + res2: Int = 5 + + scala> rna1.last + res3: Base = C + + scala> rna1.take(3) + res4: IndexedSeq[Base] = Vector(A, U, G) + +The first two results are as expected, but the last result of taking +the first three elements of `rna1` might not be. In fact, you see a +`IndexedSeq[Base]` as static result type and a `Vector` as the dynamic +type of the result value. You might have expected to see an `RNA1` value +instead. But this is not possible because all that was done in [class +`RNA1`](#first-version-of-rna-strands-class) was making `RNA1` extend +`IndexedSeq`. Class `IndexedSeq`, on the other +hand, has a `take` method that returns an `IndexedSeq`, and that's +implemented in terms of `IndexedSeq`'s default implementation, +`Vector`. So that's what you were seeing on the last line of the +previous interaction. + +Now that you understand why things are the way they are, the next +question should be what needs to be done to change them? One way to do +this would be to override the `take` method in class `RNA1`, maybe like +this: + + def take(count: Int): RNA1 = RNA1.fromSeq(super.take(count)) + +This would do the job for `take`. But what about `drop`, or `filter`, or +`init`? In fact there are over fifty methods on sequences that return +again a sequence. For consistency, all of these would have to be +overridden. This looks less and less like an attractive +option. Fortunately, there is a much easier way to achieve the same +effect, as shown in the next section. + + +### Second version of RNA strands class ### + + final class RNA2 private ( + val groups: Array[Int], + val length: Int + ) extends IndexedSeq[Base] with IndexedSeqLike[Base, RNA2] { + + import RNA2._ + + override def newBuilder: Builder[Base, RNA2] = + new ArrayBuffer[Base] mapResult fromSeq + + def apply(idx: Int): Base = // as before + } + +The RNA class needs to inherit not only from `IndexedSeq`, but +also from its implementation trait `IndexedSeqLike`. This is shown in +the above listing of class `RNA2`. The new implementation differs from +the previous one in only two aspects. First, class `RNA2` now also +extends `IndexedSeqLike[Base, RNA2]`. Second, it provides a builder for +RNA strands. The `IndexedSeqLike` trait +implements all concrete methods of `IndexedSeq` in an extensible +way. For instance, the return type of methods like `take`, `drop`, `filter`, +or `init` is the second type parameter passed to class `IndexedSeqLike`, +i.e., in class `RNA2` it is `RNA2` itself. + +To be able to do this, `IndexedSeqLike` bases itself on the `newBuilder` +abstraction, which creates a builder of the right kind. Subclasses of +trait `IndexedSeqLike` have to override `newBuilder` to return collections +of their own kind. In class `RNA2`, the `newBuilder` method returns a +builder of type `Builder[Base, RNA2]`. + +To construct this builder, it first creates an `ArrayBuffer`, which +itself is a `Builder[Base, ArrayBuffer]`. It then transforms the +`ArrayBuffer` builder by calling its `mapResult` method to an `RNA2` +builder. The `mapResult` method expects a transformation function from +`ArrayBuffer` to `RNA2` as its parameter. The function given is simply +`RNA2.fromSeq`, which converts an arbitrary base sequence to an `RNA2` +value (recall that an array buffer is a kind of sequence, so +`RNA2.fromSeq` can be applied to it). + +If you had left out the `newBuilder` definition, you would have gotten +an error message like the following: + + RNA2.scala:5: error: overriding method newBuilder in trait + TraversableLike of type => scala.collection.mutable.Builder[Base,RNA2]; + method newBuilder in trait GenericTraversableTemplate of type + => scala.collection.mutable.Builder[Base,IndexedSeq[Base]] has + incompatible type + class RNA2 private (val groups: Array[Int], val length: Int) + ^ + one error found + +The error message is quite long and complicated, which reflects the +intricate way the collection libraries are put together. It's best to +ignore the information about where the methods come from, because in +this case it detracts more than it helps. What remains is that a +method `newBuilder` with result type `Builder[Base, RNA2]` needed to be +defined, but a method `newBuilder` with result type +`Builder[Base,IndexedSeq[Base]]` was found. The latter does not override +the former. The first method, whose result type is `Builder[Base, RNA2]`, +is an abstract method that got instantiated at this type in +[class `RNA2`](#second-version-of-rna-strands-class) by passing the +`RNA2` type parameter to `IndexedSeqLike`. The +second method, of result type `Builder[Base,IndexedSeq[Base]]`, is +what's provided by the inherited `IndexedSeq` class. In other words, the +`RNA2` class is invalid without a definition of `newBuilder` with the +first result type. + +With the refined implementation of the [`RNA2` class](#second-version-of-rna-strands-class), +methods like `take`, +`drop`, or `filter` work now as expected: + + scala> val rna2 = RNA2(A, U, G, G, C) + rna2: RNA2 = RNA2(A, U, G, G, C) + + scala> rna2 take 3 + res5: RNA2 = RNA2(A, U, G) + + scala> rna2 filter (U !=) + res6: RNA2 = RNA2(A, G, G, C) + +### Dealing with map and friends ### + +However, there is another class of methods in collections that are not +dealt with yet. These methods do not always return the collection type +exactly. They might return the same kind of collection, but with a +different element type. The classical example of this is the `map` +method. If `s` is a `Seq[Int]`, and `f` is a function from `Int` to `String`, +then `s.map(f)` would return a `Seq[String]`. So the element type changes +between the receiver and the result, but the kind of collection stays +the same. + +There are a number of other methods that behave like `map`. For some of +them you would expect this (e.g., `flatMap`, `collect`), but for others +you might not. For instance, the append method, `++`, also might return +a result of different type as its arguments--appending a list of +`String` to a list of `Int` would give a list of `Any`. How should these +methods be adapted to RNA strands? The desired behavior would be to get +back an RNA strand when mapping bases to bases or appending two RNA strands +with `++`: + + scala> val rna = RNA(A, U, G, G, C) + rna: RNA = RNA(A, U, G, G, C) + + scala> rna map { case A => U case b => b } + res7: RNA = RNA(U, U, G, G, C) + + scala> rna ++ rna + res8: RNA = RNA(A, U, G, G, C, A, U, G, G, C) + +On the other hand, mapping bases to some other type over an RNA strand +cannot yield another RNA strand because the new elements have the +wrong type. It has to yield a sequence instead. In the same vein +appending elements that are not of type `Base` to an RNA strand can +yield a general sequence, but it cannot yield another RNA strand. + + scala> rna map Base.toInt + res2: IndexedSeq[Int] = Vector(0, 1, 2, 2, 3) + + scala> rna ++ List("missing", "data") + res3: IndexedSeq[java.lang.Object] = + Vector(A, U, G, G, C, missing, data) + +This is what you'd expect in the ideal case. But this is not what the +[`RNA2` class](#second-version-of-rna-strands-class) provides. In fact, all +examples will return instances of `Vector`, not just the last two. If you run +the first three commands above with instances of this class you obtain: + + scala> val rna2 = RNA2(A, U, G, G, C) + rna2: RNA2 = RNA2(A, U, G, G, C) + + scala> rna2 map { case A => U case b => b } + res0: IndexedSeq[Base] = Vector(U, U, G, G, C) + + scala> rna2 ++ rna2 + res1: IndexedSeq[Base] = Vector(A, U, G, G, C, A, U, G, G, C) + +So the result of `map` and `++` is never an RNA strand, even if the +element type of the generated collection is `Base`. To see how to do +better, it pays to have a close look at the signature of the `map` +method (or of `++`, which has a similar signature). The `map` method is +originally defined in class `scala.collection.TraversableLike` with the +following signature: + + def map[B, That](f: A => B) + (implicit cbf: CanBuildFrom[Repr, B, That]): That + +Here `A` is the type of elements of the collection, and `Repr` is the type +of the collection itself, that is, the second type parameter that gets +passed to implementation classes such as `TraversableLike` and +`IndexedSeqLike`. The `map` method takes two more type parameters, `B` and +`That`. The `B` parameter stands for the result type of the mapping +function, which is also the element type of the new collection. The +`That` appears as the result type of `map`, so it represents the type of +the new collection that gets created. + +How is the `That` type determined? In fact it is linked to the other +types by an implicit parameter `cbf`, of type `CanBuildFrom[Repr, B, That]`. +These `CanBuildFrom` implicits are defined by the individual +collection classes. Recall that an implicit value of type +`CanBuildFrom[Repr, B, That]` says: "Here is a way, given a collection +of type `Repr` and new elements of type `B`, to build a collection of type +`That` containing those elements". + +Now the behavior of `map` and `++` on `RNA2` sequences becomes +clearer. There is no `CanBuildFrom` instance that creates `RNA2` +sequences, so the next best available `CanBuildFrom` was found in the +companion object of the inherited trait `IndexedSeq`. That implicit +creates `Vector`s (recall that `Vector` is the default implementation +of `IndexedSeq`), and that's what you saw when applying `map` to +`rna2`. + + +### Final version of RNA strands class ### + + final class RNA private (val groups: Array[Int], val length: Int) + extends IndexedSeq[Base] with IndexedSeqLike[Base, RNA] { + + import RNA._ + + // Mandatory re-implementation of `newBuilder` in `IndexedSeq` + override protected[this] def newBuilder: Builder[Base, RNA] = + RNA.newBuilder + + // Mandatory implementation of `apply` in `IndexedSeq` + def apply(idx: Int): Base = { + if (idx < 0 || length <= idx) + throw new IndexOutOfBoundsException + Base.fromInt(groups(idx / N) >> (idx % N * S) & M) + } + + // Optional re-implementation of foreach, + // to make it more efficient. + override def foreach[U](f: Base => U): Unit = { + var i = 0 + var b = 0 + while (i < length) { + b = if (i % N == 0) groups(i / N) else b >>> S + f(Base.fromInt(b & M)) + i += 1 + } + } + } + +### Final version of RNA companion object ### + + object RNA { + + private val S = 2 // number of bits in group + private val M = (1 << S) - 1 // bitmask to isolate a group + private val N = 32 / S // number of groups in an Int + + def fromSeq(buf: Seq[Base]): RNA = { + val groups = new Array[Int]((buf.length + N - 1) / N) + for (i <- 0 until buf.length) + groups(i / N) |= Base.toInt(buf(i)) << (i % N * S) + new RNA(groups, buf.length) + } + + def apply(bases: Base*) = fromSeq(bases) + + def newBuilder: Builder[Base, RNA] = + new ArrayBuffer mapResult fromSeq + + implicit def canBuildFrom: CanBuildFrom[RNA, Base, RNA] = + new CanBuildFrom[RNA, Base, RNA] { + def apply(): Builder[Base, RNA] = newBuilder + def apply(from: RNA): Builder[Base, RNA] = newBuilder + } + } + +To address this shortcoming, you need to define an implicit instance +of `CanBuildFrom` in the companion object of the RNA class. That +instance should have type `CanBuildFrom[RNA, Base, RNA]`. Hence, this +instance states that, given an RNA strand and a new element type `Base`, +you can build another collection which is again an RNA strand. The two +listings above of [class `RNA`](#final-version-of-rna-strands-class) and +[its companion object](#final-version-of-rna-companion-object) show the +details. Compared to [class `RNA2`](#second-version-of-rna-strands-class) +there are two important +differences. First, the `newBuilder` implementation has moved from the +RNA class to its companion object. The `newBuilder` method in class `RNA` +simply forwards to this definition. Second, there is now an implicit +`CanBuildFrom` value in object `RNA`. To create this value you need to +define two `apply` methods in the `CanBuildFrom` trait. Both create a new +builder for an `RNA` collection, but they differ in their argument +list. The `apply()` method simply creates a new builder of the right +type. By contrast, the `apply(from)` method takes the original +collection as argument. This can be useful to adapt the dynamic type +of builder's return type to be the same as the dynamic type of the +receiver. In the case of `RNA` this does not come into play because `RNA` +is a final class, so any receiver of static type `RNA` also has `RNA` as +its dynamic type. That's why `apply(from)` also simply calls `newBuilder`, +ignoring its argument. + +That is it. The final [`RNA` class](#final-version-of-rna-strands-class) +implements all collection methods at +their expected types. Its implementation requires a little bit of +protocol. In essence, you need to know where to put the `newBuilder` +factories and the `canBuildFrom` implicits. On the plus side, with +relatively little code you get a large number of methods automatically +defined. Also, if you don't intend to do bulk operations like `take`, +`drop`, `map`, or `++` on your collection you can choose to not go the extra +length and stop at the implementation shown in for [class `RNA1`](#first-version-of-rna-strands-class). + +The discussion so far centered on the minimal amount of definitions +needed to define new sequences with methods that obey certain +types. But in practice you might also want to add new functionality to +your sequences or to override existing methods for better +efficiency. An example of this is the overridden `foreach` method in +class `RNA`. `foreach` is an important method in its own right because it +implements loops over collections. Furthermore, many other collection +methods are implemented in terms of `foreach`. So it makes sense to +invest some effort optimizing the method's implementation. The +standard implementation of `foreach` in `IndexedSeq` will simply select +every `i`'th element of the collection using `apply`, where `i` ranges from +0 to the collection's length minus one. So this standard +implementation selects an array element and unpacks a base from it +once for every element in an RNA strand. The overriding `foreach` in +class `RNA` is smarter than that. For every selected array element it +immediately applies the given function to all bases contained in +it. So the effort for array selection and bit unpacking is much +reduced. + +## Integrating a new prefix map ## + +As a second example you'll learn how to integrate a new kind of map +into the collection framework. The idea is to implement a mutable map +with `String` as the type of keys by a "Patricia trie". The term +*Patricia* is in fact an abbreviation for "Practical Algorithm to +Retrieve Information Coded in Alphanumeric" and *trie* comes from +re*trie*val (a trie is also called a radix tree or prefix tree). +The idea is to store a set or a map as a tree where subsequent +characters in a search key +uniquely determine a path through the tree. For instance a Patricia trie +storing the strings "abc", "abd", "al", "all" and "xy" would look +like this: + +A sample patricia trie: + + +To find the node corresponding to the string "abc" in this trie, +simply follow the subtree labeled "a", proceed from there to the +subtree labelled "b", to finally reach its subtree labelled "c". If +the Patricia trie is used as a map, the value that's associated with a +key is stored in the nodes that can be reached by the key. If it is a +set, you simply store a marker saying that the node is present in the +set. + +Patricia tries support very efficient lookups and updates. Another +nice feature is that they support selecting a subcollection by giving +a prefix. For instance, in the patricia tree above you can obtain the +sub-collection of all keys that start with an "a" simply by following +the "a" link from the root of the tree. + +Based on these ideas we will now walk you through the implementation +of a map that's implemented as a Patricia trie. We call the map a +`PrefixMap`, which means that it provides a method `withPrefix` that +selects a submap of all keys starting with a given prefix. We'll first +define a prefix map with the keys shown in the running example: + + scala> val m = PrefixMap("abc" -> 0, "abd" -> 1, "al" -> 2, + "all" -> 3, "xy" -> 4) + m: PrefixMap[Int] = Map((abc,0), (abd,1), (al,2), (all,3), (xy,4)) + +Then calling `withPrefix` on `m` will yield another prefix map: + + scala> m withPrefix "a" + res14: PrefixMap[Int] = Map((bc,0), (bd,1), (l,2), (ll,3)) + +### Patricia trie implementation ### + + import collection._ + + class PrefixMap[T] + extends mutable.Map[String, T] + with mutable.MapLike[String, T, PrefixMap[T]] { + + var suffixes: immutable.Map[Char, PrefixMap[T]] = Map.empty + var value: Option[T] = None + + def get(s: String): Option[T] = + if (s.isEmpty) value + else suffixes get (s(0)) flatMap (_.get(s substring 1)) + + def withPrefix(s: String): PrefixMap[T] = + if (s.isEmpty) this + else { + val leading = s(0) + suffixes get leading match { + case None => + suffixes = suffixes + (leading -> empty) + case _ => + } + suffixes(leading) withPrefix (s substring 1) + } + + override def update(s: String, elem: T) = + withPrefix(s).value = Some(elem) + + override def remove(s: String): Option[T] = + if (s.isEmpty) { val prev = value; value = None; prev } + else suffixes get (s(0)) flatMap (_.remove(s substring 1)) + + def iterator: Iterator[(String, T)] = + (for (v <- value.iterator) yield ("", v)) ++ + (for ((chr, m) <- suffixes.iterator; + (s, v) <- m.iterator) yield (chr +: s, v)) + + def += (kv: (String, T)): this.type = { update(kv._1, kv._2); this } + + def -= (s: String): this.type = { remove(s); this } + + override def empty = new PrefixMap[T] + } + + +The previous listing shows the definition of `PrefixMap`. The map has +keys of type `String` and the values are of parametric type `T`. It extends +`mutable.Map[String, T]` and `mutable.MapLike[String, T, PrefixMap[T]]`. +You have seen this pattern already for sequences in the +RNA strand example; then as now inheriting an implementation class +such as `MapLike` serves to get the right result type for +transformations such as `filter`. + +A prefix map node has two mutable fields: `suffixes` and `value`. The +`value` field contains an optional value that's associated with the +node. It is initialized to `None`. The `suffixes` field contains a map +from characters to `PrefixMap` values. It is initialized to the empty +map. + +You might ask why we picked an immutable map as the implementation +type for `suffixes`? Would not a mutable map have been more standard, +since `PrefixMap` as a whole is also mutable? The answer is that +immutable maps that contain only a few elements are very efficient in +both space and execution time. For instance, maps that contain fewer +than 5 elements are represented as a single object. By contrast, the +standard mutable map is a `HashMap`, which typically occupies around 80 +bytes, even if it is empty. So if small collections are common, it's +better to pick immutable over mutable. In the case of Patricia tries, +we'd expect that most nodes except the ones at the very top of the +tree would contain only a few successors. So storing these successors +in an immutable map is likely to be more efficient. + +Now have a look at the first method that needs to be implemented for a +map: `get`. The algorithm is as follows: To get the value associated +with the empty string in a prefix map, simply select the optional +`value` stored in the root of the tree (the current map). +Otherwise, if the key string is +not empty, try to select the submap corresponding to the first +character of the string. If that yields a map, follow up by looking up +the remainder of the key string after its first character in that +map. If the selection fails, the key is not stored in the map, so +return with `None`. The combined selection over an option value `opt` is +elegantly expressed using `opt.flatMap(x => f(x))`. When applied to an +optional value that is `None`, it returns `None`. Otherwise `opt` is +`Some(x)` and the function `f` is applied to the encapsulated value `x`, +yielding a new option, which is returned by the flatmap. + +The next two methods to implement for a mutable map are `+=` and `-=`. In +the implementation of `PrefixMap`, these are defined in terms of two +other methods: `update` and `remove`. + +The `remove` method is very similar to `get`, except that before returning +any associated value, the field containing that value is set to +`None`. The `update` method first calls `withPrefix` to navigate to the tree +node that needs to be updated, then sets the `value` field of that node +to the given value. The `withPrefix` method navigates through the tree, +creating sub-maps as necessary if some prefix of characters is not yet +contained as a path in the tree. + +The last abstract method to implement for a mutable map is +`iterator`. This method needs to produce an iterator that yields all +key/value pairs stored in the map. For any given prefix map this +iterator is composed of the following parts: First, if the map +contains a defined value, `Some(x)`, in the `value` field at its root, +then `("", x)` is the first element returned from the +iterator. Furthermore, the iterator needs to traverse the iterators of +all submaps stored in the `suffixes` field, but it needs to add a +character in front of every key string returned by those +iterators. More precisely, if `m` is the submap reached from the root +through a character `chr`, and `(s, v)` is an element returned from +`m.iterator`, then the root's iterator will return `(chr +: s, v)` +instead. This logic is implemented quite concisely as a concatenation +of two `for` expressions in the implementation of the `iterator` method in +`PrefixMap`. The first `for` expression iterates over `value.iterator`. This +makes use of the fact that `Option` values define an iterator method +that returns either no element, if the option value is `None`, or +exactly one element `x`, if the option value is `Some(x)`. + +Note that there is no `newBuilder` method defined in `PrefixMap`. There is +no need to, because maps and sets come with default builders, which +are instances of class `MapBuilder`. For a mutable map the default +builder starts with an empty map and then adds successive elements +using the map's `+=` method. For immutable maps, the non-destructive +element addition method `+` is used instead of method `+=`. Sets work +in the same way. + +However, in all these cases, to build the right kind of colletion +you need to start with an empty collection of that kind. This is +provided by the `empty` method, which is the last method defined in +`PrefixMap`. This method simply returns a fresh `PrefixMap`. + + +### The companion object for prefix maps ### + + import scala.collection.mutable.{Builder, MapBuilder} + import scala.collection.generic.CanBuildFrom + + object PrefixMap extends { + def empty[T] = new PrefixMap[T] + + def apply[T](kvs: (String, T)*): PrefixMap[T] = { + val m: PrefixMap[T] = empty + for (kv <- kvs) m += kv + m + } + + def newBuilder[T]: Builder[(String, T), PrefixMap[T]] = + new MapBuilder[String, T, PrefixMap[T]](empty) + + implicit def canBuildFrom[T] + : CanBuildFrom[PrefixMap[_], (String, T), PrefixMap[T]] = + new CanBuildFrom[PrefixMap[_], (String, T), PrefixMap[T]] { + def apply(from: PrefixMap[_]) = newBuilder[T] + def apply() = newBuilder[T] + } + } + +We'll now turn to the companion object `PrefixMap`. In fact it is not +strictly necessary to define this companion object, as class `PrefixMap` +can stand well on its own. The main purpose of object `PrefixMap` is to +define some convenience factory methods. It also defines a +`CanBuildFrom` implicit to make typing work out better. + +The two convenience methods are `empty` and `apply`. The same methods are +present for all other collections in Scala's collection framework so +it makes sense to define them here, too. With the two methods, you can +write `PrefixMap` literals like you do for any other collection: + + scala> PrefixMap("hello" -> 5, "hi" -> 2) + res0: PrefixMap[Int] = Map(hello -> 5, hi -> 2) + + scala> PrefixMap.empty[String] + res2: PrefixMap[String] = Map() + +The other member in object `PrefixMap` is an implicit `CanBuildFrom` +instance. It has the same purpose as the `CanBuildFrom` definition in +the [`RNA` companion object](#final-version-of-rna-companion-object) +from the last section: to make methods like `map` return the best possible +type. For instance, consider mapping a function over the key/value +pairs of a `PrefixMap`. As long as that function produces pairs of +strings and some second type, the result collection will again be a +`PrefixMap`. Here's an example: + + scala> res0 map { case (k, v) => (k + "!", "x" * v) } + res8: PrefixMap[String] = Map(hello! -> xxxxx, hi! -> xx) + +The given function argument takes the key/value bindings of the prefix +map `res0` and produces pairs of strings. The result of the `map` is a +`PrefixMap`, this time with value type `String` instead of `Int`. Without +the `canBuildFrom` implicit in `PrefixMap` the result would just have been +a general mutable map, not a prefix map. For convenience, the `PrefixMap` +object defines a `newBuilder` method, but it still just uses the +default `MapBuilder`. + +## Summary ## + +To summarize, if you want to fully integrate a new collection class +into the framework you need to pay attention to the following points: + +1. Decide whether the collection should be mutable or immutable. +2. Pick the right base traits for the collection. +3. Inherit from the right implementation trait to implement most + collection operations. +4. If you want `map` and similar operations to return instances of your + collection type, provide an implicit `CanBuildFrom` in your class's + companion object. + +You have now seen how Scala's collections are built and how you can +add new kinds of collections. Because of Scala's rich support for +abstraction, each new collection type has a large number of +methods without having to reimplement them all over again. + +### Acknowledgement ### + +These pages contain material adapted from the 2nd edition of +[Programming in Scala](http://www.artima.com/shop/programming_in_scala) by +Odersky, Spoon and Venners. We thank Artima for graciously agreeing to its +publication. + diff --git a/ko/overviews/index.md b/ko/overviews/index.md new file mode 100644 index 0000000000..8f2c084ab6 --- /dev/null +++ b/ko/overviews/index.md @@ -0,0 +1,12 @@ +--- +layout: guides-index +language: ko +title: 가이드 및 개요 +--- + +
+

핵심 라이브러리

+
+ * 스칼라 컬렉션 라이브러리 + * [들어가며..](/ko/overviews/collections/introduction.html) + diff --git a/overviews/collections/arrays.md b/overviews/collections/arrays.md index e698f2118b..d39c30a08e 100644 --- a/overviews/collections/arrays.md +++ b/overviews/collections/arrays.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 10 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- [Array](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/Array.html) is a special kind of collection in Scala. On the one hand, Scala arrays correspond one-to-one to Java arrays. That is, a Scala array `Array[Int]` is represented as a Java `int[]`, an `Array[Double]` is represented as a Java `double[]` and a `Array[String]` is represented as a Java `String[]`. But at the same time, Scala arrays offer much more than their Java analogues. First, Scala arrays can be _generic_. That is, you can have an `Array[T]`, where `T` is a type parameter or abstract type. Second, Scala arrays are compatible with Scala sequences - you can pass an `Array[T]` where a `Seq[T]` is required. Finally, Scala arrays also support all sequence operations. Here's an example of this in action: diff --git a/overviews/collections/concrete-immutable-collection-classes.md b/overviews/collections/concrete-immutable-collection-classes.md index 76c29daeb5..2822dd9713 100644 --- a/overviews/collections/concrete-immutable-collection-classes.md +++ b/overviews/collections/concrete-immutable-collection-classes.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 8 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- Scala provides many concrete immutable collection classes for you to choose from. They differ in the traits they implement (maps, sets, sequences), whether they can be infinite, and the speed of various operations. Here are some of the most common immutable collection types used in Scala. diff --git a/overviews/collections/concrete-mutable-collection-classes.md b/overviews/collections/concrete-mutable-collection-classes.md index ccedfe4194..6129e0f8b3 100644 --- a/overviews/collections/concrete-mutable-collection-classes.md +++ b/overviews/collections/concrete-mutable-collection-classes.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 9 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- You've now seen the most commonly used immutable collection classes that Scala provides in its standard library. Take a look now at the mutable collection classes. diff --git a/overviews/collections/conversions-between-java-and-scala-collections.md b/overviews/collections/conversions-between-java-and-scala-collections.md index e4b5001e91..5d2b0f4dc4 100644 --- a/overviews/collections/conversions-between-java-and-scala-collections.md +++ b/overviews/collections/conversions-between-java-and-scala-collections.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 17 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- Like Scala, Java also has a rich collections library. There are many similarities between the two. For instance, both libraries know iterators, iterables, sets, maps, and sequences. But there are also important differences. In particular, the Scala libraries put much more emphasis on immutable collections, and provide many more operations that transform a collection into a new one. diff --git a/overviews/collections/creating-collections-from-scratch.md b/overviews/collections/creating-collections-from-scratch.md index 0bba616794..5d022e2b2d 100644 --- a/overviews/collections/creating-collections-from-scratch.md +++ b/overviews/collections/creating-collections-from-scratch.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 16 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- You have syntax `List(1, 2, 3)` to create a list of three integers and `Map('A' -> 1, 'C' -> 2)` to create a map with two bindings. This is actually a universal feature of Scala collections. You can take any collection name and follow it by a list of elements in parentheses. The result will be a new collection with the given elements. Here are some more examples: diff --git a/overviews/collections/equality.md b/overviews/collections/equality.md index 3a076bf967..cc993e2748 100644 --- a/overviews/collections/equality.md +++ b/overviews/collections/equality.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 13 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- The collection libraries have a uniform approach to equality and hashing. The idea is, first, to divide collections into sets, maps, and sequences. Collections in different categories are always unequal. For instance, `Set(1, 2, 3)` is unequal to `List(1, 2, 3)` even though they contain the same elements. On the other hand, within the same category, collections are equal if and only if they have the same elements (for sequences: the same elements in the same order). For example, `List(1, 2, 3) == Vector(1, 2, 3)`, and `HashSet(1, 2) == TreeSet(2, 1)`. diff --git a/overviews/collections/introduction.md b/overviews/collections/introduction.md index b44cabd5b8..e0704db9a6 100644 --- a/overviews/collections/introduction.md +++ b/overviews/collections/introduction.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 1 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- **Martin Odersky, and Lex Spoon** diff --git a/overviews/collections/iterators.md b/overviews/collections/iterators.md index f8833c60ce..7d99fb14ac 100644 --- a/overviews/collections/iterators.md +++ b/overviews/collections/iterators.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 15 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- An iterator is not a collection, but rather a way to access the elements of a collection one by one. The two basic operations on an iterator `it` are `next` and `hasNext`. A call to `it.next()` will return the next element of the iterator and advance the state of the iterator. Calling `next` again on the same iterator will then yield the element one beyond the one returned previously. If there are no more elements to return, a call to `next` will throw a `NoSuchElementException`. You can find out whether there are more elements to return using [Iterator](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterator.html)'s `hasNext` method. diff --git a/overviews/collections/maps.md b/overviews/collections/maps.md index b213f15c0e..ca955548ed 100644 --- a/overviews/collections/maps.md +++ b/overviews/collections/maps.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 7 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- A [Map](http://www.scala-lang.org/api/current/scala/collection/Map.html) is an [Iterable](http://www.scala-lang.org/api/current/scala/collection/Iterable.html) consisting of pairs of keys and values (also named _mappings_ or _associations_). Scala's [Predef](http://www.scala-lang.org/api/current/scala/Predef$.html) class offers an implicit conversion that lets you write `key -> value` as an alternate syntax for the pair `(key, value)`. For instance `Map("x" -> 24, "y" -> 25, "z" -> 26)` means exactly the same as `Map(("x", 24), ("y", 25), ("z", 26))`, but reads better. diff --git a/overviews/collections/migrating-from-scala-27.md b/overviews/collections/migrating-from-scala-27.md index fa0d66dd16..62b3203b89 100644 --- a/overviews/collections/migrating-from-scala-27.md +++ b/overviews/collections/migrating-from-scala-27.md @@ -7,7 +7,7 @@ disqus: true partof: collections num: 18 outof: 18 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- Porting your existing Scala applications to use the new collections should be almost automatic. There are only a couple of possible issues to take care of. diff --git a/overviews/collections/overview.md b/overviews/collections/overview.md index 8b8bb56f6e..a29ba48c5f 100644 --- a/overviews/collections/overview.md +++ b/overviews/collections/overview.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 2 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- Scala collections systematically distinguish between mutable and diff --git a/overviews/collections/performance-characteristics.md b/overviews/collections/performance-characteristics.md index 9d640eb974..5a7fabcb91 100644 --- a/overviews/collections/performance-characteristics.md +++ b/overviews/collections/performance-characteristics.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 12 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- The previous explanations have made it clear that different collection types have different performance characteristics. That's often the primary reason for picking one collection type over another. You can see the performance characteristics of some common operations on collections summarized in the following two tables. diff --git a/overviews/collections/seqs.md b/overviews/collections/seqs.md index 4515814910..c74133cd2c 100644 --- a/overviews/collections/seqs.md +++ b/overviews/collections/seqs.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 5 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- The [Seq](http://www.scala-lang.org/api/current/scala/collection/Seq.html) trait represents sequences. A sequence is a kind of iterable that has a `length` and whose elements have fixed index positions, starting from `0`. diff --git a/overviews/collections/sets.md b/overviews/collections/sets.md index 0d55fd27db..d8ebf4459a 100644 --- a/overviews/collections/sets.md +++ b/overviews/collections/sets.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 6 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- `Set`s are `Iterable`s that contain no duplicate elements. The operations on sets are summarized in the following table for general sets and in the table after that for mutable sets. They fall into the following categories: diff --git a/overviews/collections/strings.md b/overviews/collections/strings.md index a49cf46d9c..3290bfb0c0 100644 --- a/overviews/collections/strings.md +++ b/overviews/collections/strings.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 11 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- Like arrays, strings are not directly sequences, but they can be converted to them, and they also support all sequence operations on strings. Here are some examples of operations you can invoke on strings. diff --git a/overviews/collections/trait-iterable.md b/overviews/collections/trait-iterable.md index 7db476a1a3..82e4083422 100644 --- a/overviews/collections/trait-iterable.md +++ b/overviews/collections/trait-iterable.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 4 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- The next trait from the top in the collections hierarchy is `Iterable`. All methods in this trait are defined in terms of an abstract method, `iterator`, which yields the collection's elements one by one. The `foreach` method from trait `Traversable` is implemented in `Iterable` in terms of `iterator`. Here is the actual implementation: diff --git a/overviews/collections/trait-traversable.md b/overviews/collections/trait-traversable.md index 5e91b1060d..1153888799 100644 --- a/overviews/collections/trait-traversable.md +++ b/overviews/collections/trait-traversable.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 3 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- At the top of the collection hierarchy is trait `Traversable`. Its only abstract operation is `foreach`: diff --git a/overviews/collections/views.md b/overviews/collections/views.md index b53645a5e9..b456c2585c 100644 --- a/overviews/collections/views.md +++ b/overviews/collections/views.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 14 -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- Collections have quite a few methods that construct new collections. Examples are `map`, `filter` or `++`. We call such methods transformers because they take at least one collection as their receiver object and produce another collection as their result. diff --git a/overviews/core/_posts/2010-11-30-actors.md b/overviews/core/_posts/2010-11-30-actors.md index 0913d7f057..a704f3cdfd 100644 --- a/overviews/core/_posts/2010-11-30-actors.md +++ b/overviews/core/_posts/2010-11-30-actors.md @@ -2,7 +2,7 @@ layout: overview title: The Scala Actors API overview: actors -languages: [zh-cn, es] +languages: [ko, zh-cn, es] --- **Philipp Haller and Stephen Tu** diff --git a/overviews/core/_posts/2010-12-15-architecture-of-scala-collections.md b/overviews/core/_posts/2010-12-15-architecture-of-scala-collections.md index 7d7eb5dc1c..f09689f489 100644 --- a/overviews/core/_posts/2010-12-15-architecture-of-scala-collections.md +++ b/overviews/core/_posts/2010-12-15-architecture-of-scala-collections.md @@ -2,7 +2,7 @@ layout: overview title: The Architecture of Scala Collections overview: architecture-of-scala-collections -languages: [zh-cn] +languages: [ko, zh-cn] --- **Martin Odersky and Lex Spoon** diff --git a/overviews/core/_posts/2012-09-20-futures.md b/overviews/core/_posts/2012-09-20-futures.md index e2d5cd2f6c..f53a7444ed 100644 --- a/overviews/core/_posts/2012-09-20-futures.md +++ b/overviews/core/_posts/2012-09-20-futures.md @@ -4,7 +4,7 @@ title: Futures and Promises label-color: success label-text: New in 2.10 overview: futures -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- **By: Philipp Haller, Aleksandar Prokopec, Heather Miller, Viktor Klang, Roland Kuhn, and Vojin Jovanovic** diff --git a/overviews/core/_posts/2012-09-20-implicit-classes.md b/overviews/core/_posts/2012-09-20-implicit-classes.md index c37f49361e..8204f5199b 100644 --- a/overviews/core/_posts/2012-09-20-implicit-classes.md +++ b/overviews/core/_posts/2012-09-20-implicit-classes.md @@ -4,7 +4,7 @@ title: Implicit Classes overview: implicit-classes label-color: success label-text: Available -languages: [zh-cn] +languages: [ko, zh-cn] --- **Josh Suereth** diff --git a/overviews/core/_posts/2012-09-21-string-interpolation.md b/overviews/core/_posts/2012-09-21-string-interpolation.md index 880c75c108..59324df014 100644 --- a/overviews/core/_posts/2012-09-21-string-interpolation.md +++ b/overviews/core/_posts/2012-09-21-string-interpolation.md @@ -5,7 +5,7 @@ disqus: true label-color: success label-text: New in 2.10 overview: string-interpolation -languages: [es, ja, zh-cn] +languages: [ko, es, ja, zh-cn] --- **Josh Suereth** diff --git a/overviews/core/_posts/2012-11-03-value-classes.md b/overviews/core/_posts/2012-11-03-value-classes.md index aea31a6553..a279f046d8 100644 --- a/overviews/core/_posts/2012-11-03-value-classes.md +++ b/overviews/core/_posts/2012-11-03-value-classes.md @@ -4,7 +4,7 @@ title: Value Classes and Universal Traits label-color: success label-text: New in 2.10 overview: value-classes -languages: [ja, zh-cn] +languages: [ko, ja, zh-cn] --- **Mark Harrah** diff --git a/overviews/core/_posts/2012-11-08-actors-migration-guide.md b/overviews/core/_posts/2012-11-08-actors-migration-guide.md index 021e1a7455..02660af3c2 100644 --- a/overviews/core/_posts/2012-11-08-actors-migration-guide.md +++ b/overviews/core/_posts/2012-11-08-actors-migration-guide.md @@ -4,7 +4,7 @@ title: The Scala Actors Migration Guide label-color: success label-text: New in 2.10 overview: actors-migration-guide -languages: [zh-cn] +languages: [ko, zh-cn] --- **Vojin Jovanovic and Philipp Haller** diff --git a/overviews/core/_posts/2016-11-01-binary-compatibility-of-scala-releases.md b/overviews/core/_posts/2016-11-01-binary-compatibility-of-scala-releases.md index 2f90a74fa2..a1d8a1a3b0 100644 --- a/overviews/core/_posts/2016-11-01-binary-compatibility-of-scala-releases.md +++ b/overviews/core/_posts/2016-11-01-binary-compatibility-of-scala-releases.md @@ -2,6 +2,7 @@ layout: overview title: Binary Compatibility of Scala Releases overview: binary-compatibility-of-scala-releases +languages: [ko] --- When two versions of Scala are binary compatible, it is safe to compile your project on one Scala version and link against another Scala version at run time. Safe run-time linkage (only!) means that the JVM does not throw a (subclass of) [`LinkageError`](http://docs.oracle.com/javase/7/docs/api/java/lang/LinkageError.html) when executing your program in the mixed scenario, assuming that none arise when compiling and running on the same version of Scala. Concretely, this means you may have external dependencies on your run-time classpath that use a different version of Scala than the one you're compiling with, as long as they're binary compatible. In other words, separate compilation on different binary compatible versions does not introduce problems compared to compiling and running everything on the same version of Scala. diff --git a/overviews/index.md b/overviews/index.md index 30b609c217..8818aa96a0 100644 --- a/overviews/index.md +++ b/overviews/index.md @@ -1,7 +1,7 @@ --- layout: guides-index title: Guides and Overviews -languages: [ja, zh-cn, es] +languages: [ko, ja, zh-cn, es] ---
diff --git a/overviews/macros/annotations.md b/overviews/macros/annotations.md index ab825032ff..1500c96851 100644 --- a/overviews/macros/annotations.md +++ b/overviews/macros/annotations.md @@ -7,7 +7,7 @@ disqus: true partof: macros num: 10 outof: 13 -languages: [ja] +languages: [ko, ja] --- MACRO PARADISE diff --git a/overviews/macros/blackbox-whitebox.md b/overviews/macros/blackbox-whitebox.md index 235666a599..01688a1067 100644 --- a/overviews/macros/blackbox-whitebox.md +++ b/overviews/macros/blackbox-whitebox.md @@ -7,6 +7,7 @@ disqus: true partof: macros num: 2 outof: 13 +languages: [ko] --- EXPERIMENTAL diff --git a/overviews/macros/bundles.md b/overviews/macros/bundles.md index ebde550c26..540a75b636 100644 --- a/overviews/macros/bundles.md +++ b/overviews/macros/bundles.md @@ -7,7 +7,7 @@ disqus: true partof: macros num: 5 outof: 13 -languages: [ja] +languages: [ko, ja] --- EXPERIMENTAL diff --git a/overviews/macros/changelog211.md b/overviews/macros/changelog211.md index d6d236d77d..9ea9c25654 100644 --- a/overviews/macros/changelog211.md +++ b/overviews/macros/changelog211.md @@ -7,6 +7,7 @@ disqus: true partof: macros num: 13 outof: 13 +languages: [ko] --- EXPERIMENTAL diff --git a/overviews/macros/extractors.md b/overviews/macros/extractors.md index 6fc77c1aeb..46202d5645 100644 --- a/overviews/macros/extractors.md +++ b/overviews/macros/extractors.md @@ -7,6 +7,7 @@ disqus: true partof: macros num: 7 outof: 13 +languages: [ko] --- EXPERIMENTAL diff --git a/overviews/macros/implicits.md b/overviews/macros/implicits.md index e865478915..23f9ace7c9 100644 --- a/overviews/macros/implicits.md +++ b/overviews/macros/implicits.md @@ -7,7 +7,7 @@ disqus: true partof: macros num: 6 outof: 13 -languages: [ja] +languages: [ko, ja] --- EXPERIMENTAL diff --git a/overviews/macros/inference.md b/overviews/macros/inference.md index ad23f49aa3..d023b0243d 100644 --- a/overviews/macros/inference.md +++ b/overviews/macros/inference.md @@ -3,7 +3,7 @@ layout: overview-large title: Inference-Driving Macros disqus: true -languages: [ja] +languages: [ko, ja] --- EXPERIMENTAL diff --git a/overviews/macros/overview.md b/overviews/macros/overview.md index 4445bd2847..0f4b84c75e 100644 --- a/overviews/macros/overview.md +++ b/overviews/macros/overview.md @@ -7,7 +7,7 @@ disqus: true partof: macros num: 3 outof: 13 -languages: [ja] +languages: [ko, ja] --- EXPERIMENTAL diff --git a/overviews/macros/paradise.md b/overviews/macros/paradise.md index 71a4d80cd0..5bda434b47 100644 --- a/overviews/macros/paradise.md +++ b/overviews/macros/paradise.md @@ -7,7 +7,7 @@ disqus: true partof: macros num: 11 outof: 13 -languages: [ja] +languages: [ko, ja] --- NEW diff --git a/overviews/macros/quasiquotes.md b/overviews/macros/quasiquotes.md index 61f7ec9ecc..ba6f9a0ffe 100644 --- a/overviews/macros/quasiquotes.md +++ b/overviews/macros/quasiquotes.md @@ -7,7 +7,7 @@ disqus: true partof: macros num: 4 outof: 13 -languages: [ja] +languages: [ko, ja] --- Quasiquote guide has been moved to [/overviews/quasiquotes/intro.html](/overviews/quasiquotes/intro.html). \ No newline at end of file diff --git a/overviews/macros/roadmap.md b/overviews/macros/roadmap.md index fa779c9f13..c2f3546e14 100644 --- a/overviews/macros/roadmap.md +++ b/overviews/macros/roadmap.md @@ -7,7 +7,7 @@ disqus: true partof: macros num: 12 outof: 13 -languages: [ja] +languages: [ko, ja] --- EXPERIMENTAL diff --git a/overviews/macros/typemacros.md b/overviews/macros/typemacros.md index 49144b180e..9c613091e3 100644 --- a/overviews/macros/typemacros.md +++ b/overviews/macros/typemacros.md @@ -3,7 +3,7 @@ layout: overview-large title: Type Macros disqus: true -languages: [ja] +languages: [ko, ja] --- OBSOLETE diff --git a/overviews/macros/typeproviders.md b/overviews/macros/typeproviders.md index b603de28f2..f1217322a8 100644 --- a/overviews/macros/typeproviders.md +++ b/overviews/macros/typeproviders.md @@ -7,7 +7,7 @@ disqus: true partof: macros num: 8 outof: 13 -languages: [ja] +languages: [ko, ja] --- EXPERIMENTAL diff --git a/overviews/macros/untypedmacros.md b/overviews/macros/untypedmacros.md index 081ee32737..718e05a98f 100644 --- a/overviews/macros/untypedmacros.md +++ b/overviews/macros/untypedmacros.md @@ -3,7 +3,7 @@ layout: overview-large title: Untyped Macros disqus: true -languages: [ja] +languages: [ko, ja] --- OBSOLETE diff --git a/overviews/macros/usecases.md b/overviews/macros/usecases.md index 972c2a26ff..5c420bd38d 100644 --- a/overviews/macros/usecases.md +++ b/overviews/macros/usecases.md @@ -7,7 +7,7 @@ disqus: true partof: macros num: 1 outof: 13 -languages: [ja] +languages: [ko, ja] --- EXPERIMENTAL diff --git a/overviews/parallel-collections/architecture.md b/overviews/parallel-collections/architecture.md index 85de2b052a..d72372a5c0 100644 --- a/overviews/parallel-collections/architecture.md +++ b/overviews/parallel-collections/architecture.md @@ -5,7 +5,7 @@ title: Architecture of the Parallel Collections Library disqus: true partof: parallel-collections -languages: [ja, zh-cn, es] +languages: [ko, ja, zh-cn, es] num: 5 --- diff --git a/overviews/parallel-collections/concrete-parallel-collections.md b/overviews/parallel-collections/concrete-parallel-collections.md index 12bbea3b0d..e857078d83 100644 --- a/overviews/parallel-collections/concrete-parallel-collections.md +++ b/overviews/parallel-collections/concrete-parallel-collections.md @@ -5,7 +5,7 @@ title: Concrete Parallel Collection Classes disqus: true partof: parallel-collections -languages: [ja, zh-cn, es] +languages: [ko, ja, zh-cn, es] num: 2 --- diff --git a/overviews/parallel-collections/configuration.md b/overviews/parallel-collections/configuration.md index 2570d8bcda..b7f77be8ed 100644 --- a/overviews/parallel-collections/configuration.md +++ b/overviews/parallel-collections/configuration.md @@ -5,7 +5,7 @@ title: Configuring Parallel Collections disqus: true partof: parallel-collections -languages: [ja, zh-cn, es] +languages: [ko, ja, zh-cn, es] num: 7 --- diff --git a/overviews/parallel-collections/conversions.md b/overviews/parallel-collections/conversions.md index 5b1303355f..69ce43b99c 100644 --- a/overviews/parallel-collections/conversions.md +++ b/overviews/parallel-collections/conversions.md @@ -5,7 +5,7 @@ title: Parallel Collection Conversions disqus: true partof: parallel-collections -languages: [ja, zh-cn, es] +languages: [ko, ja, zh-cn, es] num: 3 --- diff --git a/overviews/parallel-collections/ctries.md b/overviews/parallel-collections/ctries.md index 46df557d35..5bb7b4d3dd 100644 --- a/overviews/parallel-collections/ctries.md +++ b/overviews/parallel-collections/ctries.md @@ -5,7 +5,7 @@ title: Concurrent Tries disqus: true partof: parallel-collections -languages: [ja, zh-cn, es] +languages: [ko, ja, zh-cn, es] num: 4 --- diff --git a/overviews/parallel-collections/custom-parallel-collections.md b/overviews/parallel-collections/custom-parallel-collections.md index 528b5a8c3f..1870fae48d 100644 --- a/overviews/parallel-collections/custom-parallel-collections.md +++ b/overviews/parallel-collections/custom-parallel-collections.md @@ -5,7 +5,7 @@ title: Creating Custom Parallel Collections disqus: true partof: parallel-collections -languages: [ja, zh-cn, es] +languages: [ko, ja, zh-cn, es] num: 6 --- diff --git a/overviews/parallel-collections/overview.md b/overviews/parallel-collections/overview.md index 90b69e187b..6b4a4f090c 100644 --- a/overviews/parallel-collections/overview.md +++ b/overviews/parallel-collections/overview.md @@ -5,7 +5,7 @@ title: Overview disqus: true partof: parallel-collections -languages: [ja, zh-cn, es] +languages: [ko, ja, zh-cn, es] num: 1 --- diff --git a/overviews/parallel-collections/performance.md b/overviews/parallel-collections/performance.md index abfb4c0e0b..4ad114a60d 100644 --- a/overviews/parallel-collections/performance.md +++ b/overviews/parallel-collections/performance.md @@ -7,7 +7,7 @@ disqus: true partof: parallel-collections num: 8 outof: 8 -languages: [ja, zh-cn, es] +languages: [ko, ja, zh-cn, es] --- ## Performance on the JVM diff --git a/overviews/quasiquotes/definition-details.md b/overviews/quasiquotes/definition-details.md index 6013fc79f9..9ca368e7f6 100644 --- a/overviews/quasiquotes/definition-details.md +++ b/overviews/quasiquotes/definition-details.md @@ -7,6 +7,7 @@ disqus: true partof: quasiquotes num: 11 outof: 13 +languages: [ko] --- **Denys Shabalin** EXPERIMENTAL diff --git a/overviews/quasiquotes/expression-details.md b/overviews/quasiquotes/expression-details.md index 015ad1fa44..65696d291b 100644 --- a/overviews/quasiquotes/expression-details.md +++ b/overviews/quasiquotes/expression-details.md @@ -7,6 +7,7 @@ disqus: true partof: quasiquotes num: 8 outof: 13 +languages: [ko] --- **Denys Shabalin** EXPERIMENTAL diff --git a/overviews/quasiquotes/future.md b/overviews/quasiquotes/future.md index e0f3822fd5..b70d452a71 100644 --- a/overviews/quasiquotes/future.md +++ b/overviews/quasiquotes/future.md @@ -7,6 +7,7 @@ disqus: true partof: quasiquotes num: 13 outof: 13 +languages: [ko] --- **Denys Shabalin** EXPERIMENTAL diff --git a/overviews/quasiquotes/hygiene.md b/overviews/quasiquotes/hygiene.md index a232314d65..10f7e7934c 100644 --- a/overviews/quasiquotes/hygiene.md +++ b/overviews/quasiquotes/hygiene.md @@ -7,6 +7,7 @@ disqus: true partof: quasiquotes num: 5 outof: 13 +languages: [ko] --- **Denys Shabalin, Eugene Burmako** EXPERIMENTAL diff --git a/overviews/quasiquotes/intro.md b/overviews/quasiquotes/intro.md index 0d131c753f..90144ad131 100644 --- a/overviews/quasiquotes/intro.md +++ b/overviews/quasiquotes/intro.md @@ -7,6 +7,7 @@ disqus: true partof: quasiquotes num: 2 outof: 13 +languages: [ko] --- **Denys Shabalin** EXPERIMENTAL diff --git a/overviews/quasiquotes/lifting.md b/overviews/quasiquotes/lifting.md index ec603f0fa4..fa8cfafb03 100644 --- a/overviews/quasiquotes/lifting.md +++ b/overviews/quasiquotes/lifting.md @@ -7,6 +7,7 @@ disqus: true partof: quasiquotes num: 3 outof: 13 +languages: [ko] --- **Denys Shabalin** EXPERIMENTAL diff --git a/overviews/quasiquotes/pattern-details.md b/overviews/quasiquotes/pattern-details.md index 5647dec8e2..ee8502b6a2 100644 --- a/overviews/quasiquotes/pattern-details.md +++ b/overviews/quasiquotes/pattern-details.md @@ -7,6 +7,7 @@ disqus: true partof: quasiquotes num: 10 outof: 13 +languages: [ko] --- **Denys Shabalin** EXPERIMENTAL diff --git a/overviews/quasiquotes/setup.md b/overviews/quasiquotes/setup.md index e4845e6cb6..37d1f4b7eb 100644 --- a/overviews/quasiquotes/setup.md +++ b/overviews/quasiquotes/setup.md @@ -7,6 +7,7 @@ disqus: true partof: quasiquotes num: 1 outof: 13 +languages: [ko] --- ## Scala 2.11 diff --git a/overviews/quasiquotes/syntax-summary.md b/overviews/quasiquotes/syntax-summary.md index ef7973c1ad..7c4856465f 100644 --- a/overviews/quasiquotes/syntax-summary.md +++ b/overviews/quasiquotes/syntax-summary.md @@ -7,6 +7,7 @@ disqus: true partof: quasiquotes num: 7 outof: 13 +languages: [ko] --- **Denys Shabalin** EXPERIMENTAL diff --git a/overviews/quasiquotes/terminology.md b/overviews/quasiquotes/terminology.md index 96c5a77bef..90a16ee3c2 100644 --- a/overviews/quasiquotes/terminology.md +++ b/overviews/quasiquotes/terminology.md @@ -7,6 +7,7 @@ disqus: true partof: quasiquotes num: 12 outof: 13 +languages: [ko] --- EXPERIMENTAL diff --git a/overviews/quasiquotes/type-details.md b/overviews/quasiquotes/type-details.md index 2c06f13059..9778ae9fa5 100644 --- a/overviews/quasiquotes/type-details.md +++ b/overviews/quasiquotes/type-details.md @@ -7,6 +7,7 @@ disqus: true partof: quasiquotes num: 9 outof: 13 +languages: [ko] --- **Denys Shabalin** EXPERIMENTAL diff --git a/overviews/quasiquotes/unlifting.md b/overviews/quasiquotes/unlifting.md index 1bb03df9d4..d510903abb 100644 --- a/overviews/quasiquotes/unlifting.md +++ b/overviews/quasiquotes/unlifting.md @@ -7,6 +7,7 @@ disqus: true partof: quasiquotes num: 4 outof: 13 +languages: [ko] --- **Denys Shabalin** EXPERIMENTAL diff --git a/overviews/quasiquotes/usecases.md b/overviews/quasiquotes/usecases.md index ea398ce88f..cd8b88c81e 100644 --- a/overviews/quasiquotes/usecases.md +++ b/overviews/quasiquotes/usecases.md @@ -7,6 +7,7 @@ disqus: true partof: quasiquotes num: 6 outof: 13 +languages: [ko] --- **Denys Shabalin** EXPERIMENTAL diff --git a/overviews/reflection/annotations-names-scopes.md b/overviews/reflection/annotations-names-scopes.md index 1531ea4a5c..fc222f22c9 100644 --- a/overviews/reflection/annotations-names-scopes.md +++ b/overviews/reflection/annotations-names-scopes.md @@ -7,7 +7,7 @@ disqus: true partof: reflection num: 4 outof: 7 -languages: [ja] +languages: [ko, ja] --- EXPERIMENTAL diff --git a/overviews/reflection/changelog211.md b/overviews/reflection/changelog211.md index 831acb168f..9b8020eb55 100644 --- a/overviews/reflection/changelog211.md +++ b/overviews/reflection/changelog211.md @@ -5,6 +5,7 @@ title: Changes in Scala 2.11 partof: reflection num: 7 outof: 7 +languages: [ko] --- EXPERIMENTAL diff --git a/overviews/reflection/environment-universes-mirrors.md b/overviews/reflection/environment-universes-mirrors.md index 8c95e856ed..6ea9f0e9ed 100644 --- a/overviews/reflection/environment-universes-mirrors.md +++ b/overviews/reflection/environment-universes-mirrors.md @@ -7,7 +7,7 @@ disqus: true partof: reflection num: 2 outof: 7 -languages: [ja] +languages: [ko, ja] --- EXPERIMENTAL diff --git a/overviews/reflection/overview.md b/overviews/reflection/overview.md index e26b180c9d..c1d33084e6 100644 --- a/overviews/reflection/overview.md +++ b/overviews/reflection/overview.md @@ -5,7 +5,7 @@ title: Overview partof: reflection num: 1 outof: 7 -languages: [ja] +languages: [ko, ja] --- EXPERIMENTAL diff --git a/overviews/reflection/symbols-trees-types.md b/overviews/reflection/symbols-trees-types.md index 3d8d32c995..e88c9e8077 100644 --- a/overviews/reflection/symbols-trees-types.md +++ b/overviews/reflection/symbols-trees-types.md @@ -7,7 +7,7 @@ disqus: true partof: reflection num: 3 outof: 7 -languages: [ja] +languages: [ko, ja] --- EXPERIMENTAL diff --git a/overviews/reflection/thread-safety.md b/overviews/reflection/thread-safety.md index 69e43926c0..a5cbb84f54 100644 --- a/overviews/reflection/thread-safety.md +++ b/overviews/reflection/thread-safety.md @@ -7,7 +7,7 @@ disqus: true partof: reflection num: 6 outof: 7 -languages: [ja] +languages: [ko, ja] --- EXPERIMENTAL diff --git a/overviews/reflection/typetags-manifests.md b/overviews/reflection/typetags-manifests.md index 621e736bf1..225cc0071f 100644 --- a/overviews/reflection/typetags-manifests.md +++ b/overviews/reflection/typetags-manifests.md @@ -7,7 +7,7 @@ disqus: true partof: reflection num: 5 outof: 7 -languages: [ja] +languages: [ko, ja] --- As with other JVM languages, Scala’s types are erased at compile time. This diff --git a/overviews/repl/overview.md b/overviews/repl/overview.md index 27daefa4dd..c9532726c8 100644 --- a/overviews/repl/overview.md +++ b/overviews/repl/overview.md @@ -7,6 +7,7 @@ disqus: true partof: repl num: 1 outof: 1 +languages: [ko] --- The Scala REPL is a tool (_scala_) for evaluating expressions in Scala. diff --git a/overviews/scaladoc/for-library-authors.md b/overviews/scaladoc/for-library-authors.md index 6cd191054b..4f0d169ca0 100644 --- a/overviews/scaladoc/for-library-authors.md +++ b/overviews/scaladoc/for-library-authors.md @@ -7,6 +7,7 @@ disqus: true partof: scaladoc num: 2 outof: 3 +languages: [ko] --- Scaladoc is a documentation system that lives in the comments of Scala source code diff --git a/overviews/scaladoc/interface.md b/overviews/scaladoc/interface.md index 4c9afb800e..9a092d8285 100644 --- a/overviews/scaladoc/interface.md +++ b/overviews/scaladoc/interface.md @@ -7,6 +7,7 @@ disqus: true partof: scaladoc num: 3 outof: 3 +languages: [ko] --- Many Scala developers, including those with a great deal of experience, are diff --git a/overviews/scaladoc/overview.md b/overviews/scaladoc/overview.md index dc816bd54a..187f843ce6 100644 --- a/overviews/scaladoc/overview.md +++ b/overviews/scaladoc/overview.md @@ -7,6 +7,7 @@ disqus: true partof: scaladoc num: 1 outof: 3 +languages: [ko] --- Scaladoc is Scala's main documentation _tool_. Scaladoc is a documentation