4์ฃผ์ฐจ (16 ~ 20 Chapter)
Chapter 16 ๋ฆฌ์คํธ
์ค์นผ๋ผ ํ๋ก๊ทธ๋จ์์ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ์๋ง ๋ฆฌ์คํธ์ด๋ค.
๋ฆฌ์คํธ๋ฅผ ์ฌ์ฉํ๋๋ฐ ์ค์ํ ์ค๊ณ ์์น์ ์์๋ณด์.
16.1 ๋ฆฌ์คํธ ๋ฆฌํฐ๋ด
val fruit = List("apples", "oranges", "pears")
val nums = List(1, 2, 3, 4)
val diag3 = List(
List(1, 0, 1),
List(0, 1, 0),
List(1, 0, 1)
)
val empty = List()
๋ฆฌ์คํธ๋ ๋ฐฐ์ด๊ณผ ๋น์ทํ์ง๋ง ๋ค์ ๋๊ฐ์ง ์ฐจ์ด์ ์ด ์๋ค.
- ๋ฆฌ์คํธ๋ ๋ณ๊ฒฝ์ด ๋ถ๊ฐ๋ฅํ๋ค.
- ๋ฆฌ์คํธ๋ ์ฌ๊ท์ (Linked List) ์ด๊ณ ๋ฐฐ์ด์ ํ๋ฉด์ ์ด๋ค.
16.2 ๋ฆฌ์คํธ ํ์
๋ฆฌ์คํธ๋ ๋ชจ๋ ๋์ข (homogeneous) ์์๋ก ์ด๋ฃจ์ด ์ง๋ค.
๋ฆฌ์คํธ ํ์
์ ๊ณต๋ณ์ ํน์ฑ์ ๋ฐ๋ฅธ๋ค. (S
๊ฐ T
์ ์๋ธํ์
์ด๋ฉด List[S]
๋ List[T]
์ ์๋ธํ์
์ด๋ค.)
Nothing
์ ๋ชจ๋ ํ์
์ ์๋ธ ํ์
์ด๊ธฐ ๋๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ ๋ง์กฑํ๋ค.
val xs: List[String] = List()
16.3 ๋ฆฌ์คํธ ์์ฑ
๋ชจ๋ ๋ฆฌ์คํธ๋ ๋น๋ฉ ๋ธ๋ก์ธ Nil
๊ณผ ::
(์ฝ์ฆ: cons) ๋ ๊ฐ์ง๋ก ๋ง๋ค์ ์๋ค.
List("apples", "oranges", "pears")
val fruit = "apples" :: ("oranges" :: ( "pears" :: Nil ))
16.4 ๋ฆฌ์คํธ ๊ธฐ๋ณธ ์ฐ์ฐ
๋ฆฌ์คํธ์ ๋ชจ๋ ์ฐ์ฐ์ ๋ค์ ์ธ๊ฐ์ง๋ฅผ ๊ฐ์ง๊ณ ํํํ ์ ์๋ค.
- head : ์ด๋ค ๋ฆฌ์คํธ์ ์ฒซ๋ฒ์งธ ์์๋ฅผ ๋ฐํํ๋ค.
- tail : ์ด๋ค ๋ฆฌ์คํธ์ ์ฒซ๋ฒ์งธ ์์๋ฅผ ์ ์ธํ ๋๋จธ์ง ์์๋ก ์ด๋ฃจ์ด์ง ๋ฆฌ์คํธ
- isEmpty : ๋ฆฌ์คํธ๊ฐ ๋น์ด์๋ค๋ฉด
true
๋ฅผ ๋ฐํํ๋ค.
head ์ tail ์ ๋ฆฌ์คํธ๊ฐ ๋น์ด์์ง ์๋ ๊ฒฝ์ฐ์์๋ง ๊ฐ๋ฅํ๋ค.
16.5 ๋ฆฌ์คํธ ํจํด
๋ค์์ ์ฝ์ ์ ๋ ฌ์ ํจํด๋งค์น๋ฅผ ์ด์ฉํ ์ฝ๋์ด๋ค.
def isort(xs: List[Int]): List[Int] = xs match {
case List() => List()
case x :: xs1 => insert(x, isort(xs1))
}
def insert(x: Int, xs: List[Int]): List[Int] = xs match {
case List() => List(x)
case y :: ys => if (x <= y) x :: xs
else y :: insert(x, ys)
}
16.6 List ํด๋์ค์ 1์ฐจ ๋ฉ์๋
์ด๋ค ๋ฉ์๋๊ฐ ํจ์๋ฅผ ์ธ์๋ก ๋ฐ์ง ์๋๋ค๋ฉด, ๊ทธ ๋ฉ์๋๋ฅผ 1์ฐจ ๋ฉ์๋ (first-order method) ๋ผ๊ณ ๋ถ๋ฅธ๋ค.
๋ ๋ฆฌ์คํธ ์ฐ๊ฒฐํ๊ธฐ
List(1, 2) ::: List(3, 4, 5)
// List(1, 2, 3, 4, 5)
List(1, 2, 3) ::: List
// List(1, 2, 3, 4)
๋ถํ ์ ๋ณต ์์น
์ฐ๊ฒฐ (:::
) ์ List
ํด๋์ค ์์ ๊ตฌํ๋์ด ์๋ ๋ฉ์๋์ด๋ค.
ํ์ง๋ง ๋ฆฌ์คํธ์ ํจํด ๋งค์น๋ฅผ ์ฌ์ฉํด :::
๋ฅผ ์ง์ ๊ตฌํํ ์๋ ์๋ค.
def append[T](xs: List[T], ys: List[T]): List[T]
def append[T](xs: List[T], ys: List[T]): List[T] =
xs match {
case List() => ys
case x :: xs1 => x :: append(xs1, ys)
}
๋ฆฌ์คํธ ๊ธธ์ด ๊ตฌํ๊ธฐ: length
length
๋ฉ์๋๋ ๋ฆฌ์คํธ์ ๊ธธ์ด๋ฅผ ๊ณ์ฐํ๋ค.
List(1, 2, 3).length
// 3
๋ฐฐ์ด๊ณผ ๊ฐ๋ฆฌ ๋ฆฌ์คํธ์ length
๋ ๋น๊ต์ ๋น์ผ ์ฐ์ฐ์ด๋ค.
๋ฆฌ์คํธ์ ๋์ ์ฐพ๊ธฐ ์ํด ์ ์ฒด ๋ฆฌ์คํธ๋ฅผ ์ํํด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
๋๋ฌธ์ xs.isEmpty
์ ๊ฒ์ฌ๋ฅผ xs.length == 0
์ผ๋ก ๋ฐ๊พผ ๋ฐฉ์์ ์ข์ ๋ฐฉ์์ด ์๋๋ค
๋ ๊ฒ์ฌ์ ๊ฒฐ๊ณผ๋ ๊ฐ์ง๋ง ๋ชจ๋ ๋ฆฌ์คํธ๋ฅผ ์ํํด์ผ ํ๋ค๋ ์ ์์ xs.length == 0
์ ๋๋ฆฌ๋ค.
๋ฆฌ์คํธ์ ์ ๋์ ์ ๊ทผํ๊ธฐ
- head : ์ฒซ๋ฒ์งธ ์์๋ฅผ ๋ฐํ
- tail : ์ฒซ๋ฒ์งธ ์์๋ฅผ ์ ์ธํ ๋ชจ๋ ์์๋ฅผ ํฌํจํ ๋ฆฌ์คํธ๋ฅผ ๋ฐํ
- init : ๋ง์ง๋ง ์์๋ฅผ ์ ์ธํ ๋ชจ๋ ์์๋ฅผ ํฌํจํ ๋ฆฌ์คํธ๋ฅผ ๋ฐํ
- last : ๋ง์ง๋ง ์์ ๋ฐํ
val abcde = List('a', 'b', 'c', 'd', 'e')
abcde.head
// List(a)
abcde.tail
// List(b, c, d, e)
abcde.init
// List(a, b, c, d)
abcde.last
// List(e)
์ด ๋์ ์๋์ฑ (๊ฑฐ์ธ์ฐ์ฐ) ์ด๋ค.
๋ฆฌ์คํธ ๋ค์ง๊ธฐ: reverse
abcde.reverse
// List(e, d, c, b, a)
reverse
๋ ๊ฐ์ ๋ณ๊ฒฝํ๋ค๊ธฐ ๋ณด๋ค๋ ์๋ก์ด ๋ฆฌ์คํธ๋ฅผ ์์ฑํ๋ค.
reverse, init, last ์ฐ์ฐ์ ๋ค์ ๋ฒ์น์ ๋ง์กฑํ๋ค.
- reverse ๋ ์๊ธฐ์์ ์ ์ญ์ด๋ค.
- xs.reverse.reverse ๋ xs ์ ๊ฐ๋ค.
- ์์์ ๋ฐฉํฅ์ด ๋ค์งํ๋ค๋ ์ ์ ์ ์ธํ๋ฉด reverse ๋ init ์ tail ๋ก ๋ฐ๊พธ๊ณ last ๋ฅผ head ๋ก ๋ฐ๊พผ๋ค.
- xs.reverse.init ๋ xs.tail.reverse ์ ๊ฐ๋ค.
- xs.reverse.tail ์ xs.init.reverse ์ ๊ฐ๋ค.
- xs.reverse.head ๋ xs.last ์ ๊ฐ๋ค.
- xs.reverse.last ๋ xs.head ์ ๊ฐ๋ค.
:::
์ ์ด์ฉํ์ฌ reverse ๋ฅผ ๊ตฌํํ ์ ์๋ค.
def rev[T](xs: List[T]): List[T] = xs match {
case List() => xs
case x :: xs1 => rev(xs1) ::: List(x)
}
์ด rev
๋ฉ์๋๋ ๋ง์กฑ์ค๋ฌ์ด ์ฑ๋ฅ์ ๋ด์ง ๋ชปํ๋ค. (์๊ฐ๋ณต์ก๋๋ On^2)
์ ๋์ฌ์ ์ ๋ฏธ์ฌ: drop, take, splitAt
- drop: ์ฒซ๋ฒ์งธ์์ n ๋ฒ์งธ ์์๋ฅผ ์ ์ธํ xs ๋ฆฌ์คํธ๋ฅผ ๋ฐํ
- take: ์ฒซ๋ฒ์งธ์์ n ๋ฒ์งธ ์์๋ฅผ ๋ฐํ
- splitAt: ์ฃผ์ด์ง ์ธ๋ฑ์ค์์ ๋ฆฌ์คํธ๋ฅผ ๋ถํ ํด์ ๋ ๋ฆฌ์คํธ๋ฅผ ๋ฐํ
val abcde = List('a', 'b', 'c', 'd', 'e')
abcde drop 2
// List(c, d, e)
abcde take 2
// List(a, b)
abcde splitAt 2
// (List(a, b), List(c, d, e))
์์ ์ ํํ๊ธฐ: apply, indices
abcde apply 2
// c
abcde(2)
// c
์์์ ์์๋ฅผ ์ ํํ๋ apply
๋ ์ธ๋ฑ์ค n ์ ๊ฐ์ ๋น๋กํด์ ์๊ฐ์ด ๊ฑธ๋ฆฐ๋ค.
indices
๋ ์ ํจํ ์ธ๋ฑ์ค๋ฅผ ๋ฐํํ๋ค.
abcde.indices
// Range(0, 1, 2, 3, 4)
kotlin ์์ for loop
์ฌ์ฉํ ๋์ ์ ์ฌ
๋ฆฌ์คํธ์ ๋ฆฌ์คํธ๋ฅผ ํ ๋ฆฌ์คํธ๋ก ๋ฐ๋ฏํ๊ฒ ๋ง๋ค๊ธฐ: flatten
flatten
๋ฉ์๋๋ ๋ฆฌ์คํธ์ ๋ฆฌ์คํธ๋ฅผ ์ธ์๋ก ๋ฐ์ ํ๋์ ๋ฆฌ์คํธ๋ก ๋ฐ๋ฏํ๊ฒ ํผ์น๋ค.
List(List(1, 2), List(3), List(), List(4, 5)).flatten
// List(1, 2, 3, 4, 5)
์ด ๋ฉ์๋๋ ๋ฆฌ์คํธ์ ๋ชจ๋ ์์๊ฐ ๋ฆฌ์คํธ์ผ๋๋ง ์ ์ฉ ๊ฐ๋ฅํ๋ค.
๋ ๋ฆฌ์คํธ๋ฅผ ์์์ธ์ผ๋ก ๋ฌถ๊ธฐ: zip, unzip
zip
์ฐ์ฐ์ ๋ ๋ฆฌ์คํธ๋ฅผ ์ด์๋ก ๋ฐ์ ์์์์ ๋ฆฌ์คํธ๋ก ๋ง๋ ๋ค.
val zipped = abcde zip List(1, 2, 3, 4)
// List((a,1), (b,2), (c,3), (d, 4))
๋ฆฌ์คํธ์ ๊ธธ์ด๊ฐ ๋ค๋ฅด๋ฉด ๊ธธ์ด๊ฐ ๊ธด์ชฝ์ ๋จ๋ ์์๊ฐ ๋ฒ๋ ค์ง๋ค.
unzip
์ ๋น์ฐํ ๋ฐ๋์ด๋ค.
zipped.unzip
// (List(a, b, c),List(1, 2, 3))
zipWithIndex
๋ ์์์ ๊ทธ ์ธ๋ฑ์ค๋ฅผ ์์์์ผ๋ก ๋ฌถ๋๋ค.
abcde.zipWithIndex
// List((a,0), (b,1), (c,2), (d,3), (e,4))
๋ฆฌ์คํธ ์ถ๋ ฅํ๊ธฐ: toString, mkString
toString
์ ๋ฆฌ์คํธ์ ํ์ค ๋ฌธ์์ด์ ๋ฐํํ๋ค.
abcde.toString()
// List(a, b, c, d, e)
mkString
์ xs mkString (pre, sep, post)
์ผ๋ก ์ฌ์ฉํ๋ฉฐ
pre + xs(0) + sep + ... + sep + xs + post
์ผ๋ก ๊ตฌ์ฑ๋๋ค.
๋ฆฌ์คํธ ๋ณํํ๊ธฐ: iterator, toArray, copyToArray
iterator
๋ ์์๋ฅผ ์ํํ๋๋ก ๋์์ค๋ค.
val it = abcde.iterator
// it: Iterator[Char] = <iterator>
it.next
// a
it.next
// b
copyToArray
๋ ๋ฆฌ์คํธ์ ์์๋ฅผ ์ด๋ค ๋ฐฐ์ด์ ํน์ ์ง์ ์ผ๋ก ๋ถํฐ ์ฐ์์ ์ผ๋ก ๋ณต์ฌํ๋ค.
val arr2 = new Array[Int](10)
// Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
List(1, 2, 3) copyToArray (arr2, 3)
// Array(0, 0, 0, 1, 2, 3, 0, 0, 0, 0)
์์ : ๋ณํฉ์ ๋ ฌ
์์ ์ฝ๋ ์ฐธ๊ณ
16.7 List ํด๋์ค์ ๊ณ ์ฐจ ๋ฉ์๋
๋ฆฌ์คํธ ๋งคํ: map, flatmap, foreach
xs map f
์ฐ์ฐ์ List[T]
ํ์
์ธ xs
์ T => U
ํ์
์ธ f
ํจ์๋ฅผ ๋ฐ๋๋ค.
List(1, 2, 3) map (_ + 1)
// List(2, 3, 4)
val words = List("the", "quick", "brown", "fox")
words map (_.length)
// List(3, 5, 5, 3)
flatmap
์ฐ์ฐ์๋ map
๊ณผ ์ ์ฌํ์ง๋ง ๋ชจ๋ ๋ฆฌ์คํธ๋ฅผ ์ฐ๊ฒฐํ ๋จ์ผ ๋ฆฌ์คํธ๋ก ๋ฐํํ๋ค.
words map (_.toList)
// List(List(t, h, e), List(q, u, i,c, k), List(b, r, o, w, n), List(f, o, x))
words flatMap (_.toList)
// List(t, h, e, q, u, i, c, k, b, r, o, w, n, f, o, x)
foreach
๋ ์ค๋ฅธ์ชฝ ํผ์ฐ์ฐ์๋ก ํ๋ก์์ ธ๋ฅผ ๋ฐ๋๋ค.
var sum = 0
List(1, 2, 3, 4, 5) foreach (sum += _)
// sum = 15
foreach
๊ฒฐ๊ณผ๋ Unit
์ด๋ค.
๋ฆฌ์คํธ ๊ฑธ๋ฌ๋ด๊ธฐ: filter, partition, find, takeWhile, dropWhile, span
- filter:
T => Boolean
ํ์ ์ ์ ์ด๋ฅผ ๋ฐ์ ์กฐ๊ฑด์ ๋ง์กฑํ๋ ์์๋ฅผ ๋ฐํ - find:
T => Boolean
๋ฅผ ๋ง์กฑํ๋ ์ฒซ๋ฒ์งธ ์์๋ง ๋ฐํ - takeWhile:
T => Boolean
๋ฅผ ๋ง์กฑํ๋ ๊ฐ์ฅ ๊ธด ์ ๋์ฌ๋ฅผ ๋ฐํ - dropWhile:
T => Boolean
๋ฅผ ๋ง์กฑํ๋ ๊ฐ์ฅ ๊ธด ์ ๋์ฌ๋ฅผ ์ ๊ฑฐ
List(1, 2, 3, -4, 5) takeWhile (_ > 0)
// List(1, 2, 3)
List(1, 2, 3, -4, 5) dropWhile (_ > 0)
// List(-4,5)
๋ฆฌ์คํธ ์ ์ฒด์ ๋ํ ์ ์ด: forall, exists
xs forall p
: ๋ฆฌ์คํธ์ ๋ชจ๋ ์์๊ฐ ๋ง์กฑํ ๋true
๋ฐํxs exists p
: ๋ฆฌ์คํธ์ ์์์ค์ ์ ์ด (p
) ๋ฅผ ํ๋๋ผ๋ ๋ง์กฑํ๋ฉดtrue
๋ฅผ ๋ฐํ
๋ฆฌ์คํธ ํด๋: foldLeft ์ foldRight
sum(List(a, b, c))
๋ 0 + a + b + c
์ ๊ฐ๋ค.
def sum(xs: List[Int]): Int = xs.foldLeft(0)(_ + _)
์ผ์ชฝ ํด๋ (foldLeft) ์ฐ์ฐ์ xs.foldLeft(z)(op)
์ ๋ํด ์์๊ฐ z
, ํด๋ํ ๋์ xs
์ ๋ํด ์ดํญ ์ฐ์ฐ์ธ op
๋ฅผ ์ ์ฉํ๋ค.
words.foldLeft("")(_ + " " + _)
// " the quick brown fox"
์์ ๊ฐ์ด ๋งจ ์์ ๊ณต๋ฐฑ์ ์ ๊ฑฐํ๊ธฐ ์ํด ๋ค์๊ณผ ๊ฐ์ด ๋ณํํ ํํ๋ฅผ ์ฌ์ฉํ๋ค.
words.tail.foldLeft("")(_ + " " + _)
// the quick brown fox
์ผ์ชฝ ํด๋์ ๋ฐ๋๋๋ ๋ฉ์๋๊ฐ ์ค๋ฅธ์ชฝ ํด๋ (foldRight) ์ด๋ค
์: ํด๋๋ฅผ ์ฌ์ฉํด ๋ฆฌ์คํธ ๋ค์ง๊ธฐ
์์ ์ฐธ๊ณ
๋ฆฌ์คํธ ์ ๋ ฌ: sortWith
List(1, -3, 4, 2, 6) sortWith (_ < _)
// List(-3, 1, 2, 4, 6)
word sortWith (_.length > _.length)
// List(quick, brown, the, fox)
16.8 List ๊ฐ์ฒด์ ๋ฉ์๋
์์๋ก๋ถํฐ ๋ฆฌ์คํธ ๋ง๋ค๊ธฐ
List.apply(1, 2, 3)
// List(1, 2, 3)
์์ ๋ฒ์๋ฅผ ๋ฆฌ์คํธ๋ก ๋ง๋ค๊ธฐ: List.range
List.range(form, unitl)
์ด๋ฉฐ unitl
์ ๋ฒ์์ ๋ค์ด๊ฐ์ง ์๋๋ค.
List.range(1, 5)
// List(1, 2, 3, 4)
์ธ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ๋ค์๊ณผ ๊ฐ์ด ์ฆ๊ฐ์น๋ฅผ ๊ฐ๋ range
๋ฒ์ ๋ ์๋ค.
List.range(1, 9, 2)
// List(1, 3, 5, 7)
List.range(9, 1, -3)
// List(9, 6, 3)
๊ท ์ผํ ๋ฆฌ์คํธ ๋ง๋ค๊ธฐ: List.fill
์์ฑํ ๋ฆฌ์คํธ์ ๊ธธ์ด๋ฅผ ๋ฐ์ ๋ค์ ๋ฐ๋ณตํ ์์๋ฅผ ๋ฐ๋๋ค.
List.fill(5)('a')
// List(a, a, a, a, a)
fill ์ ์ธ์๋ฅผ 2๊ฐ๋ณด๋ค ๋ง์ด ์ ๋ฌํ๋ฉด ๋ค์ฐจ์ ๋ฆฌ์คํธ๋ฅผ ์์ฑํ๋ค.
List.fill(2, 3)('b')
List(List(b, b, b), List(b, b))
ํจ์ ๋ํํ: List.tabulate
์ ๊ณต๋ ํจ์๋ก ๊ณ์ฐ๋ ๋ฆฌ์คํธ๋ฅผ ์์ฑํ๋ค.
List.tabulate(5)(n => n * n)
List(0, 1, 4, 9, 16)
์ฌ๋ฌ ๋ฆฌ์คํธ ์ฐ๊ฒฐํ๊ธฐ
List.concat(List('a', 'b'), List('c'))
// List(a, b, c)
List.concat(List(), List('b'), List('c'))
// List(b, c)
16.9 ์ฌ๋ฌ ๋ฆฌ์คํธ๋ฅผ ํจ๊ป ์ฒ๋ฆฌํ๊ธฐ
zip
์ ์์์ ๋ด์๋ฏ์ด ์์์ ์ฐ์ฐ์ ํ๋ค.
ํ์ง๋ง zip
์ด ํธ์ถ๋ ์งํ ์ค๊ฐ ๋ฆฌ์คํธ๋ฅผ ์์๋ก ๋ง๋ค์ด๋ด๊ธฐ ๋๋ฌธ์ ์์ฑ๋น์ฉ์ด ๋ค์ด๊ฐ๋ค.
๋๋ฌธ์ lazyzip
์ ์ ๊ณตํ๋ค.
(List(10, 20) lazyZip List(3, 4, 5)).map(_ * _)
// List(30, 80)
ํ์ง๋ง ์ด๋ฆ์์ ์ ์ ์๋ฏ์ด ์ปฌ๋ ์ ์ ๋ฐ๋ก ๋๋ ค์ฃผ์ง ์๋๋ค.
exists
์ forall
๋ ์ง์ฐ ์ฐ์ฐ์ ํด๋นํ๋ ๋ฒ์ ์ด ์๋ค.
16.10 ์ค์นผ๋ผ์ ํ์ ์ถ๋ก ์๊ณ ๋ฆฌ์ฆ ์ดํด
msort((x: Char, y: Char) => x > y)(abcde)
// List(e, d, c, b, a)
abcde sortWith (_ > _)
// List(e, d, c, b, a)
์ ๋ ์ฝ๋๋ ๊ฐ์ ๋์์ ์ํํ๋ค.
ํ์ง๋ง ๋ค์์ ๊ฒฝ์ฐ์๋ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
msort(_ > _)(abcde)
์ค์นผ๋ผ์์๋ ํ์ ์ถ๋ก ์ด ํ๋ฆ๊ธฐ๋ฐ์ผ๋ก ๋์ํ๋ค.
๋ฉ์๋ ์ ์ฉ์ธ m(args)
์์ ํ์
์ถ๋ก ๋ก์ง์ ๋ฉ์๋ m
ํ์
์ด ์๋์ง ๋จผ์ ๊ฒ์ฌํ๋ค.
๋ง์ฝ m
ํ์
์ด ์๋ค๋ฉด ๋ฉ์๋์ ์ ์ฉํ ์ธ์์ ์์ ํ์
์ ์ถ๋ก ํ๋ค.
ํ์
์ถ๋ก ์ด ์ฒซ ์ธ์์ธ (_ > _)
์ ๊ฒํ ํ ๋ ํจ์ ์ธ์์ ์ ํํ ํ์
์ ์ ์ ์์ด ์คํจํ๋ค.
msort[Char](_ > _)(abcde)
์ด์จ๋ ํ์ ์ธ์๋ ํ์ ํ๊ธฐ๋ฅผ ๋ช ์ํด์ค๋ผ
16.11 ๊ฒฐ๋ก
๋ฆฌ์คํธ๋ฅผ ๋ค๋ฃจ๋ ๋ง์ ๋ฐฉ๋ฒ๋ค์ ์ดํด๋ณด์๋ค.
Chapter 17 ์ปฌ๋์
๊ฐ์ฅ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉํ๋ ์ปฌ๋ ์ ํ์ ๊ณผ ์ฐ์ฐ์ ์ดํด๋ณธ๋ค.
17.1 ์ํ์ค
์ํ์ค (sequence) ํ์ ์ ์์๊ฐ ์ ํด์ง ๋ฐ์ดํฐ ๊ทธ๋ฃน์ ๊ฐ์ง๊ณ ์์ ํ ์ ์๊ฒ ํด์ค๋ค.
๋ฆฌ์คํธ
๋ฆฌ์คํธ๋ ์๋ถ๋ถ์ ๋น ๋ฅด๊ฒ ์์๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์ญ์ ํ ์ ์๋ค.
๋ฆฌ์คํธ๋ฅผ ์์ฐจ์ ์ผ๋ก ๋ฐ๋ผ๊ฐ์ผ ํ๊ธฐ ๋๋ฌธ์ ์์์ ์์น์ ์ ๊ทผํ ๋๋ ๋น ๋ฅด์ง ์๋ค.
๋ถ๋ณ์ฑ์ ์ ์งํ๊ธฐ ๋๋ฌธ์ ํจ์จ์ ์ด๊ณ ์๊ณ ๋ฆฌ์ฆ์ ๊ฐ๋ฐํ ๋ ๋์์ด ๋๋ค.
๋ฐฐ์ด
์์์ ์๋ ์์์ ํจ์จ์ ์ผ๋ก ์ ๊ทผํ๊ฒ ํด์ค๋ค.
๋ฆฌ์คํธ ๋ฒํผ
๋ฆฌ์คํธ์ ์์ชฝ์ ๋ํด์๋ ๋น ๋ฅธ ์ ๊ทผ์ ์ ๊ณตํ์ง๋ง, ๋์ชฝ์์๋ ๊ทธ๋ ์ง ์๋ค.
๋๋ฌธ์ ๋ฆฌ์คํธ์ ๋๋ถ๋ถ์ ์์๋ฅผ ์ถ๊ฐํ๋ฉด์ ๋ฆฌ์คํธ๋ฅผ ์์ฑํ ํ์๊ฐ ์๋ค๋ฉด ๋ฆฌ์คํธ ์์ ์์๋ฅผ ์ฐจ๋ก๋ก ์ถ๊ฐํด ๋ค์งํ ๋ฆฌ์คํธ๋ฅผ ๋ง๋ค๊ณ ๊ทธ๋ฐ ๋ค์ reverse
๋ฅผ ํธ์ถํด ์ํ๋ ์์์ ๋ฆฌ์คํธ๋ฅผ ์ป์ด์ผ ํ๋ค.
import scala.collection.mutable.ListBuffer
val buf = new ListBuffer[Int]
buf += 1
// ListBuffer(1)
buf += 2
// ListBuffer(1, 2)
3 +=: buf
// ListBuffer(3, 1, 2)
๋ฐฐ์ด ๋ฒํผ
๋ ๋ถ๋ถ๊ณผ ์์ ๋ถ๋ถ์ ์์๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์ญ์ ํ ์ ์๋ค๋ ์ ๋ง ์ ์ธํ๋ฉด ๋ฐฐ์ด๊ณผ ๊ฐ๋ค.
๊ตฌํ์ ๊ฐ์ธ์ฃผ๋ ์ธต ๋๋ฌธ์ ์๋๊ฐ ๋ค์ ๋๋ฆฌ๋คํด๋, ๋ฐฐ์ด ๋ฒํผ์ ๋ชจ๋ ๋ฐฐ์ด ์ฐ์ฐ์ ์ฌ์ฉํ ์ ์๋ค.
val buf = new ArrayBuffer[Int]()
buf += 12
// ArrayBuffer(12)
buf += 15
// ArrayBuffer(12, 15)
์์ ๊ฐ์ด +=
๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ArrayBuffer ๋์ ์์๋ฅผ ์ถ๊ฐํ ์ ์๋ค.
๋ฌธ์์ด(StringOps๋ฅผ ํตํด์)
Predef
์ String
์ StringOps
๋ก ๋ฐ๊พธ๋ ์์์ ๋ณํ์ด ์๊ธฐ ๋๋ฌธ์ ์ํ์ค ์ฒ๋ผ ๋ฌธ์์ด์ ๋ค๋ฃฐ์ ์๋ค.
def hasUpperCase(s: String) = s.exists(_.isUpper)
hasUpperCase("Robert Frost")
// true
๋ฌธ์์ด ์์ ๋๋ฌธ์๊ฐ ์์ผ๋ฉด true ๋ฅผ ๋ฐํํ๋ค.
17.2 ์งํฉ๊ณผ ๋งต
Set
์ด๋ Map
์ ๊ธฐ๋ณธ๊ฐ์ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ ๊ฐ์ฒด์ด๋ค.
๋ง์ฝ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ์ถ์ผ๋ฉด ๋ช ์์ ์ผ๋ก ์ํฌํธ ํด์ผ ํ๋ค.
import scala.collection.mutable
์งํฉ์ ์ฌ์ฉ
์งํฉ์ ํน์ง์ ํน์ ๊ฐ์ฒด๋ ์ต๋ ํ๋๋ง ๋ค์ด๊ฐ๋๋ก ๋ณด์ฅํ๋ค๋ ์ ์ด๋ค.
416p ํ 17.1 ์ผ๋ฐ์ ์ธ ์งํฉ์ฐ์ฐ ํ ์ฐธ์กฐ
๋งต์ ์ฌ์ฉ
์ด๋ค ๊ฐ๊ณผ ์งํฉ์ ๊ฐ ์์ ์ฌ์ด์ ์ฐ๊ด ๊ด๊ณ๋ฅผ ๋ง๋ ๋ค.
419p ํ 17.2 ์ผ๋ฐ์ ์ธ ๋งต ์ฐ์ฐ ํ ์ฐธ์กฐ
๋ํดํธ ์งํฉ๊ณผ ๋งต
scala.collection.mutable.Set()
ํฉํ ๋ฆฌ ๋ฉ์๋๋ ๋ด๋ถ์ ์ผ๋ก ํด์ ํ
์ด๋ธ์ ์ฌ์ฉํ๋ scala.collection.mutable.HashSet
์ ๋ฐํํ๋ค.
scala.collection.mutable.Map()
ํฉํ ๋ฆฌ ๋ฉ์๋๋ ๋ง์ฐฌ๊ฐ์ง๋ก scala.collection.mutable.HashMap
์ ๋ฐํํ๋ค.
scala.collection.mutable.Set()
ํฉํ ๋ฆฌ ๋ฉ์๋๋ ํฉํ ๋ฆฌ์ ์ผ๋ง๋ ๋ง์ ์์๋ฅผ ์ ๋ฌํ๋๋์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ค.
์ด๋ ์ฑ๋ฅ์ ๊ทน๋ํ ํ๊ธฐ ์ํด ํน์ ํฌ๊ธฐ์ ์งํจ๋ง์ ๋ด๋นํ๋ ํน๋ณํ ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ค.
์์ ๊ฐ์ | ๊ตฌํ |
---|---|
0 | scala.collection.immutable.EmptySet |
1 | scala.collection.immutable.Set1 |
2 | scala.collection.immutable.Set2 |
3 | scala.collection.immutable.Set3 |
4 | scala.collection.immutable.Set4 |
5 ์ด์ | scala.collection.immutable.HashSet |
๋ง์ฐฌ๊ฐ์ง๋ก scala.collection.immutable.Map()
ํฉํ ๋ฆฌ ๋ฉ์๋๋ ์์๊ฐ 5๊ฐ๋ณด๋ค ์ ์ ๋งต์ ๋ํด์๋ ์ฑ๋ฅ์ ์ต๋ํ ํ๊ธฐ ์ํด ํฌ๊ธฐ๋ณ๋ก ํนํ๋ ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ค.
์์ ๊ฐ์ | ๊ตฌํ |
---|---|
0 | scala.collection.immutable.EmptyMap |
1 | scala.collection.immutable.Map1 |
2 | scala.collection.immutable.Map2 |
3 | scala.collection.immutable.Map3 |
4 | scala.collection.immutable.Map4 |
5 ์ด์ | scala.collection.immutable.HashMap |
์ ๋ ฌ๋ ์งํฉ๊ณผ ๋งต
์ ํด์ง ์์๋๋ก ์์๋ฅผ ๋ฐํํ๋ ์ดํฐ๋ ์ดํฐ๋ฅผ ์ ๊ณตํ๋ ๋งต์ด๋ ์งํฉ์ ์ฌ์ฉํ ๋๋ SortedSet
์ด๋ SortedMap
ํธ๋ ์ดํธ๋ฅผ ์ฌ์ฉํ๋ค.
์ด ๋ ํธ๋ ์ดํธ์ ๊ตฌํ์ TreeSet
๊ณผ TreeMap
ํด๋์ค์ด๋ค.
17.3 ๋ณ๊ฒฝ ๊ฐ๋ฅ ์ปฌ๋ ์ ๊ณผ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅ ์ปฌ๋ ์
๋ณ๊ฒฝ ๊ฐ๋ฅํ ์ปฌ๋ ์ ๊ณผ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ ์ปฌ๋ ์ ์ ์ ํ์ด ์ด๋ ค์ฐ๋ฉด ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ ์ปฌ๋ ์ ์ ์ฐ์ ์ ํ๋ผ
๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ ์ปฌ๋ ์ ์ ํ๋ก๊ทธ๋จ์ ์ถ๋ก ํ๊ธฐ ๋ ์ฌ์ฐ๋ฉฐ, ์ ์ฅํ ์์์ ์๊ฐ ์ ์ ๊ฒฝ์ฐ ๋ ์๊ฒ ์ ์ฅํ ์ ์๋ค.
17.4 ์ปฌ๋ ์ ์ด๊ธฐํ
์ปฌ๋ ์ ์ ์ด๊ธฐํํ๊ณ ์์ฑํ๋ ์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ์ ์ด๊ธฐ ์์๋ฅผ ์ปฌ๋ ์ ๋๋ฐ ๊ฐ์ฒด์ ํฉํ ๋ฆฌ ๋ฉ์๋์ ๋๊ธฐ๋ ๊ฒ์ด๋ค.
๋๋ถ๋ถ์ ๊ฒฝ์ฐ์๋ ์ค์นผ๋ผ ์ปดํ์ผ๋ฌ๊ฐ ๋๋ฐ ๊ฐ์ฒด์ ํฉํ ๋ฆฌ ๋ฉ์๋์ ์ ๋ฌํ ์์๋ก๋ถํฐ ์ปฌ๋ ์ ์์ ํ์ ์ ์ถ๋ก ํ ์ ์๋ค.
ํน๋ณํ ์ํฉ์์๋ ์ด๋ค ์ปฌ๋ ์
์ ๋ค๋ฅธ ์ปฌ๋ ์
์ผ๋ก ์ ํํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๋๋ฐ ์ด๋ด๋๋ to
๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ค๋ฅธ ์ปฌ๋ ์
์ผ๋ก ์ด๊ธฐํ ํ์
val colors = List("blue", "yellow", "red", "green")
val treeSet = color to TreeSet
// TreeSet(blue, green, red, yellow)
๋ฐฐ์ด์ด๋ ๋ฆฌ์คํธ๋ก ๋ฐ๊พธ๊ธฐ
๋ค๋ฅธ ์ปฌ๋ ์
์ ๊ฐ์ง๊ณ ์๋ก์ด ๋ฆฌ์คํธ๋ฅผ ์ด๊ธฐํ ํ๋ ค๋ฉด toList
๋ฅผ ํธ์ถํ์
treeSet.toList
// List(blue, green, red, yellow)
๋ง์ฝ ๋ฐฐ์ด์ ์ํ๋ค๋ฉด toArray
์ ํธ์ถํ์
treeSet.toArray
// Array(blue, green, red, yellow)
๋ณ๊ฒฝ ๊ฐ๋ฅํ ์งํฉ(๋งต)๊ณผ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ ์งํฉ(๋งต) ์ฌ์ด์ ๋ณํ
๋ณ๊ฒฝ ๊ฐ๋ฅํ ์งํฉ์ด๋ ๋งต์ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ ๊ฐ์ฒด๋ก ๋ฐ๊พธ๊ฑฐ๋ ํน์ ๊ทธ ๋ฐ๋์ผ ๊ฒฝ์ฐ to
๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
import scala.collection.mutable
treeSet
// TreeSet(blue, green, red, yellow)
val mutaSet = treeSet to mutable.Set
//Set(yellow, blue, red, green)
val immutaSet = mutaSet to Set
//Set(yellow, blue, red, green)
17.5 ํํ
ํํ (tuple) ์ ์ ํด์ง ๊ฐ์์ ์์๋ฅผ ํ๋ฐ ๋ฌถ๋๋ค.
๋ค์์ ์ ์, ๋ฌธ์์ด, Console ํ์ ์ ์์๊ฐ ์๋ ํํ์ ํ ์์ด๋ค.
(1, "Hello", Console)
ํํ์ ๊ฐ๊ธฐ ๋ค๋ฅธ ํ์ ์ ๊ฐ์ฒด๋ฅผ ๊ฒฐํฉํ ์ ์๊ธฐ ๋๋ฌธ์, Iterable์ ์์ํ์ง ์๋๋ค.
ํํ์ ์ฌ์ฉํ๋ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ๊ฒฝ์ฐ์๋ ๋ฉ์๋์์ ์ฌ๋ฌ ๊ฐ์ ๋ฐํํ๋ ๊ฒ์ด๋ค.
๋ค์์ ๊ฐ์ฅ ๊ธด ๋จ์ด๋ฅผ ์ฐพ๊ณ ๊ทธ ๋จ์ด์ ์ธ๋ฑ์ค๋ฅผ ๋ฐํํ๋ ๋ฉ์๋์ด๋ค.
def longestWord(words: Array[String]): (String, Int) = {
var word = words(0)
var idx = 0
for (i <- 1 until words.length)
if (words(i).length > word.length) {
word = words(i)
idx = i
}
(word, idx)
}
val longset = longestWord("The quick brown fox".split(" "))
// (quick, 1)
longest._1
// quick
longest._2
// 1
val (word, idx) = longest
// word = quick, idx = 1
์์์ ๊ดํธ๋ฅผ ์๋ตํ๋ฉด ๋ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ ๋์จ๋ค.
val word, idx = longest
// word = (quick, 1)
// idx = (quick, 1)
ํํ์ ๋๋ฌด๋ ์ฌ์ฉํ๊ธฐ ์ฝ๊ธฐ ๋๋ฌธ์ 'A ํ๋์ B ํ๋' ์์ค์ ๋์ง ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ฌถ์๋ ์ ์ฉํ๋ค.
๊ฒฐํฉ์ ์ด๋ค ์๋ฏธ๊ฐ ์๊ฑฐ๋ ๊ฒฐํฉ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๊ธฐ๋ฅผ ์ํ๋ค๋ฉด ํด๋์ค๋ฅผ ์์ฑํ๋ ํธ์ด ๋ ์ข๋ค.
17.6 ๊ฒฐ๋ก
์ค์นผ๋ผ ์ปฌ๋ ์ ์ ๋ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋ค.
Chapter 18 ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๊ฐ์ฒด
๋ณ๊ฒฝ ๊ฐ๋ฅํ ๊ฐ์ฒด๊ฐ ๋ฌด์์ธ์ง ์ค๋ช ํ๊ณ , ๊ทธ๋ฐ ๊ฐ์ฒด๋ฅผ ํํํ๋๋ก ์ค์นผ๋ผ๊ฐ ์ ๊ณตํ๋ ๋ฌธ๋ฒ์ ์์๋ฅผ ์ค๋ช ํ๋ค.
18.1 ๋ฌด์์ด ๊ฐ์ฒด๋ฅผ ๋ณ๊ฒฝ ๊ฐ๋ฅํ๊ฒ ํ๋๊ฐ
์์ ํจ์ํ ๊ฐ์ฒด์ ํ๋์ ์ ๊ทผํ๊ฑฐ๋ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ํญ์ ๋์ผํ ๊ฒฐ๊ณผ๊ฐ ๋์จ๋ค.
class BankAccount {
private var bal: Int = 0
def balance: Int = bal
def deposit(amount: Int) = {
require(amount > 0)
bal += amount
}
def withdraw(amount: Int): Boolean =
if (amount > bal)
false
else {
bal -= amount
true
}
}
val account new BankAccount
account deposit 100
account withdraw 80
// true
account withdraw 88
// false
์์ ์์์ ๋ง์ง๋ง ๋ withDraw
๋ ๋ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ค.
์ฒซ๋ฒ์งธ๋ ๊ณ์ข์ ์ถฉ๋ถํ ์๊ณ ๊ฐ ์๊ธฐ ๋๋ฌธ์ true
๋ฅผ ๋ฐํํ์ง๋ง ๋ ๋ฒ์งธ๋ ๋์ผํ ์ฐ์ฐ์ ํธ์ถํ์ผ๋ ์๊ณ ๊ฐ ๋ถ์กฑํ์ฌ false
๋ฅผ ๋ฐํํ๋ค.
๋ง์ฝ ์ด๋ค ํด๋์ค๊ฐ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ์ํ๋ฅผ ๊ฐ์ง ๋ค๋ฅธ ๊ฐ์ฒด์๊ฒ ๋ฉ์๋ ํธ์ถ์ ์์ํ๊ธฐ ๋๋ฌธ์ var
๋ฅผ ์์ํ๊ฑฐ๋ ์ ์ํ์ง ์๊ณ ๋ ๋ณ๊ฒฝ๊ฐ๋ฅํ ์ํ๋ฅผ ๊ฐ์ง ์ ์๋ค.
class Keyed {
def computeKey: Int = ... // ๋น์ฉ์ด ๋ง์ด ๋๋ ์ฐ์ฐ
...
}
computeKey
๊ฐ ์ด๋ค var
๋ฅผ ์ฝ๊ณ ์ฐ์ง ์๋๋ค๋ฉด, ์บ์๋ฅผ ์ถ๊ฐํจ์ผ๋ก์จ Keyed
๋ฅผ ๋ ํจ์จ์ ์ผ๋ก ๋ง๋ค ์ ์๋ค.
class MemoKeyed extends Keyed {
private var keyCache: Option[Int] = None
override def computeKey: Int = {
if (!keyCache.isDefined)
keyCache = Some(super.computeKey)
keyCache.get
}
}
Keyed
๋์ MemoKeyed
๋ฅผ ์ฌ์ฉํด ์๋๋ฅผ ๋ ์ฌ๋ฆด ์ ์๋ค.
computeKey
์ ๊ฒฐ๊ณผ๋ฅผ ๋๋ฒ์งธ๋ก ์์ฒญ ๋ฐ์ผ๋ฉด, computeKey
๋ฅผ ํ๋ฒ ๋ ๊ณ์ฐํ๋ ๋์ keyCache
ํ๋์ ์ ์ฅํด๋ ๊ฐ์ ๋ฐํํ๊ธฐ ๋๋ฌธ์ด๋ค.
18.2 ์ฌํ ๋น ๊ฐ๋ฅํ ๋ณ์์ ํ๋กํผํฐ
์ค์นผ๋ผ์์๋ ์ด๋ค ๊ฐ์ฒด์ ๋ฉค๋ฒ ์ค ๋น๊ณต๊ฐ๊ฐ ์๋ ๋ชจ๋ var
๋ฉค๋ฒ์ Getter
์ Setter
๋ฉ์๋๋ฅผ ์๋์ผ๋ก ์ ์ํด ์ค๋ค.
Getter
์ Setter
์ ์ด๋ฆ์ ์๋ฐ์ ๊ด๋ก์๋ ๋ค๋ฅด๋ค
var x
์ Getter
๋ x
์ด๊ณ Setter ๋ x_=
์ด๋ค.
๋ค์์ ๊ณต๊ฐ var
๊ฐ ๊ฒํฐ์ ์ธํฐ ๋ฉ์๋๋ก ์ด๋ป๊ฒ ํ์ฅ๋๋์ง ๋ณด์ฌ์ฃผ๋ ์
class Time {
private[this] var h = 12
private[this] var m = 0
def hour: Int = h
def hour_= (x: Int) = { h = x }
def minute: Int = m
def minute_= (x: Int) = { m = x }
}
๋ค์์ var
๋ฅผ Getter
์ Setter
๋ก ํ์ฅํ๋ ๊ฒฝ์ฐ ์ง์ ์ ์ํ ์ ์๋ค๋ ์ ์ ๋ณด์ฌ์ค๋ค.
๋ง์ฝ ํน์ ๊ฐ์ ํ์ฉ๋ฒ์๋ฅผ ์ ํํ ๊ฒฝ์ฐ require
๋ฌธ์ ์ฌ์ฉํ๋ค.
class Time {
private[this] var h = 12
private[this] var m = 0
def hour: Int = h
def hour_= (x: Int) = {
require(0 <= x && x < 24)
h = x
}
def minute: Int = m
def minute_= (x: Int) = {
require(0 <= x && x < 60)
m = x
}
}
ํ๋กํผํฐ๋ ์ฌ๋ฌ ๋ชฉ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋๋ฐ ์์ ์์์๋ require
๋ฅผ ์ฌ์ฉํ์ฌ ๋ถ๋ณ ์กฐ๊ฑด (invariant) ๋ฅผ ์ ์ฉํ์๋ค.
์ด๋ฅผ ์ฌ์ฉํ๋ฉด ํ์ฉํ๋ฉด ์๋๋ ๊ฐ์ ๋ณ์์ ํ ๋นํ๋๊ฒ์ ๋ง์์ ์๋๋ฐ ์ด๋ค ๋ณ์์ ๋ชจ๋ ์ ๊ทผ์ ๋ก๊ทธ๋ก ๋จ๊ธธ์๋ ์๊ณ , ๋ณ์์ ์ด๋ฒคํธ๋ฅผ ์ ๋ชฉํด์ ์ด๋ค ๋ณ์๋ฅผ ๋ณ๊ฒฝํ ๋๋ง๋ค ๊ตฌ๋ (subscribe) ๋ฅผ ์์ฒญํ ๋ค๋ฅธ ๊ฐ์ฒด๋ค์๊ฒ ํต์งํ๊ฒ ๋ง๋ค ์ ์๋ค.
๋ค์๊ณผ ๊ฐ์ด ํ๋ ์ด๊ธฐํ์ = _
๋ฅผ ์ฌ์ฉํ๋ฉด ํ๋์ ์ ๋ก (zero) ๋ฅผ ํ ๋นํ๋ค.
์ ๋ก๋ ํ๋ ํ์ ์ ๋ฐ๋ผ ๋ค๋ฅด๋ค.
- ์ซ์ ํ์ : 0
- ๋ ผ๋ฆฌ ํ์ : false
- ์ฐธ์กฐ ํ์ : null
val celsius: Float = _
๋ง์ฝ ๋ค์๊ณผ ๊ฐ์ด ์ด๊ธฐํ ํ์ง ์์ผ๋ฉด ์ถ์ ๋ณ์๋ฅผ ์ ์ธํด ๋ฒ๋ฆฐ๋ค.
val celsius: Float
18.3 ์ฌ๋ก ์ฐ๊ตฌ: ์ด์ฐ ์ด๋ฒคํธ ์๋ฎฌ๋ ์ด์
์ฑ ์์ ์ฝ๋ ๋ฐ ์ค๋ช ์ฐธ๊ณ
18.4 ๋์งํธ ํ๋ก๋ฅผ ์ํ ์ธ์ด
์ฑ ์์ ์ฝ๋ ๋ฐ ์ค๋ช ์ฐธ๊ณ
18.5 ์๋ฎฌ๋ ์ด์ API
์ฑ ์์ ์ฝ๋ ๋ฐ ์ค๋ช ์ฐธ๊ณ
18.6 ํ๋ก ์๋ฎฌ๋ ์ด์
์ฑ ์์ ์ฝ๋ ๋ฐ ์ค๋ช ์ฐธ๊ณ
18.7 ๊ฒฐ๋ก
ํจ์ํ ์ ๊ทผ ๋ฐฉ์๊ณผ ๋ช ๋ นํ ์ ๊ทผ ๋ฐฉ์์ ์กฐํฉํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋๋ก ์ ๋ํ์.
Chapter 19 ํ์ ํ๋ผ๋ฏธํฐํ
ํ์ ํ๋ผ๋ฏธํํ๋ฅผ ์ฌ์ฉํ๋ฉด ์ ๋ค๋ฆญ ํด๋์ค์ ํธ๋ ์ดํธ๋ฅผ ์ธ ์ ์๋ค.
์งํฉ์ ์ ๋ค๋ฆญ์ด๋ฉฐ ํ์
ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ๊ธฐ ๋๋ฌธ์ ํ์
์ด Set[T]
์ด๋ค. (ํน์ ์งํฉ์ ์ธ์คํด์ค๋ Set[String]
, Set[Int]
์ด๋ค.)
์ ๋ค๋ฆญ ํ์ ์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ฐ์ง ์์๋ ๋๋ ์๋ฐ์ ๋ฌ๋ฆฌ, ์ค์นผ๋ผ์์๋ ๋ฐ๋์ ํ์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ช ์ํด์ผ ํ๋ค.
ํ์
๋ณ์ฑ์ ํ๋ผ๋ฏธํฐ ํ์
๊ฐ์ ์์๊ด๊ณ๋ฅผ ์ง์ ํด์ผ ํ๋๋ฐ ์๋ฅผ ๋ค๋ฉด Set[String]
์ด Set[AnyRef]
ํ์ ์งํฉ์ธ์ง ๋ณ์ฑ์ ์ํด ๊ฒฐ์ ๋๋ค.
19.1 ํจ์ํ ํ
- head: ํ์ ์ฒซ ์์๋ฅผ ๋ฐํํ๋ค.
- tail: ํ์ ์ฒซ ์์๋ฅผ ์ ์ธํ ๋๋จธ์ง๋ฅผ ๋ฐํํ๋ค.
- enqueue: ์ธ์๋ก ์ฃผ์ด์ง ์์๋ฅผ ํ์ ๋งจ๋ค์ ์ถ๊ฐํ ์๋ก์ด ํ๋ฅผ ๋ฐํํ๋ค.
class SlowAppendQueue[T](elems: List[T]) {
def head = elems.head
def tail = new SlowAppendQueue(elems.tail)
def enqueue(x: T) = new SlowAppendQueue(elems ::: List(x))
}
enqueue
์ฐ์ฐ์ ํ์ ๋ค์ด์๋ ์์์ ๊ฐ์์ ๋น๋กํ๋ค.
์์ ์๊ฐ ์ถ๊ฐ๋ฅผ ๋ฐ๋๋ค๋ฉด ์๋์ ๊ฐ์ด ๋ฆฌ์คํธ์ ์์๋ฅผ ๋ค์ง์ ์๋ ์๋ค.
class SlowHeadQueue[T](smele: List[T]) {
def head = smele.last
def tail = new SlowHeadQueue(smele.init)
def enqueue(x: T) = new SlowHeadQueue(x :: smele)
}
enqueue
๋ ์์ ์๊ฐ์ด์ง๋ง head
, tail
์ ๊ทธ๋ ์ง ์๋ค. ์ด๋ค์ ์์ ๊ฐ์์ ๋น๋กํ๋ ์๊ฐ์ ์๋นํ๋ค.
์์๋ฅผ ์ถ๊ฐํ๊ธฐ ์ํด์๋ ::
์ฐ์ฐ์๋ฅผ ์ฌ์ฉํด trailing
๋ฆฌ์คํธ์ ๋ฃ์ผ๋ฉด ๋๋ฉฐ ์ด๋ ์์ ์๊ฐ์ด ๊ฑธ๋ฆฐ๋ค.
์ ๋๊ฐ์ง ๋ฐฉ๋ฒ์ ํผ์ฉํ์ฌ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํํ๋ค.
class Queue[T](
private val leading: List[T],
private val trailing: List[T]
) {
private def mirror = if (leading.isEmpty)
new Queue(trailing.reverse, Nil)
else
this
def head = mirror.leading.head
def tail = {
val q = mirror
new Queue(q.leading.tail, q.trailing)
}
def enqueue(x: T) =
new Queue(leading, x :: trailing)
}
mirror
์ฐ์ฐ์ ํ์ ์์ ๊ฐ์์ ๋น๋กํ๋ ์๊ฐ์ด ๊ฑธ๋ฆผhead
๋ฅผ ๋ง์ด ํธ์ถํ๋ฉด ๋งค๋ฒhead
๋ฅผ ์คํํ ๋ ๋ง๋ค ๋น์ผ ๋น์ฉ์ ๋ค์ฌ ๋ฆฌ์คํธ๋ฅผ ์ ๋ฆฌํ๊ธฐ ์ํดmirror
๋ฅผ ํธ์ถ
19.2 ์ ๋ณด ์๋
ํด๋ผ์ด์ธํธ์๊ฒ ๋ด๋ถ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ถ๋ ๋ฐฉ๋ฒ
๋น๊ณต๊ฐ ์์ฑ์์ ํฉํ ๋ฆฌ ๋ฉ์๋
ํด๋์ค ํ๋ผ๋ฏธํฐ ๋ชฉ๋ก ๋ฐ๋ก ์์ private ์์์๋ฅผ ๋ถ์ฌ ์ฃผ ์์ฑ์๋ฅผ ๊ฐ์ถ ์ ์๋ค.
class Queue[T] private (
private val leading: List[T],
private val trailing: List[T]
)
์ด ์์ฑ์๋ ์ค์ง ํด๋์ค ์์ ๊ณผ ๋๋ฐ ๊ฐ์ฒด์ ๋ํด์๋ง ์ ๊ทผ ๊ฐ๋ฅํ๋ค.
์ด๋ ํด๋ผ์ด์ธํธ๊ฐ์ฃผ ์์ฑ์๋ฅผ ๋์ด์ ํธ์ถํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ณด์กฐ ์์ฑ์๋ฅผ ์ถ๊ฐํด์ค์ผ ํ๋ค.
def this() = this(Nil, Nil)
์ ๋ณด์กฐ ์์ฑ์๋ ๋น ํ๋ฅผ ๋ง๋ ๋ค.
์๋์ ๊ฐ์ด ๋ณด์กฐ ํ์ฅ์๊ฐ ํ๋ฅผ ์ด๊ธฐํํ ์์๋ฅผ ๋ฐ๊ฒ ๋ง๋ค์ ์๋ค.
def this(elem: T*) = this(elems.toList, Nil)
T*
๋ ๋ฐ๋ณต ํ๋ผ๋ฏธํฐ ์ด๋ค. (8.8 ์ )
๋ค๋ฅธ ๋ฐฉ๋ฒ์ ๋ณด์กฐ ์์ฑ์ ์ฒ๋ผ ์ด๊ธฐ ์์์ ๋ชฉ๋ก์ผ๋ก๋ถํฐ ํ๋ฅผ ๋ง๋๋ ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ด๋ค.
object Queue {
def apply[T](xs: T*) = new Queue[T](xs.toList, Nil)
}
xs
์ ์์๋ฅผ ํ๋ก ๋ง๋ ๋ค.
Queue(1, 2, 3)
// or
Queue.apply(1, 2, 3)
๋์: ๋น๊ณต๊ฐ ํด๋์ค
ํด๋์ค ์์ฒด๋ฅผ ๊ฐ์ถ๊ฐ ํด๋์ค์ ๋ํ ๊ณต๊ฐ ์ธํฐํ์ด์ค๋ง์ ์ ๊ณตํ๋ ํธ๋ ์ดํธ๋ฅผ ์ธ๋ถ๋ก ๋ ธ์ถํ๋ค.
trait Queue[T] {
def head: T
def tail: Queue[T]
def enqueue(x: T): Queue[T]
}
object Queue {
def apply[T](xs: T*): Queue[T] =
new QueueImpl[T](xs.toList, Nil)
private class QueueImpl[T](
private val leading: List[T],
private val trailing: List[T]
) extends Queue[T] {
def mirror =
if (leading.isEmpty)
new QueueImpl(trailing.reverse, Nil)
else
this
def head: T = mirror.leading.head
def tail: QueueImpl[T] = {
val q = mirror
new QueueImpl(q.leading.tail, q.trailing)
}
def enqueue(x: T) =
new QueueImpl(leading, x :: trailing)
}
}
์์ ๊ฐ์ด ๊ตฌํ ํด๋์ค์ธ QueueImpl
ํด๋์ค ์ ์ฒด๋ฅผ ๊ฐ์ถ๋ค.
19.3 ๋ณ์ฑ ํ๊ธฐ
์์ ์ ์ํ Queue
๋ ํธ๋ ์ดํธ์ด๋ฉฐ ํ์
์ด ์๋๋ค.
Queue
๊ฐ ํ์
์ด ์๋ ์ด์ ๋ ํ์
ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ๊ธฐ ๋๋ฌธ์ด๋ค.
๋๋ฌธ์ Queue
๋ผ๋ ํ์
์ ๋ณ์๋ฅผ ๋ง๋ค์ ์๋ค.
def doesNotCompile(q: Queue) = {}
// ^
// error: class Queue takes type parameters
๋์ Queue
ํธ๋ ์ดํธ๋ Queue[String]
, Queue[Int]
, Queue[AnyRef]
์ฒ๋ผ ํ๋ผ๋ฏธํฐํ๋ ํ์
์ ์ง์ ํ๋๋ก ํ์ฉํ๋ค.
๋ฐ๋ผ์ Queue
๋ ํ์
์์ฑ์๋ผ๊ณ ๋ ํ ์ ์๋ค.
์ค์นผ๋ผ์์ ์ ๋ค๋ฆญ ํ์ ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ฌด๊ณต๋ณ (non-variant) ์ด๋ค.
์ด๋ค ํ์ ํ๋ผ๋ฏธํฐ์ ๊ณต๋ณ, ๋ฐ๊ณต๋ณ, ๋ฌด๊ณต๋ณ ์ฌ๋ถ๋ฅผ ํ๋ผ๋ฏธํฐ์ ๋ณ์ฑ (variance) ๋ผ๊ณ ํ๋ค.
+
, -
๊ธฐํธ๋ ๋ณ์ฑ ํ๊ธฐ (variance annotation) ๋ผ๊ณ ๋ถ๋ฅธ๋ค.
val c1 = new Cell[String]("abc")
val c2: Cell[Any] = c1
c2.set(1)
val s: String = c1.get
์ ์ฝ๋๋ ์ปดํ์ผ ์ค๋ฅ๋ฅผ ๋ฐ์ ์ํจ๋ค.
Cell.scala:7: error: covariant type T occurs in
contravariant position in type T of value x
def set(x: T) = current = x
^
๋ณ์ฑ๊ณผ ๋ฐฐ์ด
String[] a1 = { "abc" };
Object[] a2 = a1;
a2[0] = new Integer(17);
String s = a1[0];
์๋ฐ๋ ์คํ ์์ ์ ํ์ ์ ์ ๋ณด๋ฅผ ์ ์ฅํ๋ค. ์ด๋ ์์ ํ์ง ์๋ ๋ฐฉ๋ฒ์ด๋ ์ค๊ณ๋น์ ๋ฐฐ์ด์ ์ ๋ค๋ฆญํ๊ฒ ๋ค๋ฃฐ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ด ํ์ํ๊ธฐ ๋๋ฌธ์ด๋ค.
val a1 = Array("abc")
val a2: Array[Any] = a1
์ค์นผ๋ผ๋ ๋ฐฐ์ด์ ๋ฌด๊ณต๋ณ์ผ๋ก ๋ค๋ฃจ๊ธฐ ๋๋ฌธ์ ์์ ๊ฐ์ด Array[String]
์ Array[Any]
๋ก ๋์ฒดํ ์ ์๋ค.
19.4 ๋ณ์ฑ ํ๊ธฐ ๊ฒ์ฌ
- ์ค์นผ๋ผ ์ปดํ์ผ๋ฌ๋ ํด๋์ค๋ ํธ๋ ์ดํธ ๋ณธ๋ฌธ์ ๋ชจ๋ ์์น๋ฅผ ๊ธ์ ์ , ๋ถ์ ์ , ์ค๋ฆฝ์ ์ผ๋ก ๊ตฌ๋ถํ๋ค.
+
๋ก ํ์ํ ํ์ ํ๋ผ๋ฏธํฐ๋ ๊ธ์ ์ ์ธ ์์น์์๋ง ์ฌ์ฉ ๊ฐ๋ฅ-
๋ก ํ์ํ ํ๋ผ๋ฏธํฐ๋ ๋ถ์ ์ ์์น์์๋ง ์ฌ์ฉ ๊ฐ๋ฅ- ์๋ฌด ๋ณ์ฑ ํ๊ธฐ๊ฐ ์๋ ํ์ ํ๋ผ๋ฏธํฐ๋ ์๋ฌด ๊ณณ์์๋ ์ฌ์ฉ ๊ฐ๋ฅ
- ๊ฐ์ฅ ๋ฐ๊นฅ ์ค์ฝํ๋ถํฐ ๋ด๋ถ ์ค์ฝํ๋ก ๊ธ์ ์ /๋ถ์ ์ /์ค๋ฆฝ์ ์ธ์ง ๊ตฌ๋ถํ๋ค.
19.5 ํ์ ๋ฐ์ด๋
Queue[T]
์ ์์์ T
๋ฅผ ๊ณต๋ณ์ ์ผ๋ก ๋ง๋ค ์ ์๋ค.
T
๋ enqueue
๋ฉ์๋์ ํ๋ผ๋ฏธํฐ ํ์
์ธ๋ฐ ๊ทธ ์์น๋ ๋ถ์ ์ ์ด๊ธฐ ๋๋ฌธ์ด๋ค (?)
enqueue
๋ฅผ ๋คํ์ฑ (์ฆ enqueue์ ํ์
ํ๋ผ๋ฏธํฐ๋ฅผ ์ง์ ) ์ผ๋ก ๋ ์ผ๋ฐํํ๊ณ , ํ์
ํ๋ผ๋ฏธํฐ์ ํ์ ๋ฐ์ด๋ (lower bound) ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ์ด๋ค.
class Queue[+T](
private val leading: List[T],
private val trailing: List[T]
) {
def enqueue[U >: T](x: U) =
new Queue[U](leading, x :: trailing) // ...
}
์ ์ฝ๋์์๋ enqueue
์ ํ์
ํ๋ผ๋ฏธํฐ U
๋ฅผ ์ถ๊ฐํ๋ฉด์ U >: T
๋ฅผ ์ฌ์ฉํ์ฌ T
๋ฅผ U
์ ํ์ ๋ฐ์ด๋๋ก ์ง์ ํ์๋ค. (U
๋ T
์ ์ํผํ์
)
๋ฐ๋ผ์ ๋ฉ์๋์ ๋ฐํ๊ฐ์ผ๋ก Queue[T]
์์ Queue[U]
๋ก ๋ฐ๋๋ค.
์ ์ฝ๋๋ ๋ณ์ฑ ํ๊ธฐ์ ํ์ ๋ฐ์ด๋๊ฐ ํจ๊ป ์ ์๋ํ ์ ์์์ ๋ณด์ฌ์ค๋ค.
์ด๋ค์ ํ์ ์์ฃผ ์ค๊ณ (type-driven design) ์ ์ข์ ์์ด๋ค.
์ค์นผ๋ผ๊ฐ ์๋ฐ์ ์์ผ๋์นด๋ (wildcard) ์์ ๋ณผ ์ ์๋ ์ฌ์ฉ ์์น ๋ณ์ฑ (use-site variance) ๋ณด๋ค ์ ์ธ ์์น ๋ณ์ฑ (declaration-site variance) ๋ฅผ ์ ํธํ๋ ์ฃผ๋ ์ด์ ์ด๋ค.
19.6 ๋ฐ๊ณต๋ณ์ฑ
trait OutputChannel[-T] {
def write(x: T)
}
U
ํ์
์ ๊ฐ์ด ํ์ํ ๋ชจ๋ ๊ฒฝ์ฐ๋ฅผ T
ํ์
์ ๊ฐ์ผ๋ก ๋์นํ ์ ์๋ค๋ฉด T
ํ์
์ U
ํ์
์ ์๋ธํ์
์ผ๋ก ๊ฐ์ ํด๋ ์์ ํ๋ค๋ ๊ฒ์ด๋ค. (๋ฆฌ์ค์ฝํ ์นํ์์น)
ํ ํ์ ์์์ ๊ณต๋ณ์ฑ๊ณผ ๋ฐ๊ณต๋ณ์ฑ์ด ํจ๊ป ์์ฌ์๋ ๊ฒฝ์ฐ๋ ์๋ค.
trait Function1[-S, +T] {
def apply(x: S): T
}
Function1
ํธ๋ ์ดํธ๋ ์ธ์ ํ์
S
์ ๋ํด์๋ ๋ฐ๊ณต๋ณ์ด๊ณ , ๊ฒฐ๊ณผ ํ์
T
์ ๋ํด์๋ ๊ณต๋ณ์ด๋ค.
์ธ์๋ ํจ์๊ฐ ์๊ตฌํ๋๊ฒ์ด๊ณ ๊ฒฐ๊ณผ๋ ํจ์๊ฐ ์ ๊ณตํ๋๊ฒ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
PECS ์ ์ ์ฌํด ๋ณด์ธ๋ค.
19.7 ๊ฐ์ฒด์ ๋น๊ณต๊ฐ ๋ฐ์ดํฐ
class Queue[+T] private (
private[this] var leading: List[T],
private[this] var trailing: List[T]
) {
private def mirror() =
if (leading.isEmpty) {
while (!trailing.isEmpty) {
leading = trailing.head :: leading
trailing = trailing.tail
}
}
def head: T = {
mirror()
leading.head
}
def tail: Queue[T] = {
mirror()
new Queue(leading.tail, trailing)
}
def enqueue[U >: T](x: U) =
new Queue[U](leading, x :: trailing)
}
19.8 ์์ ๋ฐ์ด๋
T <: Ordered[T]
๋ผ๋ ๋ฌธ๋ฒ์ ์ฌ์ฉํ์ฌ ํ์
ํ๋ผ๋ฏธํฐ T
์ ์์ ๋ฐ์ด๋๊ฐ Order[T] ๋ผ๋ ์ฌ์ค์ ๋ช
์ํ ์ ์๋ค.
def orderedMergeSort[T <: Ordered[T]](xs: List[T]): List[T] = {
def merge(xs: List[T], ys: List[T]): List[T] =
(xs, ys) match {
case (Nil, _) => ys
case (_, Nil) => xs
case (x :: xs1, y :: ys1) =>
if (x < y) x :: merge(xs1, ys)
else y :: merge(xs, ys1)
}
val n = xs.length / 2
if (n == 0) xs
else {
val (ys, zs) = xs splitAt n
merge(orderedMergeSort(ys), orderedMergeSort(zs))
}
}
19.9 ๊ฒฐ๋ก
์ ๋ณด ์๋์ ์ํ ์ฌ๋ฌ ๊ธฐ๋ฒ์ ์ดํด๋ณด์๋ค. (๋น๊ณต๊ฐ ์์ฑ์, ํฉํ ๋ฆฌ ๋ฉ์๋, ๊ฐ์ฒด ๋น๊ณต๊ฐ ๋ฉค๋ฒ)
๋ํ ํ์ ๋ณ์ฑ์ ์ง์ ํ๋ ๋ฒ, ๋ณ์ฑ ํ๊ธฐ๋ฅผ ์ํ ๊ธฐ๋ฒ๋ค๋ ์ดํด๋ณด์๋ค.
Chapter 20 ์ถ์ ๋ฉค๋ฒ
ํด๋์คํ ํธ๋ ์ดํธ์ ๋ฉค๋ฒ๊ฐ ๊ทธ ํด๋์ค ์์ ์์ ํ ์ ์๋ฅผ ๊ฐ๊ณ ์์ง ์์ผ๋ฉด ์ถ์ ๋ฉค๋ฒ (abstract member) ๋ผ๊ณ ํ๋ค.
์ถ์ ๋ฉค๋ฒ๋ ๊ทธ ๋ฉค๋ฒ๊ฐ ์ ์๋ ํด๋์ค๋ฅผ ์์ํ ์๋ธ ํด๋์ค์์ ๊ตฌํํ๋๋ก ๋์ด ์๋ค.
20.1 ์ถ์ ๋ฉค๋ฒ ๊ฐ๋ตํ๊ฒ ๋์๋ณด๊ธฐ
trait Abstract {
type T
def transform(x: T): T
val initial: T
var current: T
}
Abstract
๋ฅผ ๊ตฌ์ฒด์ ์ผ๋ก ๊ตฌํํ๋ ค๋ฉด ๊ฐ๊ฐ์ ์ถ์ ๋ฉค๋ฒ ์ ์๋ฅผ ์ฑ์๋ฃ์ด์ผ ํ๋ค.
class Concrete extends Abstract {
type T = String
def transform(x: String) = x + x
val initial = "hi"
var current = initial
}
20.2 ํ์ ๋ฉค๋ฒ
์ค์นผ๋ผ์์ ์ถ์ ํ์ (abstract type) ์ ํด๋์ค๋ ํธ๋ ์ดํธ์ ๋ฉค๋ฒ๋ก ์ ์ ์์ด ์ ์ธ๋ ํ์ ์ด๋ค.
์ด๋ค ํ์ ์ ๋ํ ์๋ก์ด ์ด๋ฆ, ํน์ ๋ณ๋ช (alias) ์ ์ ์ํ๋ ๋ฐฉ๋ฒ์ผ๋ก ์๊ฐํ ์ ์๋ค.
ํ์ ๋ฉค๋ฒ๋ ์ค์ ์ด๋ฆ์ด ๋๋ฌด ๊ธธ๊ฑฐ๋ ์๋ฏธ๊ฐ ๋ถ๋ช ํํ ๋ ๋ ๊ฐ๋จํ๊ณ ์๋๋ฅผ ์ ์ ๋ฌํ ์ ์๋ ๋ณ๋ช ์ ์ ์ธํ๋ ๊ฒ์ด๋ค.
์๋ธํด๋์ค์์ ๊ผญ ์ ์ํด์ผ ํ๋ ์ถ์ ํ์ ์ ์ ์ธ ํ์ฌ ์ฌ์ฉํ๋ค.
20.3 ์ถ์ val
val inital: String
val
์ ๋ํด ์ด๋ฆ๊ณผ ํ์
์ ์ฃผ์ง๋ง ๊ฐ์ ์ง์ ํ์ง ์๋๋ค.
์ค์ ๋ก Concrete ํด๋์ค ๊ตฌํ์์ ์์ val
์ ๋ค์๊ณผ ๊ฐ์ด ์ ์ํ ์ ์๋ค.
์ถ์ val ์ ์ธ์ ํ๋ผ๋ฏธํฐ ์๋ ์ถ์ ๋ฉ์๋ ์ ์ธ๊ณผ ๋น์ทํด ๋ณด์ธ๋ค.
abstract class Fruit {
val v: String // `v' ๋ ๊ฐ์ ์๋ฏธ
def m: String // `m' ์ ๋ฉ์๋๋ฅผ ์๋ฏธ
}
abstract class Apple extends Fruit {
val v: String
val m: String // def ๋ฅผ val ๋ก ์ค๋ฒ๋ผ์ด๋ ํ ์ ์๋ค.
}
abstract class BadApple extends Fruit {
def v: String // ์ค๋ฅ: val ์ def ๋ก ์ค๋ฒ๋ผ์ด๋ ํ ์ ์๋ค.
def m: String
}
20.4 ์ถ์ var
์์์ ์ผ๋ก Getter
๋ฉ์๋์ Setter
๋ฉ์๋๋ฅผ ์ ์ํ๋ ๊ฒ๊ณผ ๊ฐ๋ค.
trait AbstractTime {
var hour: Int
var minute: Int
}
trait AbstractTime {
def hour: Int
def hour_=(x: Int)
def minute: Int
def minute_=(x: Int)
}
20.5 ์ถ์ val ์ ์ด๊ธฐํ
์ํผํด๋์ค์ ๋น ์ง ์์ธํ ๋ถ๋ถ์ ์๋ธํด๋์ค์ ์ ๋ฌํ ์ ์๋ ์๋จ์ ์ ๊ณตํ๋ค.
์ด ๋ถ๋ถ์ ํธ๋ ์ดํธ์ ์ค์ํ๋ฐ, ํธ๋ ์ดํธ์๋ ํ๋ผ๋ฏธํฐ๋ฅผ ๋๊ธธ ์์ฑ์๊ฐ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๋ฐ๋ผ์ ๋ณดํต ํธ๋ ์ดํธ๋ฅผ ํ๋ผ๋ฏธํฐํ ํ๋ ค๋ฉด ์๋ธ ํด๋์ค์์ ๊ตฌํํ๋ ์ถ์ val ์ ํตํ๊ธฐ ๋ง๋ จ์ด๋ค.
trait RationalTrait {
val numerArg: Int
val denomArg: Int
}
new RationalTrait {
val numerArg = 1
val denomArg = 2
}
new
ํค์๋๋ฅผ ํธ๋ ์ดํธ ์ด๋ฆ RationalTrait
์์ ์ ์๋ค. ๊ทธ๋ฆฌ๊ณ ํธ๋ ์ดํธ ์ด๋ฆ ๋ค์์ ์ค๊ดํธ ์์ ์ ํด๋์ค์ ๋ณธ๋ฌธ์ด ๋ค์ด๊ฐ๋ค.
์ด ํํ์์ ํธ๋ ์ดํธ๋ฅผ ํผํฉํ ์ต๋ช ํด๋์ค (anonymous class) ์ ์ธ์คํด์ค๋ฅผ ๋ง๋ค๋ฉฐ ํด๋์ค ์ ์๋ ๋ณธ๋ฌธ์ ์๋ค.
trait RationalTrait {
val numerArg: Int
val denomArg: Int
require(denomArg != 0)
private val g = gcd(numerArg, denomArg)
val numer = numerArg / g
val denom = denomArg / g
private def gcd(a: Int, b: Int): Int =
if (b == 0) a else gcd(b, a % b)
override def toString = numer +"/"+ denom
}
์ ์ฝ๋์์ ํธ๋ ์ดํธ์ ๋ถ๋ชจ๋ ๋ถ์์ ๋จ์ํ ๋ฆฌํฐ๋ด์ด ์๋ ํํ์์ ๋ฃ์ด์ ์ด๊ธฐํํ๋ ค๊ณ ํ๋ฉด ์์ธ๊ฐ ๋ฐ์ํ๋ค.
RationalTrait
ํด๋์ค๋ฅผ ์ด๊ธฐํํ ๋ denomArg
์ ๊ฐ์ด ๋ํดํธ ๊ฐ์ธ 0
์ด๊ธฐ ๋๋ฌธ์ด๋ค.
ํ๋ ๋ฏธ๋ฆฌ ์ด๊ธฐํํ๊ธฐ
- ์ต๋ช ํด๋์ค ํํ์์์ ํ๋ ๋ฏธ๋ฆฌ ์ด๊ธฐํํ๊ธฐ
new {
val numerArg = 1 * x
val denomArg = 2 * x
} with RationalTrait
- ๊ฐ์ฒด ์ ์์์ ํ๋๋ฅผ ๋ฏธ๋ฆฌ ์ด๊ธฐํํ๊ธฐ
object twoThirds extends {
val numerArg = 2
val denomArg = 3
} with RationalTrait
- ํด๋์ค ์ ์์์ ํ๋๋ฅผ ๋ฏธ๋ฆฌ ์ด๊ธฐํํ๊ธฐ
class RationalClass(n: Int, d: Int) extends {
val numerArg = n
val denomArg = d
} with RationalTrait {
def + (that: RationalClass) = new RationalClass(
numer * that.denom + that.numer * denom,
denom * that.denom
)
}
์ง์ฐ ๊ณ์ฐ val ๋ณ์
object Demo {
lazy val x = { println("initializing x"); "done" }
}
scala> Demo
res5: Demo.type = Demo$@11dda2d
scala> Demo.x
initializing x
res6: java.lang.String = done
Demo
๋ฅผ ์ด๊ธฐํํ๋ ๊ณผ์ ์๋ x
๋ฅผ ์ด๊ธฐํํ๋ ๊ณผ์ ์ด ๋ค์ด๊ฐ์ง ์๋๋ค.
x
์ ์ด๊ธฐํ๋ฅผ x
๊ฐ ๋งจ ์ฒ์ ์ฐ์ผ ๋๊น์ง ์ฐ๊ธฐํ๋ค.
20.6 ์ถ์ ํ์
- ์ถ์ ํ์ ์ ์ธ: ์๋ธ ํด๋์ค์์ ๊ตฌ์ฒด์ ์ผ๋ก ์ ํด์ผ ํ๋ ์ด๋ค ๋์์ ๋ํ ๋น ๊ณต๊ฐ์ ๋ง๋ จํด๋๋ ๊ฒ์ด๋ค.
class Food
abstract class Animal {
type SuitableFood <: Food
def eat(food: SuitableFood)
}
SuitableFood
๋ฅผ ๊ตฌ์ฒด์ ์ผ๋ก ์ธ์คํด์คํ ํด์ผ ํ๋ ๊ฒฝ์ฐ Food
์ ์๋ธํด๋์ค์ฌ์ผ ํ๋ค๋ ๋ป์ด๋ค.
20.7 ๊ฒฝ๋ก์ ์์กดํ๋ ํ์
val bessy: Animal = new Cow
bessy.SuitableFood
์ ๊ฐ์ ํ์
์ ๊ฒฝ๋ก์ ์์กดํ๋ ํ์
(path-dependent type) ์ด๋ผ๊ณ ํ๋ค.
์ฌ๊ธฐ์ ๊ฒฝ๋ก๋ ๊ฐ์ฒด์ ์ฐธ์กฐ๋ฅผ ์๋ฏธํ๋ค.
์ด ํ์ ์ ๊ฒฝ๋ก์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ค.
20.8 ์ธ๋ถํํ ํ์
์ด๋ค ํด๋์ค A ๊ฐ ๋ค๋ฅธ ํด๋์ค B ๋ฅผ ์์ํ ๋, ์ ์ (A) ๊ฐ ํ์ (B) ์ ์ด๋ฆ์ ์ํ ์๋ธํ์ ์ด๋ผ๊ณ ๋งํ๋ค.
์ด ์ด๋ฆ์ ์ํ ์๋ธํ์ ์ ์ฌ์ฉํ๊ธฐ ํธํ๋ฉฐ ์ด๋ฆ์ ์งง์ ์๋ณ์์ด๊ธฐ ๋๋์ ํ์ ์ ๋์ดํ๋๊ฒ ๋ณด๋ค ํจ์ฌ ๊ฐ๊ฒฐํ๋ค.
Animal { type SuitableFood = Grass }
class Pasture {
var animals: List[Animal { type SuitableFood = Grass }] = Nil
// ...
}
20.9 ์ด๊ฑฐํ
์ค์นผ๋ผ๋ ์ด๊ฑฐํ์ ์ํ ํน๋ณํ ๋ฌธ๋ฒ์ ์ ๊ณตํ์ง๋ ์์ง๋ง scala.Enumeration
์ด๋ผ๋ ํด๋์ค๊ฐ ์ค์นผ๋ผ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์๋ค.
object Color extends Enumeration {
val Red = Value
val Green = Value
val Blue = Value
}
object Color extends Enumeration {
val Red, Green, Blue = Value
}
์ ๋ ์ฝ๋๋ ๊ฐ์ ๊ธฐ๋ฅ์ ํ๋ค.
๋ค์๊ณผ ๊ฐ์ด Value
๋ฉ์๋๋ฅผ ์ค๋ฒ๋ก๋ํ ๋ณํ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ์ด๊ฑฐํ ๊ฐ๊ณผ ์ด๋ฆ์ ์ฐ๊ด์ํฌ์ ์๋ค.
object Direction extends Enumeration {
val North = Value("North")
val East = Value("East")
val South = Value("South")
val West = Value("West")
}
๋ํ values ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด, ์ด๋ค ์ด๊ฑฐํ์ ๊ฐ์ ๋ํด ์ดํฐ๋ ์ด์ ํ ์ ์๋ค.
for (d <- Direction.values) print(d +" ")
// North East South West
๊ฐ ์ด๊ฑฐํ์ 0 ๋ถํฐ ๋ฒํธ (id) ๊ฐ ๋ถ๋๋ค ์ด ๋ฒํธ๋ id ๋ฉ์๋ ๋ฐ๋๋ก ์ด๊ฒจํ ๊ฐ์ผ๋ก ํธ์ถํ ์ ์๋ค.
Direction.East.id
// 1: Int
Direction(1)
// East
20.10 ์ฌ๋ก ์ฐ๊ตฌ: ํตํ ๋ณํ
์์ ์ฝ๋ ์ค๋ช
20.11 ๊ฒฐ๋ก
์ค์นผ๋ผ๋ ๊ฐ์ฒด์งํฅ ์ถ์ํ๋ฅผ ๊ตฌ์กฐ์ ์ผ๋ก ์ผ๋ฐํํ์ฌ ์ง์ํ๋ค.