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()

๋ฆฌ์ŠคํŠธ๋Š” ๋ฐฐ์—ด๊ณผ ๋น„์Šทํ•˜์ง€๋งŒ ๋‹ค์Œ ๋‘๊ฐ€์ง€ ์ฐจ์ด์ ์ด ์žˆ๋‹ค.

  1. ๋ฆฌ์ŠคํŠธ๋Š” ๋ณ€๊ฒฝ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
  2. ๋ฆฌ์ŠคํŠธ๋Š” ์žฌ๊ท€์  (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 ์—ฐ์‚ฐ์€ ๋‹ค์Œ ๋ฒ•์น™์„ ๋งŒ์กฑํ•œ๋‹ค.

  1. reverse ๋Š” ์ž๊ธฐ์ž์‹ ์˜ ์—ญ์ด๋‹ค.
  • xs.reverse.reverse ๋Š” xs ์™€ ๊ฐ™๋‹ค.
  1. ์›์†Œ์˜ ๋ฐฉํ–ฅ์ด ๋’ค์ง‘ํ˜”๋‹ค๋Š” ์ ์„ ์ œ์™ธํ•˜๋ฉด 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 ๊ฒฐ๋ก 

์Šค์นผ๋ผ๋Š” ๊ฐ์ฒด์ง€ํ–ฅ ์ถ”์ƒํ™”๋ฅผ ๊ตฌ์กฐ์ ์œผ๋กœ ์ผ๋ฐ˜ํ™”ํ•˜์—ฌ ์ง€์›ํ•œ๋‹ค.