5μ£Όμ°¨ (21 ~ 25 Chapter)

Chapter 21 μ•”μ‹œμ  λ³€ν™˜κ³Ό μ•”μ‹œμ  νŒŒλΌλ―Έν„°

일반적으둜 λ‹€λ₯Έ μ‚¬λžŒμ˜ 라이브러리λ₯Ό μ‚¬μš©ν•˜κ³  싢은 κ²½μš°μ—λŠ” 보톡 μžˆλŠ” κ·ΈλŒ€λ‘œ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€λŠ” 점이닀.

이λ₯Ό κ°œμ„ ν•˜κΈ° μœ„ν•΄ ν”„λ‘œκ·Έλž˜λ° 언어듀은 λ‹€μ–‘ν•œ μš”μ†Œλ₯Ό λ„μž…ν•΄ μ™”λ‹€.

  • 루비 & 슀λͺ°ν† ν¬ -> νŒ¨ν‚€μ§€λ“€μ΄ μ„œλ‘œ 클래슀λ₯Ό μΆ”κ°€ν•  수 있음
  • C# -> 정적 λ©”μ„œλ“œ (static extendsion method) κ°€ μžˆμ–΄ μ’€ 더 μ§€μ—­μ μœΌλ‘œ λ³€κ²½ν•  수 있음

μŠ€μΉΌλΌμ—μ„œλŠ” μ•”μ‹œμ  λ³€ν™˜μ΄λΌλŠ” 해법을 μ œκ³΅ν•œλ‹€.

21.1 μ•”μ‹œμ  λ³€ν™˜

μ•”μ‹œμ  λ³€ν™˜μ„ μ‚¬μš©ν•˜λ©΄ ν•œ νƒ€μž…μ„ λ‹€λ₯Έ νƒ€μž…μœΌλ‘œ λ³€κ²½ν•˜λŠ” 데 ν•„μš”ν•œ λͺ…μ‹œμ μΈ λ³€ν™˜μ˜ 숫자λ₯Ό 쀄일 수 μžˆλ‹€.

val button = new JButton
button.addActionListener(
  new ActionListener {
    def actionPerformed(event: ActionEvent) {
      println("pressed!")
    }
  }
)

μœ„ μ½”λ“œλ₯Ό 슀칼리 μΉœν™”μ μœΌλ‘œ λ°”κΎΌλ‹€.

button.addActionListener( // νƒ€μž… 뢈일치!
  (_: ActionEvent) => println("pressed!")
)

μœ„ μ½”λ“œλŠ” λ™μž‘λ˜μ§€ μ•ŠλŠ”λ‹€.

addActionListener κ°€ μ›ν•˜λŠ” 것은 ActionListener 이기 λ•Œλ¬Έμ΄λ‹€.

μ΄λŠ” λ‹€μŒκ³Ό 같이 μ•”μ‹œμ  λ³€ν™˜λ°©λ²•μ„ μ‚¬μš©ν•˜μ—¬ μž‘μ„±ν•œλ‹€.

Β 




implicit def function2ActionListener(f: ActionEvent => Unit) = 
  new ActionListener {
    def actionPerformed(event: ActionEvent) = f(event)
  }

function2ActionListener κ°€ implicit 둜 ν‘œκΈ°ν•΄λ’€κΈ° λ•Œλ¬Έμ—, 이λ₯Ό μƒλž΅ν•΄λ„ μ»΄νŒŒμΌλŸ¬κ°€ μžλ™μœΌλ‘œ μΆ”κ°€ν•΄μ€€λ‹€.

21.2 μ•”μ‹œ κ·œμΉ™

ν‘œμ‹œ κ·œμΉ™: implicit둜 ν‘œμ‹œν•œ μ •μ˜λ§Œ κ²€ν†  λŒ€μƒμ΄λ‹€.

λ³€μˆ˜, ν•¨μˆ˜, 객체 μ •μ˜μ— implicit ν‘œμ‹œλ₯Ό 달 수 μžˆλ‹€.

implicit def intToString(x: Int) = x.toString

μ»΄νŒŒμΌλŸ¬λŠ” μ•”μ‹œμ μ΄λΌκ³  λͺ…μ‹œν•œ μ •μ˜ μ€‘μ—μ„œλ§Œ λ³€ν™˜ ν•¨μˆ˜λ₯Ό μ°ΎλŠ”λ‹€.

μŠ€μ½”ν”„ κ·œμΉ™: μ‚½μž…λœ implicit λ³€ν™˜μ€ μŠ€μ½”ν”„ 내에 단일 μ‹λ³„μžλ‘œλ§Œ μ‘΄μž¬ν•˜κ±°λ‚˜, λ³€ν™˜μ˜ κ²°κ³Όλ‚˜ μ›λž˜ νƒ€μž…κ³Ό 연관이 μžˆμ–΄μ•Ό ν•œλ‹€.

μ•”μ‹œμ  λ³€ν™˜μ€ 단일 μ‹λ³„μžλ‘œλ§Œ μŠ€μ½”ν”„ μ•ˆμ— μ‘΄μž¬ν•΄μ•Ό ν•œλ‹€.

μ»΄νŒŒμΌλŸ¬λŠ” someVariable.convert 같은 ν˜•νƒœμ˜ λ³€ν™˜μ„ μ‚½μž…ν•˜μ§€ μ•ŠλŠ”λ‹€.

x + y λ₯Ό someVariable.convert(x) + y 둜 ν™•μž₯ν•˜μ§€ μ•ŠλŠ”λ‹€.

λ§Œμ•½ 이λ₯Ό μœ„ν•΄μ„œλŠ” someVariable.convert λ₯Ό 단일 μ‹λ³„μžλ‘œ κ°€λ₯΄ν‚¬ 수 있게 λ§Œλ“€μ–΄μ•Ό ν•œλ‹€.

단일 μ‹λ³„μžλŠ” ν•œ 가지 μ˜ˆμ™Έκ°€ μžˆλ‹€.

μ»΄νŒŒμΌλŸ¬λŠ” 원 νƒ€μž…μ΄λ‚˜ λ°˜ν™˜ κ²°κ³Ό νƒ€μž…μ˜ λ™λ°˜ 객체에 μžˆλŠ” μ•”μ‹œμ  μ •μ˜λ„ μ‚΄νŽ΄λ³Έλ‹€.


Β 




object Dollar {
  implicit def dollarToEuro(x: Dollar): Euro = ...
}

class Dollar { ... }

μ»΄νŒŒμΌλŸ¬λŠ” Dollar νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό λ‹€λ₯Έ νƒ€μž…μœΌλ‘œ λ³€ν™˜ν•  ν•„μš”κ°€ μžˆμ„ λ•Œλ§ˆλ‹€ 연관이 μžˆλŠ” λ³€ν™˜μ„ μ°ΎλŠ”λ‹€.

ν•œ λ²ˆμ— ν•˜λ‚˜λ§Œ κ·œμΉ™: 였직 ν•˜λ‚˜μ˜ μ•”μ‹œμ  μ„ μ–Έλ§Œ μ‚¬μš©ν•œλ‹€.

μ»΄νŒŒμΌλŸ¬λŠ” x + y λ₯Ό convert1(convert2(x)) + y 둜 λ³€ν™˜ν•˜μ§€ μ•ŠλŠ”λ‹€.

κ·Έλ ‡κ²Œ ν•˜λ©΄ 잘λͺ» μž‘μ„±ν•œ μ½”λ“œλ₯Ό μ»΄νŒŒμΌν•˜λŠ” μ‹œκ°„μ΄ 극적으둜 λŠ˜μ–΄λ‚˜κ³  ν”„λ‘œκ·Έλž˜λ¨Έκ°€ μž‘μ„±ν•œ μ½”λ“œμ™€ κ·Έ ν”„λ‘œκ·Έλž¨μ΄ μ‹€μ œ ν•˜λŠ” 일 μ‚¬μ΄μ˜ 차이가 컀진닀.

λͺ…μ‹œμ„± μš°μ„  κ·œμΉ™: μ½”λ“œκ°€ κ·Έ μƒνƒœ κ·ΈλŒ€λ‘œ νƒ€μž… 검사λ₯Ό ν†΅κ³Όν•œλ‹€λ©΄ μ•”μ‹œλ₯Ό ν†΅ν•œ λ³€ν™˜μ„ μ‹œλ„ν•˜μ§€ μ•ŠλŠ”λ‹€.

μ»΄νŒŒμΌλŸ¬λŠ” 이미 잘 μž‘λ™ν•˜λŠ” μ½”λ“œλ₯Ό λ³€κ²½ν•˜μ§„ μ•ŠλŠ”λ‹€.

μ•”μ‹œμ  λ³€ν™˜ 이름 뢙이기

μ•”μ‹œμ  λ³€ν™˜μ—λŠ” 아무 μ΄λ¦„μ΄λ‚˜ 뢙일 수 μžˆλ‹€.

이름이 λ¬Έμ œκ°€ λ˜λŠ”κ²ƒμ€ λ‹€μŒ 두 가지 뿐이닀.

  • λ©”μ„œλ“œ 호좜 μ‹œ λͺ…μ‹œμ μœΌλ‘œ λ³€ν™˜μ„ μ‚¬μš©ν•˜κ³  싢은 경우
  • ν”„λ‘œκ·Έλž¨μ˜ νŠΉμ • μ§€μ μ—μ„œ μ‚¬μš© κ°€λŠ₯ν•œ μ•”μ‹œμ  λ³€ν™˜μ΄ μ–΄λ–€ 것이 μžˆλŠ”μ§€ νŒŒμ•…ν•΄μ•Ό ν•˜λŠ” 경우
object MyConversions {
  implicit def stringWrapper(s: String):  IndexedSeq[Char] = ...
  implicit def intToString(x: Int): String = ...
}

stringWrapper λ³€ν™˜μ„ μ‚¬μš©ν•˜κ³  μ‹Άμ§€λ§Œ intToString λŠ” 막고 μ‹Άλ‹€.

import MyConversions.stringWrapper

μœ„ μ½”λ“œ 처럼 νŠΉμ • μ•”μ‹œμ  λ³€ν™˜λ§Œ μž„ν¬νŠΈν•œλ‹€.

μ•”μ‹œκ°€ μ“°μ΄λŠ” λΆ€λΆ„

  • 값을 μ»΄νŒŒμΌλŸ¬κ°€ μ›ν•˜λŠ” νƒ€μž…μœΌλ‘œ λ³€ν™˜ν•  λ•Œ
  • μ–΄λ–€ μ„ νƒμ˜ μˆ˜μ‹  객체λ₯Ό λ³€ν™˜ν•  λ•Œ
  • μ•”μ‹œμ  νŒŒλΌλ―Έν„°λ₯Ό 지정할 λ•Œ

21.3 μ˜ˆμƒ νƒ€μž…μœΌλ‘œμ˜ μ•”μ‹œμ  λ³€ν™˜

val i: Int = 3.5
<console>:4: error: type mismatch;
  found : Double(3.5)
  required: Int
  val i: Int = 3.5
                ^
implicit def doubleToInt(x: Double) = x.toInt

이제 이 μ½”λ“œλŠ” λ‹€μŒκ³Ό 같이 바뀐닀.

val i: Int = doubleToInt(3.5)

scala.Predef λŠ” λͺ¨λ“  슀칼라 ν”„λ‘œκ·Έλž¨μ— μ•”μ‹œμ μœΌλ‘œ μž„ν¬νŠΈ λœλ‹€.

더 μž‘μ€ 수 νƒ€μž…μ„ 더 큰 κ²ƒμœΌλ‘œ λ³€ν™˜ν•˜λŠ” μ•”μ‹œμ  λ³€ν™˜λ“€μ΄ λ“€μ–΄μžˆλ‹€.

implicit def int2double(x: Int): Double = x.toDouble  

21.4 호좜 λŒ€μƒ 객체 λ³€ν™˜

μ•”μ‹œμ  λ³€ν™˜μ„ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” λŒ€μƒμ΄ λ˜λŠ” 객체인 μˆ˜μ‹  객체에도 μ μš©ν•  수 μžˆλ‹€.

  1. μˆ˜μ‹  객체 λ³€ν™˜μ„ 톡해 μƒˆ 클래슀λ₯Ό κΈ°μ‘΄ 클래슀 계측ꡬ쑰에 λ§€λ„λŸ½κ²Œ 톡합 κ°€λŠ₯
  2. μ–Έμ–΄ μ•ˆμ—μ„œ λ„λ©”μΈμ˜ νŠΉν™” μ–Έμ–΄ (DSL) λ₯Ό λ§Œλ“œλŠ” 일을 지원

μƒˆ νƒ€μž…κ³Ό κΈ°μ‘΄ νƒ€μž… ν†΅ν•©ν•˜κΈ°

class Rational(n: Int, d: Int) {
  ...
  def + (that: Rational): Rational = ...
  def + (that: Int): Rational = ...
}
val oneHalf = new Rational(1, 2)

oneHalf + oneHalf

oneHalf + 1

// μ—λŸ¬
1 + oneHalf

μ•„λž˜μ™€ 같이 λ³€ν™˜μ„ λ§Œλ“€μ–΄ 두면 μˆ˜μ‹  객체듀이 λ‚˜λ¨Έμ§€ 처리λ₯Ό ν•΄μ€€λ‹€.

implicit def intToRational(x: Int) =  new Rational(x, 1)

1 + oneHalf

μƒˆλ‘œμš΄ 문법 흉내내기

μŠ€μΉΌλΌλŠ” μ•”μ‹œμ  λ³€ν™˜μ„ 톡해 μƒˆ 문법을 μΆ”κ°€ν•œ 것 처럼 흉내낼 수 μžˆλ‹€.

Map(1 -> "one", 2 -> "two", 3 -> "three")

-> λŠ” 문법이 μ•„λ‹Œ 슀칼라 ν”„λ¦¬μ— λΈ”μ—μ„œ μ§€μ›ν•˜λŠ” ArrowAssoc 클래슀의 λ©”μ„œλ“œμ΄λ‹€.

package scala

object Predef {
  class ArrowAssoc[A](x: A) {
    def -> [B](y: B): Tuple2[A, B] = Tuple2(x, y)
  }
  implicit def any2ArrowAssoc[A](x: A): ArrowAssoc[A] =
    new ArrowAssoc(x)
  ...
}

μ•”μ‹œμ  클래슀

μ•”μ‹œμ  ν΄λž˜μŠ€λŠ” implicit ν‚€μ›Œλ“œκ°€ 클래슀 μ„ μ–ΈλΆ€ μ•žμ— μžˆλŠ” ν΄λž˜μŠ€μ΄λ‹€.

case class Rectangle(width: Int, Height: Int)

implicit class RectangleMaker(width: Int){
  def x(height: Int) = Rectangle(width, height)
}

μœ„ μ½”λ“œλ₯Ό μΆ”κ°€ν•¨μœΌλ‘œμ¨ μ•„λž˜μ™€ 같이 λ„ˆλΉ„ 3 높이 4 의 μ‚¬κ°ν˜• 객체λ₯Ό μ‰½κ²Œ λ§Œλ“€μˆ˜ μžˆλ‹€.

val myRectangle = 3 x 4

μ•”μ‹œμ  ν΄λž˜μŠ€λŠ” μΌ€μ΄μŠ€ 클래슀 일 수 μ—†μœΌλ©° μ•”μ‹œμ  클래슀의 μƒμ„±μžμ—λŠ” νŒŒλΌλ―Έν„°κ°€ 1개만 μžˆμ–΄μ•Ό ν•œλ‹€.

21.5 μ•”μ‹œμ  νŒŒλΌλ―Έν„°

object Greeter {
  def greet(name: String)(
    // νŒŒλΌλ―Έν„° λͺ©λ‘μ— implicit λ₯Ό λͺ…μ‹œ
    implicit prompt: PreferredPrompt,
    drink: PreferredDrink
  ) {
    println("Welcome, "+ name +". The system is ready.")
    print("But while you work, ")
    println("why not enjoy a cup of "+ drink.preference +"?")
    println(prompt.preference)
  }
}

object JoesPrefs {
  // μ•”μ‹œμ  νŒŒλΌλ―Έν„°μ— implicit λ₯Ό λͺ…μ‹œ
  implicit val prompt = new PreferredPrompt("Yes, master> ")
  implicit val drink = new PreferredDrink("tea")
}

implicit ν‚€μ›Œλ“œλŠ” κ°œλ³„μ μΈ νŒŒλΌλ―Έν„°κ°€ μ•„λ‹ˆκ³  전체 νŒŒλΌλ―Έν„° λͺ©λ‘μ„ λ²”μœ„λ‘œ ν•œλ‹€.

μ•”μ‹œ νŒŒλΌλ―Έν„°μ— λŒ€ν•œ μŠ€νƒ€μΌ κ·œμΉ™

μ•”μ‹œμ  νŒŒλΌλ―Έν„° νƒ€μž…μ€ μΌλ°˜μ μ΄μ§€ μ•ŠλŠ” νŠΉλ³„ν•œ 이름을 μ‚¬μš©ν•œλ‹€.

def maxListPoorStyle[T](elements: List[T])(implicit orderer: (T, T) => Boolean): T

λͺ…μ‹œμ μœΌλ‘œ νƒ€μž…μ— λŒ€ν•œ μ–΄λ– ν•œ 정보도 μ œκ³΅ν•˜μ§€ μ•ŠμœΌλ©° ν”ν•œ νƒ€μž…μ΄κΈ° λ•Œλ¬Έμ— μ»΄νŒŒμΌλŸ¬μ—μ„œ μ‹€μˆ˜λ‘œ μ΄μƒν•œ κ°’μ˜ μ•”μ‹œμ  νŒŒλΌλ―Έν„°λ₯Ό λ„£μ„μˆ˜ μžˆλ‹€.

μ•”μ‹œμ  νŒŒλΌλ―Έν„° νƒ€μž…μ€ μ—­ν™œμ„ μ•Œλ € 쀄 수 μžˆλŠ” μ΅œμ†Œν•œ ν•˜λ‚˜μ˜ 이름을 μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

21.6 λ§₯락 λ°”μš΄λ“œ

def maxListOrdering[T](elements: List[T])(implicit ordering: Ordering[T]): T =
  elements match {
    case List() =>
      throw new IllegalArgumentException("empty list!")
    case List(x) => x
    case x :: rest =>
      // ordering 을 μ•”μ‹œμ μœΌλ‘œ μ‚¬μš©
      val maxRest = maxListOrdering(rest)
      // λͺ…μ‹œμ μœΌλ‘œ ordering 을 μ‚¬μš©
      if (ordering.gt(x, maxRest)) x
      else maxRest
  }

μ•”μ‹œμ  λ³€ν™˜μ„ μ—†μ• λŠ” 방법은 ν‘œμ€€ λΌμ΄λΈŒλŸ¬λ¦¬μ— μžˆλŠ” μ•„λž˜ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ ν•΄λ‹Ή 객체λ₯Ό ν˜ΈμΆœν•˜μ—¬ μ¦‰μ‹œ λŒλ €μ€€λ‹€.

def implicitly[T](implicit t: T) = t

λ§₯락 λ°”μš΄λ“œ (context bound) λŠ” νƒ€μž…μ˜ μ •μ˜λ₯Ό λ³€κ²½ν•˜μ§€ μ•Šκ³ λ„ 그것을 λ™μž‘ κ°€λŠ₯ν•˜κ²Œ μ§€μ›ν•œλ‹€.

def maxListOrdering[T: Ordering](elements: List[T]): T =
  elements match {
    case List() =>
      throw new IllegalArgumentException("empty list!")
    case List(x) => x
    case x :: rest =>
      val maxRest = maxListOrdering(rest)
      if (implicitly[Ordering[T]].gt(x, maxRest)) x
      else maxRest
  }

21.7 μ—¬λŸ¬ λ³€ν™˜μ„ μ‚¬μš©ν•˜λŠ” 경우

μŠ€μΉΌλΌλŠ” μ ˆλŒ€μ μœΌλ‘œ 더 ꡬ체적 이라면 μ»΄νŒŒμΌλŸ¬λŠ” 더 ꡬ체적인것을 선택 ν•œλ‹€.

  • μ „μžμ˜ 인자 νƒ€μž…μ΄ ν›„μžμ˜ μ„œλΈŒνƒ€μž…μ΄λ‹€.
  • 두 λ³€ν™˜ λͺ¨λ‘ λ©”μ„œλ“œμΈλ°, μ „μžλ₯Ό λ‘˜λŸ¬μ‹Ό ν΄λž˜μŠ€κ°€ ν›„μžλ₯Ό λ‘˜λŸ¬μ‹Ό 클래슀λ₯Ό ν™•μž₯ν•œλ‹€.
val cba = "abc".reverse
  1. "abc" λŠ” μ»¬λ ‰μ…˜μœΌλ‘œ λ³€ν™˜
  2. reverse λŠ” μ»¬λ ‰μ…˜μ„ λ°˜ν™˜
  3. cba λŠ” μ»¬λ ‰μ…˜μ„ λ°˜ν™˜
// false
"abc" == "abc".reverse.reverse

21.8 μ•”μ‹œ 디버깅

μ»΄νŒŒμΌλŸ¬κ°€ 찾지 λͺ»ν•˜λŠ” 경우 λ³€ν™˜μ„ λͺ…μ‹œμ μœΌλ‘œ 써본닀.

였λ₯˜μ˜ 원인 좔적이 쉽닀.

val chars: List[Char] = "xyz"


val chars: List[Char] = wrapString("xyz")

scala -Xprint:typer λ₯Ό μ‚¬μš©ν•˜λ©° λ‚΄λΆ€μ—μ„œ νƒ€μž… 검사 이후 μ†ŒμŠ€μ½”λ“œλ₯Ό 좜λ ₯ν•˜κ²Œ ν•œλ‹€.

21.9 κ²°λ‘ 

μŠ€μΉΌλΌμ—μ„œ μ•”μ‹œλŠ” κ°•λ ₯ν•˜λ©°, μ½”λ“œλ₯Ό μ••μΆ•ν•΄μ£ΌλŠ” κΈ°λŠ₯이닀.

μ•”μ‹œλ₯Ό λ„ˆλ¬΄ 자주 μ‚¬μš©ν•˜λ©΄ μ½”λ“œλ₯Ό μ΄ν•΄ν•˜κΈ° μ–΄λ €μ›Œμ§ˆ 수 μžˆλ‹€.

Chapter 22 리슀트 κ΅¬ν˜„

μŠ€μΉΌλΌμ—μ„œ κ°€μž₯ 널리 μ‚¬μš©λ˜λŠ” κ΅¬μ‘°ν™”λœ 데이터 νƒ€μž…μ΄λ‹€.

21.1 List 클래슀 κ°œκ΄„

슀칼라 리슀트의 클래슀 계측ꡬ쑰

Nil 객체

Nil κ°μ²΄λŠ” 빈 리슀트λ₯Ό μ •μ˜ν•œλ‹€.

Nil κ°μ²΄λŠ” List[Noting] 을 μƒμ†ν•œλ‹€.

:: 클래슀

final case class ::[T](hd: T, tl: List[T]) extends List[T] {
  def head = hd
  def tail = tl
  override def isEmpty: Boolean = false
}

μΆ”κ°€ λ©”μ„œλ“œ

def length: Int = 
  if (isEnpty) 0 else 1 + tail.length
def drop(n: Int): List[A] = 
  if (isEmpty) Nil
    else if (n <= 0) this
    else tail.drop(n - 1)
def map[B](f: A => B): List[B] = 
  if (isEmpty) Nil
    else f(head) :: tail.map(f) 

리슀트 ꡬ성

리슀트 ꡬ성 λ©”μ„œλ“œμΈ :: 와 ::: λŠ” 각각이 콜둠(πŸ˜ƒ 으둜 λλ‚˜κΈ° λ•Œλ¬Έμ— 였λ₯Έμͺ½ ν”Όμ—°μ‚°μžμ— 바인딩 λœλ‹€.

x :: xs κ°€ x.::(xs) κ°€ μ•„λ‹ˆκ³  xs.::(x) 호좜과 κ°™λ‹€.

:: λ©”μ„œλ“œλŠ” μ›μ†Ÿκ°’μ„ λ°›μ•„μ„œ μƒˆ 리슀트λ₯Ό λ§Œλ“€μ–΄ λ‚΄μ•Ό ν•œλ‹€.

abstract class Fruit
class Apple extends Fruit
class Orange extends Fruit
scala> val apples = new Apple :: Nil
apples: List[Apple] = List(Apple@585fa9)

scala> val fruits = new Orange :: apples
fruits: List[Fruit] = List(Orange@cd6798, Apple@585fa9)

리슀트의 μ •μ˜κ°€ 곡변적이기 λ•Œλ¬Έμ— λ©”μ„œλ“œ νŒŒλΌλ―Έν„°λ₯Ό λ°˜κ³΅λ³€μœΌλ‘œ ν•¨μœΌλ‘œμ¨ 더 μœ μ—°ν•˜κ³  μ•ˆμ •μ μœΌλ‘œ μ‚¬μš© κ°€λŠ₯ν•˜κ²Œ λ§Œλ“€μ–΄ μ€€λ‹€.

def ::[U >: T](x: U): List[U] = new scala.::(x, this)

슀칼라의 리슀트 ꡬ쑰

22.2 ListBuffer 클래슀

λ¦¬μŠ€νŠΈμ— λŒ€ν•œ μ „ν˜•μ μΈ μ ‘κ·Ό νŒ¨ν„΄μ€ μž¬κ·€μ μ΄λ‹€.

::: μ²˜λ¦¬λŠ” 첫 인자의 길이에 λΉ„λ‘€ν•˜λŠ” μ‹œκ°„μ„ κ°–κΈ° λ•Œλ¬Έμ— λΉ„νš¨μœ¨μ μ΄λ‹€.

리슀트 버퍼λ₯Ό μ‚¬μš©ν•˜λ©΄ μ›μ†Œλ₯Ό 좕적할 수 μžˆλ‹€.

Β 



var result = List[Int]()
for (x <- xs) result = result ::: List(x + 1)
result


Β 



import scala.collection.mutable.ListBuffer

val buf = new ListBuffer[Int]
for (x <- xs) buf += x + 1
buf.toList

22.3 μ‹€μ œ List 클래슀

λΉ„ 꼬리 μž¬κ·€ κ΅¬ν˜„κ³Ό 같은 μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš° λ¬Έμ œκ°€ 생길 κ²½μš°μ—λŠ” μ‹€μ œλ‘œ κ΅¬ν˜„ν•˜λŠ” List μ—μ„œλŠ” μž¬κ·€λ₯Ό νšŒν”Όν•˜κ³  리슀트 버퍼에 루프λ₯Ό μˆ˜ν–‰ν•˜λŠ” 방식을 μ„ νƒν•œλ‹€.

final override def map[B](f: A => B): List[B] = {
  if (this eq Nil) Nil else {
    val h = new ::[B](f(head), Nil)
    var t: :: [B] = h
    var rest = tail
    while (rest ne Nil) {
      val nx = new ::(f(rest.head), Nil)
      t.next = nx
      rest = rest.tail
    }
    h
  }
}
package scala.collection.immutable
class ListBuffer[A] extends Buffer[A] {
  private var first: List[A] = Nil
  private var list0: ::[A] = null
  private var aliased: Boolean = false
  ...
}

ListBuffer 의 νŠΉμ„±μ„ κ²°μ •ν•˜λŠ” 세가지 λΉ„κ³΅κ°œ ν•„λ“œλ₯Ό λ³Ό 수 μžˆλ‹€.

  • first: 버퍼에 μ €μž₯된 λͺ¨λ“  μš”μ†Œμ˜ 리슀트λ₯Ό κ°€λ₯΄ν‚¨λ‹€.
  • last0: 리슀트의 λ§ˆμ§€λ§‰ :: 셀을 가리킨닀.
  • aliased: toListλ₯Ό μ‚¬μš©ν•΄ 버퍼λ₯Ό 리슀트둜 λ°”κΎΌ 적이 μžˆλŠ”μ§€ ν‘œμ‹œν•œλ‹€.

22.4 μ™ΈλΆ€μ—μ„œ λ³Ό λ•ŒλŠ” ν•¨μˆ˜ν˜•

λ¦¬μŠ€νŠΈκ°€ μ™ΈλΆ€μ—μ„œλŠ” μ™„μ „νžˆ ν•¨μˆ˜μ μ΄μ§€λ§Œ, λ‚΄λΆ€μ—μ„œλŠ” 리슀트 버퍼λ₯Ό μ‚¬μš©ν•΄ λͺ…λ Ήν˜•μœΌλ‘œ λ˜μ–΄ μžˆλ‹€.

μ΄λŠ” μˆœμˆ˜ν•˜μ§€ μ•ŠλŠ” μ—°μ‚°μ˜ νš¨κ³Όκ°€ λ―ΈμΉ˜λŠ” λ²”μœ„λ₯Ό 주의깊게 μ œν•œν•¨μœΌλ‘œμ¨ ν•¨μˆ˜μ  μˆœμˆ˜μ„±μ„ 효율적으둜 λ‹¬μ„±ν•˜λ €λŠ” 것이닀.

val ys = 1 :: xs
val zs = 2 :: xs

ys 와 zs λŠ” 꼬리λ₯Ό κ³΅μœ ν•œλ‹€.

νš¨μœ¨μ„ μœ„ν•΄μ„œ ν•„μˆ˜μ μ΄λ©°, xs 에 μƒˆλ‘œμš΄ μ›μ†Œλ₯Ό μΆ”κ°€ν•  λ•Œλ§ˆλ‹€ 전체λ₯Ό 볡사해야 ν•œλ‹€λ©΄ 훨씬 λŠλ¦΄κ²ƒμ΄λ‹€.

// μŠ€μΉΌλΌμ—μ„œλŠ” λΆˆκ°€λŠ₯
ys.drop(2).tail = Nil

λΆ€μˆ˜ 효과둜 ys 와 zs λ¦¬μŠ€νŠΈλ„ 쀄어듀 수 μžˆλ‹€.

보톡 :: λŠ” λΆ„ν•  정볡 (divide-and-conquer) μŠ€νƒ€μΌμ˜ μž¬κ·€μ  μ•Œκ³ λ¦¬μ¦˜μ— 잘 λ§žμ•„ 떨어진닀.

리슀트 λ²„νΌλŠ” μ’€ 더 전톡적인 루프 μŠ€νƒ€μΌμ—μ„œ 많이 μ‚¬μš©ν•œλ‹€.

22.5 κ²°λ‘ 

λ¦¬μŠ€νŠΈλŠ” μŠ€μΉΌλΌμ—μ„œ κ°€μž₯ 많이 μ‚¬μš©ν•˜λŠ” 데이터 ꡬ쑰쀑 ν•˜λ‚˜μ΄λ©°, μ„Έλ°€ν•˜κ³  κ΅¬ν˜„λ˜μ–΄ μžˆλ‹€.

Chapter 23 for ν‘œν˜„μ‹ λ‹€μ‹œλ³΄κΈ°

case class Person(
  name: String,
  isMale: Boolean,
  children: Person*
)

val lara = Person("Lara", false)
val bob = Person("Bob", true)
val julie = Person("Julie", false, lara, bob)
val persons = List(lara, bob, julie)

λͺ¨λ“  μ—„λ§ˆμ™€ μžμ‹μ˜ μŒμ„ μ°Ύκ³  μ‹Άλ‹€.

persons 
  filter (p => !p.isMale) 
  flatMap (p => (p.children map (c => (p.name, c.name))))
persons 
  withFilter (p => !p.isMale) 
  flatMap (p => (p.children map (c => (p.name, c.name))))
for (
  p <- persons
  if !p.isMale
  c <- p.children
) yield (p.name, c.name)

이 μ‹λ“€μ˜ κ²°κ³ΌλŠ” μ™„μ „νžˆ κ°™λ‹€.

슀칼라 μ»΄νŒŒμΌλŸ¬λŠ” 두 번째 질의λ₯Ό 첫 번째 κ²ƒμœΌλ‘œ λ³€ν™˜ν•œλ‹€.

23.1 for ν‘œν˜„μ‹

일반적인 for ν‘œν˜„μ‹μ€ λ‹€μŒκ³Ό κ°™λ‹€.

for ( seq ) yield expr

μ—¬κΈ°μ„œ seq λŠ” μ œλ„ˆλ ˆμ΄ν„° (generator), μ •μ˜ (difinition), ν•„ν„° (filter) λ₯Ό λ‚˜μ—΄ν•œκ²ƒμ΄λ‹€.

for {
  p <- persons              // μ œλ„ˆλ ˆμ΄ν„°
  n = p.name                // μ •μ˜
  if (n startWith "To")     // ν•„ν„°
}

μ œλ„ˆλ ˆμ΄ν„°μ˜ ν˜•νƒœλŠ” λ‹€μŒκ³Ό κ°™λ‹€.

pat <- expr

expr 은 리슀트λ₯Ό λ°˜ν™˜ν•œλ‹€.

μ •μ˜μ˜ ν˜•νƒœλŠ” λ‹€μŒκ³Ό κ°™λ‹€.

pat = expr

pat νŒ¨ν„΄μ„ expr 의 값에 λ°”μΈλ”©ν•œλ‹€. (val μ •μ˜ 같은 μ—­ν™œμ„ ν•œλ‹€.)

ν•„ν„°μ˜ ν˜•νƒœλŠ” λ‹€μŒκ³Ό κ°™λ‹€.

if expr

μ—¬κΈ°μ„œ expr 은 Boolean 의 값이닀. ν•„ν„°λŠ” expr 이 false ν•˜λŠ” 값을 μ΄ν„°λ ˆμ΄μ…˜μ—μ„œ μ œμ™Έν•˜λ„λ‘ λ§Œλ“ λ‹€.

23.2 n μ—¬μ™• 문제

μ±… μ˜ˆμ œμ½”λ“œ 및 μ„€λͺ… μ°Έκ³ 

23.3 for μ‹μœΌλ‘œ μ§ˆμ˜ν•˜κΈ°

case class Book(title: String, authors: String*)
val books: List[Book] =
  List(
    Book(
      "Structure and Interpretation of Computer Programs",
      "Abelson, Harold", "Sussman, Gerald J."
    ),
    Book(
      "Principles of Compiler Design",
      "Aho, Alfred", "Ullman, Jeffrey"
    ),
    Book(
      "Programming in Modula-2",
      "Wirth, Niklaus"
    ),
    Book(
      "Elements of ML Programming",
      "Ullman, Jeffrey"
    ),
    Book(
      "The Java Language Specification", "Gosling, James",
      "Joy, Bill", "Steele, Guy", "Bracha, Gilad"
    )
  )

μž‘μ‚¬μ˜ 성이 Gosling인 λͺ¨λ“  μ±…μ˜ 제λͺ©μ„ μ°ΎλŠ”λ‹€.

for (
  b <- books
  a <- b.authors
  if a startsWith "Gosling"
) yield b.title

제λͺ©μ— "Program" μ΄λΌλŠ” λ¬Έμžμ—΄μ΄ λ“€μ–΄κ°„ λͺ¨λ“  μ±…μ˜ 제λͺ©μ„ μ°ΎλŠ”λ‹€.

for (
  b <- books
  if (b.title indexOf "Program") >= 0
) yield b.title

μ΅œμ†Œν•œ 두 ꢌ μ΄μƒμ˜ 책을 μ“΄ μž‘κ°€λ₯Ό λͺ¨λ‘ μ°ΎλŠ”λ‹€.

for (
  b1 <- books
  b2 <- books 
  if b1 != b2
  a1 <- b1.authors
  a2 <- b2.authors 
  if a1 == a2
) yield a1

23.4 for ν‘œν˜„μ‹ λ°˜ν™˜

μ œλ„ˆλ ˆμ΄ν„°κ°€ ν•˜λ‚˜λ°–μ— μ—†λŠ” for ν‘œν˜„μ‹μ˜ λ³€ν™˜

for ( x <- expr1 ) yield expr2

μœ„ μ½”λ“œλŠ” μ•„λž˜μ™€ 같이 λ³€ν™˜

expr1. map( x => expr2 )

μ œν„°λ ˆμ΄ν„°λ‘œ μ‹œμž‘ν•˜κ³  ν•„ν„°κ°€ ν•˜λ‚˜ μžˆλŠ” for ν‘œν˜„μ‹μ˜ λ³€ν™˜

for (
  x <- expr1 
  if expr2
) yield expr3

μœ„ μ½”λ“œλŠ” μ•„λž˜μ™€ 같이 λ³€ν™˜

for (x <- expr1 withFilter (x => expr2 )) yield expr3

for ν‘œν˜„μ‹μ„ λ³€ν™˜

expr1 withFilter ( x=>expr2 ) map ( x => expr3 )

μ œλ„ˆλ ˆμ΄ν„° 2개둜 μ‹œμž‘ν•˜λŠ” for ν‘œν˜„μ‹μ˜ λ³€ν™˜

for (x <- expr1 ; y <- expr2; seq) yield expr3

μœ„ μ½”λ“œλŠ” μ•„λž˜μ™€ 같이 λ³€ν™˜

expr1.flatMap(x => for (y <- expr2; seq) yield expr3  

μ œλ„ˆλ ˆμ΄ν„°μ— μžˆλŠ” νŒ¨ν„΄μ˜ λ³€ν™˜

for ((x1,  ..., xn) <- expr1) yield expr2

μœ„ μ½”λ“œλŠ” μ•„λž˜μ™€ 같이 λ³€ν™˜

expr1.map { 
  case (x1, ... , xn) => expr2 
}

μ •μ˜ λ³€ν™˜

for ( x <- expr1; y = expr2; seq) yield expr3

μœ„ μ½”λ“œλŠ” μ•„λž˜μ™€ 같이 λ³€ν™˜

for ((x, y) <- for (x <- expr1) yield (x, expr2); seq) yield expr3

for 루프 λ³€ν™˜

for (x <- expr1) body

μœ„ μ½”λ“œλŠ” μ•„λž˜μ™€ 같이 λ³€ν™˜

expr1 foreach (x => body)

23.5 μ—­λ°©ν–₯ 적용

λͺ¨λ“  for ν‘œν˜„μ‹μ€ map, flatMap, filter κ³ μ°¨ ν•¨μˆ˜ 호좜둜 λ³€ν™˜ν•  수 μžˆλ‹€

ν•˜μ§€λ§Œ κ·Έ λ°˜λŒ€λ‘œλ„ κ°€λŠ₯ν•˜λ‹€.

object Demo {
  def map[A, B](xs: List[A], f: A => B): List[B] =
    for (x <- xs) yield f(x)

  def flatMap[A, B](xs: List[A], f: A => List[B]): List[B] =
    for (x <- xs; y <- f(x)) yield y

  def filter[A](xs: List[A], p: A => Boolean): List[A] =
    for (x <- xs if p(x)) yield x
}

23.6 for μΌλ°˜ν™”

for ν‘œν˜„μ‹μ€μ˜ λ³€ν™˜μ€ 였직 map, flatMap, filter λ©”μ„œλ“œμ—λ§Œ μ˜μ‘΄ν•œλ‹€.

λ”°λΌμ„œ for ν‘œκΈ°λ²•μ„ λ‹€μ–‘ν•œ 데이터 νƒ€μž…μ— μ μš©ν•  수 μžˆλ‹€.

λ¦¬μŠ€νŠΈμ™€ λ°°μ—΄μ—λŠ” for loop 도 μ‚¬μš©μ΄ κ°€λŠ₯ν•˜λ‹€.

for ν‘œν˜„μ‹μ˜ μ™„λ²½ν•œ 지원을 μœ„ν•œ μ „ν˜•μ μΈ μ„€μ •

abstract class C[A] {
  def map[B](f: A => B): C[B]
  def flatMap[B](f: A => C[B]): C[B]
  def withFilter(p: A => Boolean): C[A]
  def foreach(b: A => Unit): Unit
}

23.7 κ²°λ‘ 

for ν‘œν˜„μ‹μ˜ λ‚΄λΆ€λ₯Ό μ‚΄νŽ΄λ³΄μ•˜λ‹€.

for ν‘œν˜„μ‹μ„ μ§€μ›ν•˜λ„λ‘ κ΅¬ν˜„ν•˜λŠ” 방법을 μ‚΄νŽ΄λ³΄μ•˜λ‹€.

Chapter 24 μ»¬λ ‰μ…˜ μžμ„Ένžˆ 듀여닀보기

μ±… μ°Έκ³ 

Chapter 25 슀칼라 μ»¬λ ‰μ…˜ μ•„ν‚€ν…μ²˜