2μ£Όμ°¨ (6 ~ 10 Chapter)

Chapter 06 ν•¨μˆ˜ν˜• 객체

μ§€κΈˆκΉŒμ§€ 슀칼라의 기본적인 λ‚΄μš©μ„ μ΄ν•΄ν–ˆλ‹€λ©΄, μ΄μ œλŠ” μ’€ 더 μ™„μ „ν•œ κΈ°λŠ₯을 κ°–μΆ˜ 슀칼라의 클래슀 μž‘μ„±λ²•μ„ μ•Œμ•„λ³Ό 차둀이닀.

클래슀 νŒŒλΌλ―Έν„°, μƒμ„±μž, λ©”μ„œλ“œ, μ—°μ‚°μž, λΉ„κ³΅κ°œ 멀버, μ˜€λ²„λΌμ΄λ“œ, μ„ κ²° 쑰건 확인, μ˜€λ²„λ‘œλ“œ, 자기 μ°Έμ‘° 같은 슀칼라의 객체지ν–₯ ν”„λ‘œκ·Έλž˜λ° μš”μ†Œλ₯Ό μ„€λͺ…ν•  것이닀.

6.1 λΆ„μˆ˜ 클래슀 λͺ…μ„Έ

이번μž₯ λΆ€ν„°λŠ” λΆ„λͺ¨ 클래슀λ₯Ό λ§Œλ“€μ–΄ 진행해보겠닀.

일반적으둜 μˆ˜ν•™μ—μ„œμ˜ λΆ„μˆ˜μ˜ 연산을 μ‚΄νŽ΄λ³΄λ©΄ 각 λΆ„λͺ¨μ˜ μΌμΉ˜ν•˜λŠ” μž‘μ—…μ„ 톡해 연산을 μˆ˜ν–‰ν•œλ‹€.

λ”°λΌμ„œ μˆ˜ν•™μ˜ λΆ„μˆ˜λ₯Ό μ½”λ“œμ μœΌλ‘œ ν•΄μ„ν•˜λ©΄ λ³€κ²½ κ°€λŠ₯ν•œ μƒνƒœκ°€ μ—†μŒμ„ μ•Œ 수 μžˆλ‹€.

λ‹€μŒμ€ 이λ₯Ό μ½”λ“œλ‘œ ν‘œν˜„ν•œ 방식이닀.

val oneHalf = new Rational(1, 2)

val twoThirds = new Rational(2, 3)

(oneHalf / 7) + (1 - twoThireds)

6.2 Rational 생성

μˆ˜ν•™μ˜ λΆ„μˆ˜μ—μ„œ 처럼 Rational 객체λ₯Ό μ‚¬μš©ν•˜λ„λ‘ λ³€κ²½ λΆˆκ°€λŠ₯ν•œ 객체둜 μ‚¬μš©ν•˜μž.

class Rational(n: Int, d: Int)

클래슀 이름인 Rational 뒀에 κ·Έ μ•ˆμ—λŠ” n, d μ΄λΌλŠ” μ‹λ³„μžκ°€ μžˆλ‹€.

이λ₯Ό 클래슀 νŒŒλΌλ―Έν„° (class parameter) 라고 λΆ€λ₯Έλ‹€.

클래슀 νŒŒλΌλ―Έν„°μ™€ 같은 λ‘₯ 인자λ₯Ό λ°›λŠ” μ£Ό μƒμ„±μž (primary constructor) λ₯Ό λ§Œλ“ λ‹€.

λ³€κ²½ λΆˆκ°€λŠ₯ν•œ 객체의 μž₯단점
λ³€κ²½ λΆˆκ°€λŠ₯ν•œ 객체의 μž₯점은 λ§Žμ§€λ§Œ κ°€μž₯ 큰 단점은 κ·Έ μžλ¦¬μ—μ„œ μƒνƒœλ₯Ό λ°”λ‘œ λ³€κ²½ν•˜λ©΄ κ°„λ‹¨ν•œλ°
κ±°λŒ€ κ·Έλž˜ν”„ 객체λ₯Ό 볡사해야 ν•˜λŠ” 경우처럼 λ§Žμ€ λΉ„μš©μ΄ λ“œλŠ” μž‘μ—…μ„ μˆ˜ν–‰ν•  λ•Œ ν•΄λ‹Ή μ•Œκ³ λ¦¬μ¦˜μ„ ν‘œν˜„ν•˜κΈ°μ—λ„ μ–΄λ €μš°λ©° μ„±λŠ₯μƒμ˜ μ΄μŠˆκ°€ λ°œμƒν•˜κΈ°λ„ ν•œλ‹€.
λ•Œλ¬Έμ— μŠ€μΉΌλΌμ—μ„œλŠ” λ³€κ²½ λΆˆκ°€λŠ₯ν•œκ²ƒκ³Ό λ³€κ²½ κ°€λŠ₯ν•œκ²ƒμ„ 항상 같이 μ œκ³΅ν•œλ‹€.

6.3 toString λ©”μ„œλ“œ λ‹€μ‹œ κ΅¬ν˜„ν•˜κΈ°

μžλ°”μ™€ 같이 toString λ©”μ„œλ“œλ₯Ό Rational ν΄λž˜μŠ€μ— μΆ”κ°€ν•˜λ©΄ κΈ°μ‘΄ κ΅¬ν˜„μ„ μ˜€λ²„λΌμ΄λ”© ν•  수 μžˆλ‹€.

class Rational(n: Int, d: Int) {
  override def toString = s"$n/$d"
}

μΈν„°ν”„λ¦¬ν„°μ—μ„œλŠ” λ‹€μŒκ³Ό 같이 확인이 κ°€λŠ₯ν•˜λ‹€.

val x = new Rational(1, 3)
// x: Rational = 1/3

val y = new Rational(5/7)
// y: Rational = 5/7

6.4 μ„ κ²° 쑰건 확인

require λŠ” 선결쑰건을 λ§Œλ“€κΈ° μœ„ν•œ μ—¬λŸ¬κ°€μ§€ 방법 쀑 ν•˜λ‚˜μ΄λ©°

μ£Ό μƒμ„±μžμ— μžˆλŠ” νŒŒλΌλ―Έν„°λ₯Ό 검증할 λ•Œ μœ μš©ν•˜λ‹€.

class Rational(n: Int, d: Int) {
  require(d != 0)
  override def toString = s"$n/$d"
}

require λ©”μ„œλ“œλŠ” 인자둜 Boolean 값을 λ°›λŠ”λ°, 이 값이 μ°Έ (true) 이면 require 값이 μ •μƒμ μœΌλ‘œ λλ‚˜κ³  λ‹€μŒμœΌλ‘œ μ§„ν–‰ν•œλ‹€.

λ§Œμ•½ 전달 받은 값이 거짓 (false) 이라면 IllegalArgumentException μ˜ˆμ™Έκ°€ λ°œμƒν•˜μ—¬ 객체 생성을 λ§‰λŠ”λ‹€.

6.5 ν•„λ“œ μΆ”κ°€

class Rational(n: Int, d: Int) {
  require(d != 0)
  override def toString = s"$n/$d"
  def add(that: Rational): Rational = 
    new Rational(n * that.d + that.n * d, d * that.d)
}

μœ„ μ½”λ“œλŠ” 컴파일 였λ₯˜κ°€ λ°œμƒν•œλ‹€.

Rational 객체 λΆ„λͺ¨, λΆ„μž 값에 μ ‘κ·Όν•˜κΈ° μœ„ν•΄μ„œλŠ” ν•„λ“œλ‘œ λ§Œλ“€μ–΄μ•Ό ν•œλ‹€.

ν•„λ“œλ₯Ό μΆ”κ°€ν•˜μ—¬ ν•΄κ²°ν•œ ν˜•νƒœλŠ” λ‹€μŒκ³Ό κ°™λ‹€.

class Rational(n: Int, d: Int) {
  require(d != 0)

  val numer: Int = n
  val denom: Int = d

  override def toString = s"$n/$d"

  def add(that: Rational): Rational = 
    new Rational(
      numer * that.denom + that.numer * denom,
      denom * that.denom
    )
}

이전과 달리 객체 λ°”κΉ₯μ—μ„œ ν•„λ“œλ₯Ό 톡해 λΆ„μžμ™€ λΆ„λͺ¨κ°’에 μ ‘κ·Όν•  수 μžˆλ‹€.

6.6 자기 참쑰

싀행쀑인 λ©”μ„œλ“œμ˜ 호좜 λŒ€μƒ μΈμŠ€ν„΄μŠ€μ— λŒ€ν•œ μ°Έμ‘°λ₯Ό 자기 μ°Έμ‘° (self reference) 라고 ν•œλ‹€.

def lessThan(that: Rational) = 
  this.numer * that.denom < that.numer * this.denom

μœ„ μ½”λ“œμ—μ„œ this λ₯Ό λΉΌκ³  numer 라고 써도 κ°™λ‹€.

6.7 보쑰 μƒμ„±μž

μŠ€μΉΌλΌμ—μ„œ μ£Ό μƒμ„±μžκ°€ μ•„λ‹Œ λ‹€λ₯Έ μƒμ„±μžλ₯Ό 보쑰 μƒμ„±μž (auxiliary constructor) 라고 ν•œλ‹€.

class Rational(n: Int, d: Int) {
  require(d != 0)
  
  val numer: Int = n
  val denom: Int = d
  
  def this(n: Int) = this(n, 1) // 보쑰 μƒμ„±μž

  override def toString = s"$n/$d"

  def add(that: Rational): Rational = 
    new Rational(
      numer * that.denom + that.numer * denom,
      denom * that.denom
    )
}

μŠ€μΉΌλΌμ—μ„œ 보쑰 μƒμ„±μžλŠ” def this(...) 라고 μ‹œμž‘ν•œλ‹€.

λͺ¨λ“  μƒμ„±μž ν˜ΈμΆœμ„ 거슬러 μ˜¬λΌκ°€λ©΄ κ²°κ΅­ μ£Ό μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜κ²Œ λ§Œλ“œλŠ” νš¨κ³Όκ°€ μžˆλ‹€.

6.8 λΉ„κ³΅κ°œ ν•„λ“œμ™€ λ©”μ„œλ“œ

μ΅œλŒ€ κ³΅μ•½μˆ˜λ₯Ό κ³„μ‚°ν•˜λŠ” λΉ„κ³΅κ°œ ν•„λ“œμ™€ λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•˜μž

class Rational(n: Int, d: Int) {
  require(d != 0)
  
  private val g = gcd(n.abs, d.abs)
  val numer: Int = n
  val denom: Int = d
  
  def this(n: Int) = this(n, 1) // 보쑰 μƒμ„±μž

  override def toString = s"$n/$d"

  def add(that: Rational): Rational = 
    new Rational(
      numer * that.denom + that.numer * denom,
      denom * that.denom
    )
}

첫 쀄에 λ“±μž₯ν•˜λŠ” g 의 μ΄ˆκΈ°ν™” μ½”λ“œ gcd(n.abs, d.abs) λŠ” λ‹€λ₯Έ 두 μ΄ˆκΈ°ν™” μ½”λ“œλ³΄λ‹€ λ¨Όμ € μ‹€ν–‰λœλ‹€.

λ•Œλ¬Έμ— μ΅œλŒ€κ³΅μ•½μˆ˜ g 둜 λ‚˜λ‰œ 값이 numer, denom λ₯Ό μ•½λΆ„μƒνƒœλ‘œ μ΄ˆκΈ°ν™” μ‹œμΌœμ€€λ‹€.

6.9 μ—°μ‚°μž μ •μ˜

μˆ˜ν•™μ  기호 + λŠ” λ©”μ„œλ“œ 이름을 μ •μ˜ν•˜λ©΄ add λ©”μ„œλ“œλ₯Ό λŒ€μ²΄ν•  수 μžˆλ‹€.

def + (that: Rational): Rational = 
  new Rational(
    numer * that.denom + that.numer * denom,
    denom * that.denom
  )

λ§ˆμ°¬κ°€μ§€λ‘œ κ³±μ…ˆ μ—°μ‚°μžμΈ * λ˜ν•œ times λ©”μ„œλ“œλ₯Ό λŒ€μ²΄ν•  수 μžˆλ‹€.

def * (that: Reational): Rational = 
  new Rational(numer * that.numer, denom * that.denom)

6.10 슀칼라의 μ‹λ³„μž

영숫자 μ‹λ³„μž (alphanumeric identifier)

  • λ¬Έμžλ‚˜ 밑쀄 (_) 둜 μ‹œμž‘ν•œλ‹€.

κ°„ν˜Ή λ°‘μ€„κ³Όλ‘œ λλ‚˜λŠ” μ‹λ³„μžμΌλ•Œ λ‹€μŒκ³Ό 같은 μ—λŸ¬λ₯Ό λ°œμƒ μ‹œν‚¬μˆ˜ μžˆλ‹€.

val name_:Int = 1

μœ„ 경우 name_:Int λ₯Ό λ³€μˆ˜λͺ…μœΌλ‘œ 컴파일 ν•˜λ € ν•˜κΈ° λ•Œλ¬Έμ— 콜둠 μ•žμ— 곡백을 ν•˜λ‚˜ 두어 λ‹€μŒκ³Ό 같이 μž‘μ„±ν•΄μ•Ό ν•œλ‹€.

val name_ :Int = 1

μ—°μ‚°μž μ‹λ³„μž (operator identifier)

ν•˜λ‚˜ μ΄μƒμ˜ μ—°μ‚°μž 문자둜 이루어져 μžˆλ‹€.

+ ++ ::: <?> :->

예λ₯Ό λ“€λ©΄ :-> λŠ” λ‚΄λΆ€μ μœΌλ‘œ $colon$minus$grater 둜 λ³€ν™˜λœλ‹€.

μžλ°”μ—μ„œ μ‚¬μš©ν•˜λ €κ³  ν•œλ‹€λ©΄ λ‚΄λΆ€ λ³€ν™˜ 이름을 μ•Œμ•„μ•Ό ν•œλ‹€.

ν˜Όν•© μ‹λ³„μž (mixed identifier)

영문과 숫자둜 이뀄진 μ‹λ³„μž 뒀에 밑쀄이 였고 κ·Έ 뒀에 μ—°μ‚°μž μ‹λ³„μžκ°€ μ˜¨λ‹€.

myvar_=

λ¦¬ν„°λŸ΄ μ‹λ³„μž (iteral identifier)

μ•„λž˜ μ½”λ“œμ²˜λŸΌ μ—­λ”°μ˜΄ν‘œ (`)둜 λ‘˜λŸ¬μ‹Ό μž„μ˜μ˜ λ¬Έμžμ—΄μ΄λ‹€.

`x` `<clinit>` `yield`

λŸ°νƒ€μž„μ΄ 인식할 수 μžˆλŠ” μ–΄λ–€ λ¬Έμžμ—΄μ΄λΌλ„ μ—­λ”°μ˜΄ν‘œ 사이에 넣을 수 μžˆλ‹€λŠ”κ²Œ 핡심이닀.

μ‹œμŠ€ν…œ μ˜ˆμ•½μ–΄λ₯Ό λ¬΄μ‹œν•  수 μžˆλŠ” λ°©λ²•μœΌλ‘œ μ”ŒμΈλ‹€.

Thread.`yield`()

6.11 λ©”μ„œλ“œ μ˜€λ²„λ‘œλ“œ

μŠ€μΉΌλΌμ—μ„œ μ²˜λ¦¬ν•˜λŠ” μ˜€λ²„λ‘œλ“œ λ©”μ„œλ“œλŠ” μžλ°”μ™€ 거의 μœ μ‚¬ν•˜λ‹€.

μŠ€μΉΌλΌλŠ” μ˜€λ²„λ‘œλ“œν•œ λ©”μ„œλ“œ 쀑 인자의 정적인 νƒ€μž…κ³Ό κ°€μž₯ 잘 μΌμΉ˜ν•˜λŠ” 버전을 μ„ νƒν•œλ‹€.

λ§Œμ•½ μΌμΉ˜ν•˜λŠ” κ²°κ³Όκ°€ 없을 경우 μ»΄νŒŒμΌλŸ¬λŠ” ambiguous reference 였λ₯˜λ₯Ό λ…ΈμΆœν•˜μ—¬ λͺ¨ν˜Έν•œ μ°Έμ‘°λΌλŠ” 사싀을 μ•Œλ¦°λ‹€.

6.12 μ•”μ‹œμ  νƒ€μž… λ³€ν™˜

μ•”μ‹œμ  νƒ€μž… λ³€ν™˜μ€ 라이브러리λ₯Ό μ’€ 더 μœ μ—°ν•˜κ³  μ‚¬μš©ν•˜κΈ° νŽΈλ¦¬ν•˜κ²Œ λ§Œλ“€μ–΄μ£ΌλŠ” μ•„μ£Ό κ°•λ ₯ν•œ 기법이닀.

ν•˜μ§€λ§Œ λ„ˆλ¬΄λ‚˜λ„ κ°•λ ₯ν•΄ 잘λͺ» μ‚¬μš©ν•˜κΈ°λ„ ν•œλ‹€.

μ—°μ‚°μž μ‹λ³„μžλ₯Ό μ΄μš©ν•˜μ—¬ r * 2 ν‘œν˜„μ„ μ‚¬μš©ν•  수 μžˆμ§€λ§Œ 2 * r 의 ν‘œν˜„μ€ 였λ₯˜λ₯Ό λ°œμƒ μ‹œν‚¨λ‹€.

μ΄λŠ” μ•”μ‹œμ  νƒ€μž…μœΌλ‘œ λ³€ν™˜ν•˜λŠ” κ³Όμ •μ—μ„œ r * 2 λŠ” r.*(2) 둜 λ°”λ€Œκ²Œ 되며 2 * r λŠ” 2.*(r) 둜 λ³€ν™˜λ˜μ–΄ Int ν΄λž˜μŠ€λŠ” Rational 인자λ₯Ό λ°›λŠ” κ³±μ…ˆ λ©”μ„œλ“œκ°€ μ—†κΈ° λ•Œλ¬Έμ΄λ‹€.

6.13 μ£Όμ˜μ‚¬ν•­

μŠ€μΉΌλΌλŠ” μ‰½κ²Œ μ‚¬μš©ν•  수 μžˆλŠ” 라이브러리 섀계λ₯Ό ν•  수 μžˆλŠ” λ§‰κ°•ν•œ κΆŒν•œμ„ μ£Όμ§€λ§Œ λ―Έμˆ™ν•˜κ²Œ μ‚¬μš©ν•˜λ©΄ μ—°μ‚°μž λ©”μ„œλ“œμ™€ μ•”μ‹œμ  νƒ€μž… λ³€ν™˜ λͺ¨λ‘ ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œλ₯Ό 읽고 μ΄ν•΄ν•˜κΈ° νž˜λ“€κ²Œ λ§Œλ“ λ‹€.

라이브러리λ₯Ό μ„€κ³„ν•˜λ©° 항상 염두에 두어야 ν•  λͺ©ν‘œλŠ” λ‹¨μˆœνžˆ ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œλ₯Ό κ°„κ²°ν•˜κ²Œ ν•˜λŠ”κ²ƒ 뿐만이 μ•„λ‹ˆλΌ, 가독성을 높이고 μ΄ν•΄ν•˜κΈ° μ‰½κ²Œ λ§Œλ“œλŠ” 법이닀.

6.14 κ²°λ‘ 

λ‹€μŒμž₯μ—μ„œλŠ” Rational 클래슀의 λ™λ°˜ 객체에 μ•”μ‹œμ  νƒ€μž… λ³€ν™˜μ„ λ„£μ–΄μ„œ νŽΈλ¦¬ν•˜κ²Œ μ‚¬μš©κ°€λŠ₯ν•œ μŠ€μ½”ν”„λ‘œ 뢈러올 수 있게 ν•˜λŠ” 방법을 μ„€λͺ…ν•˜κ² λ‹€.

Chapter 07 λ‚΄μž₯ μ œμ–΄ ꡬ문

슀칼라의 λ‚΄μž₯ μ œμ–΄ ꡬ문은 λͺ‡κ°€μ§€ μ—†λ‹€.

  • if
  • while
  • for
  • try
  • match
  • ν•¨μˆ˜ 호좜 (function call)

μŠ€μΉΌλΌμ— μ œμ–΄ ꡬ문의 μˆ˜κ°€ 적은 μ΄μœ λŠ” 섀계 μ΄ˆκΈ°λΆ€ν„° ν•¨μˆ˜ λ¦¬ν„°λŸ΄μ„ ν¬ν•¨ν–ˆκΈ° λ•Œλ¬Έμ΄λ‹€.

ν”„λ‘œκ·Έλž¨ 전체λ₯Ό 값을 κ³„μ‚°ν•˜λŠ” κ΄€μ μ—μ„œ 바라보고 ν”„λ‘œκ·Έλž¨ κ΅¬μ„±μš”μ†Œ λ˜ν•œ 값을 λ„μΆœν•΄μ•Ό ν•œλ‹€λŠ” ν•¨μˆ˜ 언어적 접근을 μ±„μš©ν•œ 결과이닀.

7.1 if ν‘œν˜„μ‹

슀칼라의 if ν‘œν˜„μ‹μ€ 값을 내놓기 λ•Œλ¬Έμ— 더 κ°„κ²°ν•˜κ²Œ μ½”λ“œ μž‘μ„±μ΄ κ°€λŠ₯ν•˜λ‹€.

val filename = 
  if (!args.isEmpty) args(0)
    else "default.txt"

μœ„ μ½”λ“œλŠ” μ§„μ§œ μž₯점은 var 이 μ•„λ‹Œ val 을 μ‚¬μš©ν–ˆλ‹€λŠ” 점이닀.

var 이 μ•„λ‹Œ val 을 μ‚¬μš©ν•¨μ— μžˆμ–΄μ„œ μž₯점은 동일성 μΆ”λ‘  (equational reasoning) 이 λ”μš± μœ λ¦¬ν•˜λ‹€.
λΆ€μˆ˜νš¨κ³Όκ°€ μ—†κΈ° λ•Œλ¬Έμ— 값을 λ„μΆœν•˜λŠ” ν‘œν˜„μ‹κ³Ό λ™μΌν•˜λ‹€.
val 을 μ‚¬μš©ν•  기회λ₯Ό 노리면 μ½”λ“œλ₯Ό 더 가독성이 λ†’κ³  λ¦¬νŽ™ν† λ§ ν•˜κΈ° μ‰¬μ›Œμ§„λ‹€.

7.2 while 루프

while λ£¨ν”„λŠ” κ²°κ³Όκ°€ νŠΉμ • 값이 μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— μˆœμˆ˜ν•œ ν•¨μˆ˜ν˜• μ–Έμ–΄λŠ” 이λ₯Ό μ’…μ’… μ œμ™Έν•˜κ³€ ν•œλ‹€.

ν•˜μ§€λ§Œ κ°„ν˜Ή λͺ…λ Ήν˜• 해법이 가독성이 λ›°μ–΄λ‚˜κΈ° λ•Œλ¬Έμ— νŠΉμ • 쑰건이 λ°”λ€”λ•ŒκΉŒμ§€ 정해진 μ ˆμ°¨λŒ€λ‘œ λ°˜λ³΅ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜μ„ μž‘μ„±ν•œλ‹€κ³  ν•˜λ©΄ while 루프가 λŒ€μ•ˆμ΄ 될 수 μžˆλ‹€.

일반적으둜 while λ£¨ν”„λŠ” var λ³€μˆ˜μ™€ λ§ˆμ°¬κ°€μ§€λ‘œ μ΅œλŒ€ν•œ 적게 μ‚¬μš©ν•˜κΈ° μœ„ν•΄ λ…Έλ ₯ν•˜λŠ”κ²ƒμ„ ꢌμž₯ν•œλ‹€.

νŠΉλ³„νžˆ while μ΄λ‚˜ do-while 루프λ₯Ό μ‚¬μš©ν•  μΆ©λΆ„ν•œ μ΄μœ κ°€ μ—†λ‹€λ©΄ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”κ²ƒμ„ ꢌμž₯ν•œλ‹€.

7.3 for ν‘œν˜„μ‹

슀칼라의 for ν‘œν˜„μ‹μ€ 반볡 처리λ₯Ό μœ„ν•œ 만λŠ₯ ν‘œν˜„μ‹μ΄λ‹€.

μ»¬λ ‰μ…˜ μ΄ν„°λ ˆμ΄μ…˜

for 둜 ν•  수 μž‡λŠ” κ°€μž₯ κ°„λ‹¨ν•œ 일은 λͺ¨λ“  μš”μ†Œλ₯Ό μ΄ν„°λ ˆμ΄μ…˜ν•˜λŠ” 것이닀.

val fileHere = (new java.io.File(".")).listFiels
for (file <- filesHere)
  println(file)

μ œλ„ˆλ ˆμ΄ν„° (generator) 라고 λΆ€λ₯΄λŠ” file <- filesHere 문법을 μ΄μš©ν•΄ filesHere μ›μ†Œλ₯Ό μ΄ν„°λ ˆμ΄μ…˜ ν•œλ‹€.

μ΄ν„°λ ˆμ΄μ…˜ λŒ€μƒ κ°’μ˜ λ²”μœ„μ—μ„œ μ΅œλŒ“κ°’μ„ μ œμ™Έν•˜κ³  μ‹Άλ‹€λ©΄ to λŒ€μ‹  until 을 μ‚¬μš©ν•œλ‹€.

for (i <- 1 until 4)
  println("Iteration " + i)
Iteration 1
Iteration 2
Iteration 3

필터링

for ν‘œν˜„μ‹μ— ν•„ν„° (filter) 을 μΆ”κ°€ν•˜λ©΄ 전체 μ»¬λ ‰μ…˜μ—μ„œ μΌλΆ€λ§Œ μ‚¬μš©ν•  수 μžˆλ‹€.

val filesHere = (new java.io.File(".")).listFiles

for (file <-filesHere if file.getName.endsWith(".scala))
  println(file)

λ§Œμ•½ μ—¬λŸ¬κ°œμ˜ ν•„ν„°λ₯Ό μ μš©ν•˜λ €λ©΄ λ‹€μŒκ³Ό 같이 μ‚¬μš©ν•˜λ©΄ λœλ‹€.

for (
  file <- filesHere
  if file.isFile
  if file.getName.endsWith(".scala")
) println(file)

쀑첩 μ΄ν„°λ ˆμ΄μ…˜

2개의 루프λ₯Ό μ€‘μ²©ν•œ λ¦¬μŠ€νŠΈλŠ” μ—¬λŸ¬κ°œμ˜ <- μ ˆμ„ μ΄μš©ν•˜μ—¬ 쀑첩루프λ₯Ό 생성할 수 μžˆλ‹€.

def fileLines(file: java.io.File) = 
  scala.io.Source.fromFile(file).getLines().toArray

def grep(pattern: String) =
  for (
    file <- filesHere
    if file.getName.endsWith(".scala");
    line <- fileLines(file)
    if line.trim.matches(pattern)
  ) println(s"$file: ${line.trim}")

grep(".*gcd.*")

λ°”κΉ₯μͺ½ λ£¨ν”„λŠ” filesHere λ‚΄μ˜ .scala 둜 λλ‚˜λŠ” νŒŒμΌμ„
μ•ˆμͺ½ λ£¨ν”„λŠ” λ°”κΉ₯λ£¨ν”„μ—μ„œ 얻은 file 에 fileLines(file) 을 ν˜ΈμΆœν•œ κ²°κ³Όλ₯Ό μ΄ν„°λ ˆμ΄μ…˜ ν•œλ‹€.

μ›ν•œλ‹€λ©΄ μ€‘κ΄„ν˜Έλ₯Ό μ‚¬μš©ν•˜μ—¬ μ œλ„ˆλ ˆμ΄ν„°μ™€ ν•„ν„°λ₯Ό 감싸도 λœλ‹€.
μ€‘κ΄„ν˜Έλ₯Ό μ‚¬μš©ν•œλ‹€λ©΄ 슀칼라 μ»΄νŒŒμΌλŸ¬κ°€ μ„Έλ―Έμ½œλ‘ μ„ μΆ”λ‘ ν•˜κΈ° λ•Œλ¬Έμ—, κ΄„ν˜Έλ₯Ό μ‚¬μš©ν•  λ•Œ μ¨μ•Όλ§Œ ν–ˆλ˜ μ„Έλ―Έμ½œλ‘ μ„ μ œκ±°ν•  수 μžˆλ‹€.

for 쀑에 λ³€μˆ˜ 바인딩 ν•˜κΈ°

μœ„ μ½”λ“œμ—μ„œ line.trim μ΄λΌλŠ” ν‘œν˜„μ‹μ„ λ°˜λ³΅ν•˜λŠ”λ° 이λ₯Ό λ³€μˆ˜λ‘œ λ°”μΈλ”©ν•˜μ—¬ 처리 κ°€λŠ₯ν•˜λ‹€.

def fileLines(file: java.io.File) = 
  scala.io.Source.fromFile(file).getLines().toArray

def grep(pattern: String) =
  for (
    file <- filesHere
    if file.getName.endsWith(".scala");
    line <- fileLines(file)
    trimmed = line.trim
    if trimmed.matches(pattern)
  ) println(s"$file: ${trimmed}")

grep(".*gcd.*")

μƒˆλ‘œμš΄ μ»¬λ ‰μ…˜ λ§Œλ“€μ–΄λ‚΄κΈ°

μ΄ν„°λ ˆμ΄μ…˜μ˜ 맀 반볡 λ‹¨κ³„μ˜ κ²°κ³Όλ₯Ό μ €μž₯ν•˜κΈ° μœ„ν•œ 값을 λ§Œλ“€ 수 μžˆλ‹€.

for ν‘œν˜„μ‹μ˜ λ³Έλ¬Έ μ•žμ— yield λΌλŠ” ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•œλ‹€.

def scalaFiles = 
  for {
    file <- filesHere
    if file.getName.endsWith(".scala")
  } yield file

μœ„ μ½”λ“œλŠ” for ν‘œν˜„μ‹μ„ μˆ˜ν–‰ν•  λ•Œλ§ˆλ‹€ κ°’ (file) 을 ν•˜λ‚˜μ”© λ§Œλ“€μ–΄λ‚Έλ‹€.

7.4 try ν‘œν˜„μ‹μœΌλ‘œ μ˜ˆμ™Έ 닀루기

ν˜ΈμΆœν•œ λ©”μ„œλ“œκ°€ 별닀λ₯Έ 처리λ₯Ό ν•˜μ§€ μ•Šκ³  μ’…λ£Œν•˜λ©΄ ν•΄λ‹Ή λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œ λ©”μ„œλ“œ, 즉 호좜자의 호좜자 λ©”μ„œλ“œλ‘œ μ˜ˆμ™Έλ₯Ό μ „νŒŒν•œλ‹€.

이λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄ try ν‘œν˜„μ‹μœΌλ‘œ μ²˜λ¦¬ν•œλ‹€.

μ˜ˆμ™Έ λ°œμƒ μ‹œν‚€κΈ°

μžλ°”μ™€ λ™μΌν•˜κ²Œ throw ν‚€μ›Œλ“œλ₯Ό μ΄μš©ν•˜μ—¬ μ˜ˆμ™Έλ₯Ό λ˜μ§„λ‹€.

throw new IllegalArgumentException
val half = 
  if (n % 2 == 0)
    n / 2
  else 
    throw new RuntimeException("n must be even")

μ˜ˆμ™ΈλŠ” Nothing μ΄λΌλŠ” νƒ€μž…μ„ κ°–λŠ”λ‹€.

λ°œμƒν•œ μ˜ˆμ™Έ 작기

νŒ¨ν„΄ 맀치 (pattern match)λ₯Ό μ΄μš©ν•˜μ—¬ λ°œμƒν•œ μ˜ˆμ™Έλ₯Ό μž‘λŠ”λ‹€.

try {
  val f = new FileReader("input.txt")
} catch {
  case e: FileNotFoundException => // νŒŒμΌμ„ λͺ» μ°ΎλŠ” 경우 처리
  case e: IOException => // κ·Έ 밖에 IO 였λ₯˜ 처리
}

finally 절

ν‘œν˜„μ‹μ˜ κ²°κ³Όκ°€ μ–΄λ–»λ“  νŠΉμ •μ½”λ“œλ₯Ό λ°˜λ“œμ‹œ μˆ˜ν–‰ν•˜κ³  싢은 경우 μ‚¬μš©

try {
  // νŒŒμΌμ„ μ‚¬μš©ν•œλ‹€.
} finally {
  file.close()
}

μŠ€μΉΌλΌμ—μ„œλŠ” λ™μΌν•œ λͺ©μ μ„ μ’€ 더 κ°„κ²°ν•˜κ²Œ λ‹¬μ„±ν•˜κΈ° μœ„ν•΄, 빌렀주기 νŒ¨ν„΄ (loan pattern) μ΄λΌλŠ” 기법을 μ‚¬μš©ν•  수 μžˆλ‹€.

κ°’ λ§Œλ“€μ–΄λ‚΄κΈ°

finally κ΅¬λ¬Έμ—μ„œλŠ” 값을 λ°˜ν™˜ν•˜μ§€ μ•ŠλŠ” 게 μ΅œμ„ μ΄λ‹€.

finally μ ˆμ€ 결괏값을 λ§Œλ“€μ–΄ λ‚΄κΈ° λ³΄λ‹€λŠ” νŒŒμΌμ„ λ‹«κ±°λ‚˜ μ •λ¦¬ν•˜λŠ” μž‘μ—…μ„ ν•˜λŠ”λ“± λΆ€μˆ˜νš¨κ³Όλ₯Ό μ œκ³΅ν•˜λŠ” 방법이라고 μƒκ°ν•˜λŠ”κ²Œ μ’‹λ‹€.

7.5 match ν‘œν˜„μ‹

슀칼라의 match ν‘œν˜„μ‹μ€ 여타 μ–Έμ–΄μ˜ swtich λ¬Έκ³Ό μœ μ‚¬ν•˜κ²Œ λ‹€μˆ˜μ˜ λŒ€μ•ˆ (alternative) 쀑 ν•˜λ‚˜λ₯Ό μ„ νƒν•˜κ²Œ ν•΄μ€€λ‹€.

val firstArg = if (args.length > 0) args(0) else ""

firstArg match {
  case "salt" => println("pepper")
  case "chips" => println("salsa")
  case "eggs" => println("bacon")
  case _ => println("huh?")
}

λͺ¨λ“  case λ§ˆλ‹€ break 문이 μ•”λ¬΅μ μœΌλ‘œ μžˆμ–΄μ„œ, break 문이 없어도 λ‹€μŒ μ„ νƒμœΌλ‘œ λ„˜μ–΄κ°€μ§€ μ•ŠλŠ”λ‹€.

7.6 break 와 continue λ¬Έ 없이 μ‚΄κΈ°

ν•¨μˆ˜ λ¦¬ν„°λŸ΄μ˜ μž₯점을 ν™œμš©ν•˜λ©΄ break λ‚˜ continue 없이 더 κ°„κ²°ν•œ μ½”λ“œ μž‘μ„±μ΄ κ°€λŠ₯ν•˜λ‹€.

λ§Œμ•½ κ·Έλž˜λ„ break 문이 ν•„μš”ν•˜λ‹€ μƒκ°λ˜λ©΄ scala.util.control 에 μžˆλŠ” Breaks ν΄λž˜μŠ€μ—μ„œ break λ©”μ„œλ“œλ₯Ό μ œκ³΅ν•œλ‹€.

import scala.util.control.Breaks._
import java.io._

val in = new BufferedReader(new InputStreamReader(System.in))

breakable {
  while (true) {
    println("? ")
    if (in.readLine() == "") break
  }
}

7.7 λ³€μˆ˜ μŠ€μ½”ν”„

μŠ€μΉΌλΌμ—μ„œ λ³€μˆ˜μ˜ μ •μ˜ν•˜λŠ” μŠ€μ½”ν”„ (scope) λ₯Ό 가진닀.

μžλ°”μ—μ„œ ν†΅μš©λ˜λŠ” μ§€μ—­λ³€μˆ˜ (local variable) κ°œλ…μ„ 가진닀.

λ³€μˆ˜λ“€μ΄ 말 κ·ΈλŒ€λ‘œ ν•¨μˆ˜ 내에 μ§€μ—­μ μœΌλ‘œ μ‘΄μž¬ν•˜λ©°, ν•¨μˆ˜κ°€ 호좜될 λ•Œλ§ˆλ‹€ μƒˆλ‘œμš΄ μ§€μ—­λ³€μˆ˜λ₯Ό λ§Œλ“€μ–΄μ„œ μ‚¬μš©ν•œλ‹€.

val a = 1;
{
  val a = 2;
  {
    println(a)
  }
}
2

μ€‘κ΄„ν˜Έλ₯Ό μ‚¬μš©ν•˜μ—¬ μŠ€μ½”ν”„λ₯Ό μƒˆλ‘œ λ§Œλ“€ 수 μžˆλ‹€.

7.8 λͺ…λ Ήν˜• μŠ€νƒ€μΌ μ½”λ“œ λ¦¬νŽ™ν† λ§

ν•¨μˆ˜ν˜• λ°©μ‹μœΌλ‘œ κ³°μ…ˆν‘œ λ§Œλ“€κΈ°

def makeRowSeq(row: Int) = 
  for (col <- 1 to 10) yield {
    val prod = (row * col).toString
    val padding = " " * (4 - prod.length)
    padding + prod
  }

def makeRow(row: Int) = makeRowSeq(row).mkString

def multiTable() = {
  val tableSeq = 
    for (row <- 1 to 10)
    yield makeRow(row)
  tableSeq.mkString("\n")
}

7.9 κ²°λ‘ 

슀칼라의 λ‚΄μž₯ μ œμ–΄ κ΅¬μ‘°λŠ” κ·Έ μˆ˜λŠ” μ μ§€λ§Œ μ—­ν™œμ„ μ œλŒ€λ‘œ μˆ˜ν–‰ν•œλ‹€.

λͺ…λ Ήν˜• 언어에 μ‘΄μž¬ν•˜λŠ” ꡬ문과 μœ μ‚¬ν•œ μ—­ν™œμ„ μˆ˜ν–‰ν•˜μ§€λ§Œ, 값이 κ²°κ³Όκ°€ λ˜λ„λ‘ μ˜λ„ν–ˆκΈ° λ•Œλ¬Έμ— ν•¨μˆ˜ν˜• μŠ€νƒ€μΌλ‘œλ„ μž‘μ„±μ΄ κ°€λŠ₯ν•˜λ‹€.

Chapter 08 ν•¨μˆ˜μ™€ ν΄λ‘œμ €

ν”„λ‘œκ·Έλž¨μ΄ 컀질수둝 관리가 κ°€λŠ₯ν•œ μž‘μ€ 쑰각으둜 λ‚˜λˆŒ 수 μžˆλŠ” 방법이 ν•„μš”ν•˜λ‹€.

μŠ€μΉΌλΌμ— μ‘΄μž¬ν•˜λŠ” μ—¬λŸ¬μ’…λ₯˜μ˜ ν•¨μˆ˜κ°€ μ§€λ‹Œ νŠΉμ§•μ„ μ•Œμ•„λ³΄μž.

8.1 λ©”μ„œλ“œ

ν•¨μˆ˜λ₯Ό μ •μ˜ν•˜λŠ” κ°€μž₯ ν”ν•œ 방법은 νŠΉμ • 객체의 멀버λ₯Ό ν•¨μˆ˜λ‘œ λ§Œλ“œλŠ” 것이닀.

객체의 멀버인 ν•¨μˆ˜λ₯Ό λ©”μ„œλ“œ (method) 라고 ν•œλ‹€.

8.2 지역 ν•¨μˆ˜

μŠ€μΉΌλΌλ„ μžλ°”μ²˜λŸΌ 잘 μ •μ˜ν•œ μž‘μ—…μ„ μž‘μ€ ν•¨μˆ˜ ν”„λ‘œκ·Έλž¨μœΌλ‘œ λ‚˜λ‰˜μ–΄ μœ μ—°ν•˜κ²Œ 쑰립할 수 μžˆλŠ” λΉŒλ”© 블둝 (building block) 을 μ œκ³΅ν•œλ‹€.

μžλ°”λŠ” μ ‘κ·Ό μ œμ–΄μžλ₯Ό ν†΅ν•œ λΉ„κ³΅κ°œ λ©”μ„œλ“œλ₯Ό μ΄μš©ν•˜μ§€λ§Œ μŠ€μΉΌλΌμ—μ„œλŠ” ν•¨μˆ˜μ•ˆμ— ν•¨μˆ˜λ₯Ό μ •μ˜ν•˜λŠ” λ°©λ²•μœΌλ‘œ μ •μ˜ν•  수 μžˆλ‹€.

def processFile(filename: String, width: Int) = {
  def processLine(filename: String, width: Int, line: String) = {
    if (line.length > width)
      println(filename + ": " + line.trim)
  }

  val source = Source.fromFile(filename)
  for (line <- source.getLines()) {
    processLine(filename, width, line)
  }
}

processLine λ©”μ„œλ“œλŠ” processfile λ‚΄λΆ€μ—μ„œλ§Œ μ ‘κ·Όν•  수 있으며, μ™ΈλΆ€μ—μ„œλŠ” 접근이 λΆˆκ°€λŠ₯ ν•˜λ‹€.

8.3 1κΈ‰ 계측 ν•¨μˆ˜

μŠ€μΉΌλΌλŠ” 1κΈ‰ 계측 ν•¨μˆ˜ (first class function) λ₯Ό μ œκ³΅ν•œλ‹€.

ν•¨μˆ˜λ₯Ό μ •μ˜ν•˜κ³  ν˜ΈμΆœν•  뿐만 μ•„λ‹ˆλΌ 이름없이 λ¦¬ν„°λŸ΄λ‘œ ν‘œκΈ°ν•΄ κ°’μ²˜λŸΌ 주고받을 수 μžˆλ‹€.

ν•¨μˆ˜ λ¦¬ν„°λŸ΄μ€ μ†ŒμŠ€ μ½”λ“œμ— μ‘΄μž¬ν•˜λŠ” 반면, ν•¨μˆ˜κ°’μ€ μ‹€ν–‰ μ‹œμ μ— 객체둜 μ‘΄μž¬ν•œλ‹€λŠ” 점에 μžˆλ‹€.

8.4 κ°„λ‹¨ν•œ ν˜•νƒœμ˜ ν•¨μˆ˜ λ¦¬ν„°λŸ΄

ν•¨μˆ˜ λ¦¬ν„°λŸ΄μ„ μ’€ 더 κ°„λ‹¨ν•˜κ²Œ λ§Œλ“œλŠ” 방법은 인자의 νƒ€μž…μ„ μ œκ±°ν•˜λŠ” 것이닀.

someNumbers.filter((x) => x > 0)

someNumbers λΌλŠ” μ •μˆ˜μ˜ 리슀트λ₯Ό κ±ΈλŸ¬λ‚΄λŠ” ν•„ν„° ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ—, 슀칼라 μ»΄νŒŒμΌλŸ¬λŠ” ν•¨μˆ˜ λ¦¬ν„°λŸ΄μ˜ μΈμžκ°€ xκ°€ μ •μˆ˜λΌλŠ” 사싀을 μ•ˆλ‹€.

이λ₯Ό νƒ€κ²Ÿ 타이핑 (target typing) 이라고 ν•˜λŠ”λ° ν‘œν˜„μ‹μ„ μ–΄λ–€ λ°©μ‹μœΌλ‘œ μ‚¬μš©ν•˜λŠλƒμ— 따라 μ»΄νŒŒμΌλŸ¬κ°€ μΆ”λ‘ ν•˜λŠ” νƒ€μž…μ΄ 달라지기 λ•Œλ¬Έμ΄λ‹€.

8.5 μœ„μΉ˜ ν‘œμ‹œμž 문법

ν•¨μˆ˜ λ¦¬ν„°λŸ΄μ„ μ’€ 더 κ°„κ²°ν•˜κ²Œ λ§Œλ“€κΈ° μœ„ν•΄ 밑쀄을 ν•˜λ‚˜ μ΄μƒμ˜ νŒŒλΌλ―Έν„°μ— μœ„μΉ˜ ν‘œμ‹œμžλ‘œ μ‚¬μš©ν•  수 μžˆλ‹€.

someNumbers.filter(_ > 0)

밑쀄을 μ±„μ›Œλ„£μ–΄μ•Ό ν•˜λŠ” 빈칸으둜 생각해도 μ’‹λ‹€.

λ•Œλ‘œλŠ” λ°‘μ€„μ˜ 인자의 μœ„μΉ˜ ν‘œμ‹œμžλ‘œ μ‚¬μš©ν•  λ•Œ μ»΄νŒŒμΌλŸ¬κ°€ 인자의 νƒ€μž… 정보λ₯Ό 찾지 λͺ»ν•  κ²½μš°κ°€ μžˆλ‹€.

이럴 κ²½μš°μ—λŠ” μ½œλ‘ μ„ μ΄μš©ν•˜μ—¬ νƒ€μž…μ„ λͺ…μ‹œν•΄μ£Όλ©΄ λœλ‹€.

val f = (_: Int) + (_: Int)

8.6 λΆ€λΆ„ 적용 ν•¨μˆ˜

전체 νŒŒλΌλ―Έν„° λͺ©λ‘μ„ λ°‘μ€„λ‘œ λ°”κΏ€μˆ˜λ„ μžˆλ‹€.

예λ₯Ό λ“€λ©΄ println(_) 이라고 쓰지 μ•Šκ³  println _ 이라고 μ“Έ 수 μžˆλ‹€.

def sum(a: Int, b: Int, c: Int) = a + b + c

val a = sum _

a(1, 2, 3)
// 6

μœ„ μ½”λ“œλŠ” 슀칼라 μ»΄νŒŒμΌλŸ¬κ°€ λΆ€λΆ„ 적용 ν•¨μˆ˜ ν‘œν˜„μ‹ sum _ μ—μ„œ 빠진 인자 3개λ₯Ό λ°›λŠ” ν•¨μˆ«κ°’μ„ μΈμŠ€ν„΄μŠ€ν™” ν•œλ‹€.

슀칼라 μ»΄νŒŒμΌλŸ¬λŠ” a(1, 2, 3) 의 ν•¨μˆ«κ°’μ˜ apply λ©”μ„œλ“œμ— λŒ€ν•œ 호좜둜 해석해 1, 2, 3을 μ „λ‹¬ν•œλ‹€.

λ”°λΌμ„œ a(1, 2, 3) 은 a.apply(1, 2, 3) 을 짧게 μ“΄ 것이닀.

λ‹€μŒκ³Ό 같이 ν•„μš”ν•œ μΈμžμ€‘ μΌλΆ€λ§Œ λ„˜κ²¨μ„œ λΆ€λΆ„ 적용 ν•¨μˆ˜λ₯Ό λ§Œλ“€ μˆ˜λ„ μžˆλ‹€.

val b = sum(1, _:Int, 3)

b(2)
// 6

μ•„λž˜λŠ” λ¦¬ν„°λŸ΄ ν…ŒμŠ€νŠΈμ™€ 객체 ν…ŒμŠ€νŠΈ ν–ˆμ„ 경우 결과이닀.

def makeIncreaser(more: Foo) = (x: Int) => x + more.f

var value = 1

val increaser = makeIncreaser(value)

value = 2

println(increaser(3))
// 4
case class Foo(var f: Int)

def makeIncreaser(more: Foo) = (x: Int) => x + more.f

val foo = Foo(1)

val increaser = makeIncreaser(foo)

foo.f = 2

println(increaser(3))
// 5

8.7 ν΄λ‘œμ €

주어진 ν•¨μˆ˜ λ¦¬ν„°λŸ΄λΆ€ν„° μ‹€ν–‰ μ‹œμ μ— λ§Œλ“€μ–΄λ‚Έ 객체인 ν•¨μˆ«κ°’ (객체) 을 ν΄λ‘œμ € (closure) 라고 ν•œλ‹€.

μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ ν΄λ‘œμ €μ™€ λΉ„μŠ·ν•  κ²ƒμœΌλ‘œ νŒλ‹¨.

8.8 νŠΉλ³„ν•œ ν˜•νƒœμ˜ ν•¨μˆ˜ 호좜

반볡 νŒŒλΌλ―Έν„°

반볡 κ°€λŠ₯ν•œ 인자λ₯Ό ν‘œκΈ°ν•˜λ €λ©΄ λ³„ν‘œ (*) λ₯Ό 인자의 νƒ€μž… λ‹€μŒμ— μΆ”κ°€ν•˜λ©΄ λœλ‹€.

def echo(args: String*) =
  for (arg <- args) println(arg)

echo()
echo("one")
echo("hello", "world")

배열을 반볡 인자둜 μ „λ‹¬ν•˜κΈ° μœ„ν•΄ λ‹€μŒκ³Ό 같이 콜둠 (πŸ˜ƒ 에 _* 기호λ₯Ό μΆ”κ°€ν•΄μ•Ό ν•œλ‹€.

aka. κ°€λ³€μΈμž

이름 뢙인 인자

이름 뢙인 인자λ₯Ό μ΄μš©ν•΄ ν˜ΈμΆœν•˜λ©΄ μΈμžλ“€μ˜ μˆœμ„œλ₯Ό λ°”κΎΈμ–΄ 전달해도 호좜의 μ˜λ―Έκ°€ λ³€ν•˜μ§€ μ•ŠλŠ”λ‹€.

def speed(distance: Float, time: Float): Float = 
  distance / time

speed(distance = 100, time = 10)

or 

speed(time = 10, distance = 100)

λ””ν΄νŠΈ μΈμž£κ°’

μŠ€μΉΌλΌμ—μ„œ νŒŒλΌλ―Έν„°μ˜ λ””ν΄νŠΈκ°’μ„ 지정할 수 μžˆλ‹€.

def printTime(
  out: java.io.PrintStream = Console.out,
  divisor: Int = 1
) = 
  outprintln("time = " + System.currentTimeMillis() / divisor)

νŠΉμ • νŒŒλΌλ―Έν„°λ₯Ό λͺ…μ‹œν•˜κ³  μ‹ΆμœΌλ©΄ λ‹€μŒκ³Ό 같이 ν˜ΈμΆœν•œλ‹€.

printTime(divisor = 1000)

8.9 꼬리 μž¬κ·€

λ§ˆμ§€λ§‰μ˜ μžμ‹ μ˜ μž¬κ·€ ν˜ΈμΆœν•˜λŠ” 경우λ₯Ό κΌ¬λ¦¬μž¬κ·€ (tail recursive) 라고 ν•œλ‹€.

문제λ₯Ό ν•΄κ²°ν• λ•Œ μž¬κ·€λ₯Ό μ‚¬μš©ν•˜λŠ” 것을 λ‘λ €μ›Œν•˜μ§€ μ•Šμ•„λ„ λœλ‹€. μž¬κ·€λ₯Ό μ‚¬μš©ν•˜λŠ” 해법이 루프λ₯Ό μ‚¬μš©ν•˜λŠ” 해법보닀 κ°„κ²°ν•˜κ³  μš°μ•„ν•œ κ²½μš°κ°€ μ’…μ’… μžˆλ‹€.

꼬리 μž¬κ·€ ν•¨μˆ˜ 좔적

꼬리 μž¬κ·€ ν•¨μˆ˜λŠ” μž¬κ·€ ν˜ΈμΆœλ§ˆλ‹€ μƒˆλ‘œμš΄ μŠ€νƒμ„ λ§ˆλ“€μ§€ μ•Šκ³  같은 μŠ€νƒ ν”„λ ˆμž„μ„ μž¬ν™œμš© ν•œλ‹€.

def boom(x: Int): Int = 
  if (x == 0) throw new Exception("boom!")
  else boom(x - 1) + 1

μœ„ μ½”λ“œμ˜ boom ν•¨μˆ˜λŠ” μž¬κ·€ 호좜 후에 λ”ν•˜κΈ° 연산을 μˆ˜ν–‰ν•˜κΈ° λ•Œλ¬Έμ— 꼬리 μž¬κ·€κ°€ μ•„λ‹ˆλ‹€.

μ‹€ν–‰ν•˜λ©΄ λ‹€μŒκ²°κ³Όλ₯Ό λ³Ό 수 μžˆλ‹€.

boom(3)
java.lang.Exception: boom!
    at .boom(<console>:5)
    at .boom(<console>:6)
    at .boom(<console>:6)
    at .boom(<console>:6)
    at .<init>(<console>:6)
...

boom 을 μˆ˜μ •ν•΄ 꼬리 μž¬κ·€λ‘œ λ§Œλ“€λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

def bang(x: Int): Int =
  if (x == 0) throw new Exception("bang!")
  else bang(x - 1)
bang(5)
java.lang.Exception: bang!
    at .bang(<console>:5)
    at .<init>(<console>:6)...

μ΄λ²ˆμ—λŠ” bang 에 단 ν•˜λ‚˜μ˜ μŠ€νƒλ§Œ 보인닀.

꼬리 μž¬κ·€μ˜ ν•œκ³„

JVM λͺ…λ Ήμ–΄ μ§‘ν•©λ§ŒμœΌλ‘œλŠ” κ³ μˆ˜μ€€μ˜ 꼬리 μž¬κ·€λ₯Ό κ΅¬ν˜„ν•˜κΈ°μ— 어렀움이 있기 λ•Œλ¬Έμ—, 슀칼라의 꼬리 μž¬κ·€ μ΅œμ ν™”μ—λŠ” ν•œκ³„κ°€ μžˆλ‹€.

꼬맂 μž¬κ·€ μ΅œμ ν™”λŠ” λ©”μ„œλ“œλ‚˜ 쀑첩 ν•¨μˆ˜κ°€ λ§ˆμ§€λ§‰ μ—°μ‚°μœΌλ‘œμ„œ μžμ‹ μ„ 직접 ν˜ΈμΆœν•˜λŠ” κ²½μš°μ—λ§Œ 이뀄진닀.

8.10 κ²°λ‘ 

슀칼라의 ν•¨μˆ˜λ₯Ό μ•Œμ•„λ³΄μ•˜λ‹€.

μŠ€μΉΌλΌλŠ” λ©”μ„œλ“œ 이외에도 μ§€μ—­ν•¨μˆ˜, ν•¨μˆ˜ λ¦¬ν„°λŸ΄, ν•¨μˆ«κ°’μ„ μ œκ³΅ν•˜λ©° 일반적인 ν•¨μˆ˜ 호좜 외에, λΆ€λΆ„ 적용 ν•¨μˆ˜μ™€ 반볡 μΈμžλ“±μ„ μ‚¬μš©ν•  수 μžˆλ‹€.

λ‹€μŒμž₯μ—μ„œλŠ” ν•¨μˆ˜μ˜ 지원을 ν†΅ν•œ νλ¦„μ œμ–΄λ₯Ό μ•Œμ•„λ³΄μž.

Chapter 09 흐름 μ œμ–΄ 좔상화

μŠ€μΉΌλΌμ—λŠ” λ‚΄μž₯ μ œμ–΄ 좔상화가 λ§Žμ§€ μ•Šλ‹€.

ν•˜μ§€λ§Œ μžμ‹ μ˜ κ³ μœ ν•œ μ œμ–΄ 좔상화λ₯Ό μž‘μ„±ν•  수 μžˆλ‹€.

9.1 μ½”λ“œ 쀑볡 쀄이기

ν•¨μˆ˜λ₯Ό 인자둜 λ°›λŠ” ν•¨μˆ˜λ₯Ό κ³ μ°¨ ν•¨μˆ˜ (higher-order function) 이라고 ν•˜λŠ”λ° 이λ₯Ό μ΄μš©ν•˜μ—¬ μ½”λ“œλ₯Ό 더 κ°™λ‹¨ν•˜κ²Œ μ••μΆ•ν•  수 μžˆλŠ” 기회λ₯Ό μ œκ³΅ν•œλ‹€.

κ³ μ°¨ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•  λ•Œμ˜ μž₯점 쀑 ν•˜λ‚˜λŠ” μžμ‹ λ§Œμ˜ μΆ”μƒν™”ν•œ 흐름 μ œμ–΄λ₯Ό μž‘μ„±ν•  수 μžˆμ–΄ μ½”λ“œμ˜ 쀑볡을 쀄일 수 μžˆλ‹€λŠ” 점이닀.

object FileMatcher {
  private def filesHere = (new java.io.File(".")).listFiles

  private def filesMatching(matcher: String => Boolean) = 
    for (file <- filesHere; if matcher(file.getName))
      yield file
  
  def fileEnding(query: String) =
    filesMatching(_.endsWith(query))

  def filesContaining(query: String) = 
    filesMatching(_.contains(query))

  def filesRegex(query: String) =
    filesMatching(_.matches(query))
}

9.2 ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œ λ‹¨μˆœν•˜κ²Œ λ§Œλ“€κΈ°

def containsOdd(nums: List[Int]) = nums.exists(_ % 2 == 1)

μœ„ μ½”λ“œμ™€ 같이 exists 와 같은 루프 λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ μ½”λ“œλ₯Ό 더 λ‹¨μˆœν•˜κ²Œ λ§Œλ“€μˆ˜ μžˆλ‹€.

9.3 컀링

def curriedSum(x: Int)(y: Int) = x + y

curriedSum(1)(2)
// 3

μœ„μ™€ 같이 ν•¨μˆ˜λ₯Ό μ—°μ†μ μœΌλ‘œ ν˜ΈμΆœν•˜μ—¬ 호좜 κ°€λŠ₯ν•œ 값을 λ°˜ν™˜ν•˜λŠ” 것이닀.

9.4 μƒˆλ‘œμš΄ μ œμ–΄ ꡬ쑰 μž‘μ„±

이전 try ~ catch ~ finally κ΅¬λ¬Έμ—μ„œ μ‚¬μš©ν–ˆλ˜ 방식을 μƒˆλ‘œμš΄ μ œμ–΄κ΅¬μ‘°λ‘œ λ³€κ²½ν•˜μ—¬ λ‹€μŒκ³Ό 같이 ν‘œν˜„ν•œλ‹€.

def widthPrintWriter(file: File, op: PrintWriter => Unit) = {
  val writer = new PrintWriter(file)
  try {
    op(writer)
  } finally {
    writer.close()
  }
}
withPrintWriter(
  new File("date.txt"),
  writer => writer.println(new java.util.Date)
)

μœ„ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 경우 withPrintWriter κ°€ 파일 λ‹«κΈ°λ₯Ό 보μž₯ν•œλ‹€λŠ” μž₯점이 μžˆλ‹€.

μ œμ–΄ 좔상화λ₯Ό ν•˜λŠ” ν•¨μˆ˜κ°€ μžμ›μΌ μ—΄μ–΄ νŠΉμ • ν•¨μˆ˜μ—κ²Œ ν•΄λ‹Ή μžμ›μ„ 빌렀주기 λ•Œλ¬Έμ΄λ‹€.

λ‹€μŒμ€ 컀링을 μ΄μš©ν•œ 빌렀주기 방식을 μ΄μš©ν•œ νŒŒμΌμ“°κΈ° 이닀.

def withPrintWriter(file: File)(op: PrintWriter => Unit) = {
  val writer = new PrintWriter(file)
  try {
    op(writer)
  } finally {
    writer.close()
  }
}
val file = new File("date.txt")

withPrintWriter(file) {
  writer => writer.println(new java.util.Date)
}

File 인자λ₯Ό ν¬ν•¨ν•˜λŠ” 첫 인자 λͺ©λ‘μ€ μ†Œκ΄„ν˜Έλ‘œ κ°μŒŒλ‹€.

ν•¨μˆ˜ 인자λ₯Ό ν¬ν•¨ν•˜λŠ” 두 번째 인자 λͺ©λ‘μ—λŠ” μ€‘κ΄„ν˜Έλ₯Ό μ‚¬μš©ν–ˆλ‹€.

9.5 이름에 μ˜ν•œ 호좜 νŒŒλΌλ―Έν„°

def byNameAssert(predicate: => Boolean) =
  if (assertionsEnabled && !predicate)
    throw new AssertionError
def boolAssert(predicate: Boolean) =
  if (assertionsEnabled && !predicate)
    throw new AssertionError
byNameAssert(5 > 3)

boolAssert(5 > 3)

byNameAssert κ³Ό boolAssert 의 결과도 μ‚¬μš©ν•˜λŠ” μ½”λ“œλ„ κ°™λ‹€.

μœ„ λ‘˜μ˜ κ°€μž₯ μ€‘μš”ν•œ 차이점은 boolAssert 인자 νƒ€μž…μ΄ Boolean μ΄λ―€λ‘œ, boolAssert(5 > 3) 의 κ΄„ν˜Έ μ•ˆμ— μœ„μΉ˜ν•œ ν‘œν˜„μ‹μ„ boolAssert 호좜 직전에 κ³„μ‚°ν•œλ‹€.

λ§Œμ•½ boolAssert μΈμžνƒ€μž…μ΄ x / 0 == 0 이라면 boolAssert 의 인자의 ν‘œν˜„μ‹μ„ 계산함에 따라 μ—λŸ¬κ°€ λ°œμƒλœλ‹€.

ν•˜μ§€λ§Œ 같은 μ½”λ“œμ˜ byNameAssert λŠ” μ˜ˆμ™Έκ°€ λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€.

9.6 κ²°λ‘ 

슀칼라 라이브러리의 κ³ μ°¨ν•¨μˆ˜, 컀링 등을 μ΄μš©ν•˜μ—¬ μ’€ 더 κ°„κ²°ν•œ λ¬Έλ²•μœΌλ‘œ ν™œμš©ν•˜λŠ” 방법을 μ•Œμ•„λ³΄μ•˜λ‹€.

Chapter 10 상속과 ꡬ성

클래슀 κ°„μ˜ 근본적인 두 가지 관계인 상속 (inheritance) κ³Ό ꡬ성 (composition) 을 비ꡐ할 것이닀.

10.1 2차원 λ ˆμ΄μ•„μ›ƒ 라이브러리

쑰립을 λ‹΄λ‹Ήν•˜λŠ” above 와 beside 도 μ •μ˜ ν•  것이닀.

elem(s: String) = Element
val column1 = elem("hello") above elem("***")
val column2 = elem("***") above elem("world")

hello***
***world

쑰립 μ—°μ‚°μžλŠ” νŠΉμ • λ„λ©”μΈμ˜ μš”μ†Œλ₯Ό κ²°ν•©ν•˜μ—¬ μƒˆλ‘œμš΄ μš”μ†Œλ₯Ό λ§Œλ“€μ–΄λ‚΄κΈ° λ•Œλ¬Έμ— 콀비넀이터 (combinator) 라고 λΆ€λ₯Έλ‹€.

10.2 좔상 클래슀

abstract ν‚€μ›Œλ“œλ‘œ μ•„λž˜μ™€ 같이 클래슀λ₯Ό μ •μ˜ λ‚΄λ¦°λ‹€.

abstract class Element {
  def contents: Array[String]
}

contents λŠ” Element 클래슀의 좔상 멀버 (abstract member) 이닀.

abstract μˆ˜μ‹μžλŠ” ν•΄λ‹Ή 클래슀 μ•ˆμ— κ΅¬ν˜„μ΄ μ—†λŠ” 좔상 멀버가 μžˆμŒμ„ μ•Œλ €μ€€λ‹€. λ•Œλ¬Έμ— μΆ”μƒν΄λž˜μŠ€λ‘œλŠ” μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€μˆ˜ μ—†λ‹€.

λ§Œμ•½ λ©”μ„œλ“œμ˜ κ΅¬ν˜„μ΄ μžˆλ‹€λ©΄ ꡬ체 λ©”μ„œλ“œ (concrete method) 라고 ν•œλ‹€.

10.3 νŒŒλΌλ―Έν„° μ—†λŠ” λ©”μ„œλ“œ μ •μ˜

ν•„λ“œλ‚˜ λ©”μ„œλ“œμ€‘ μ–΄λ–€ λ°©μ‹μœΌλ‘œ 속성을 μ •μ˜ ν•˜λ”λΌλ„ ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œμ—λŠ” 영ν–₯을 λΌμΉ˜μ§€ 말아야 ν•œλ‹€λŠ” 단일 μ ‘κ·Ό 원칙 (uniform assess principle) 에 λΆ€ν•©ν•œλ‹€.

"hello".length // λΆ€μˆ˜νš¨κ³Όκ°€ μ—†μœΌλ―€λ‘œ () λ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠμŒ
println() // () 을 μ‚¬μš©ν•˜λŠ” 편이 λ‚˜μŒ

호좜 ν•˜λŠ” ν•¨μˆ˜κ°€ μ–΄λ– ν•œ μž‘μ—…μ„ μˆ˜ν–‰ν•œλ‹€λ©΄ 빈 κ΄„ν˜Έλ₯Ό μ‚¬μš©ν•˜λΌ

ν•˜μ§€λ§Œ ν”„λ‘œνΌν‹°μ— λŒ€ν•œ μ ‘κ·Όλ§Œμ„ μˆ˜ν–‰ν•œλ‹€λ©΄ κ΄„ν˜Έλ₯Ό 떼버렀라.

10.4 클래슀 ν™•μž₯

μΆ”μƒν΄λž˜μŠ€λ₯Ό ν™•μž₯ν•˜λ €λ©΄ extends ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ •μ˜ν•œλ‹€.

class ArrayElement(conts: Array[String]) extends Element {
  def contents: Array[String] = conts
}

extends μ ˆμ€ λ‹€μŒ 효과λ₯Ό 가진닀.

  • ν™•μž₯ ν΄λž˜μŠ€λŠ” μΆ”μƒν΄λž˜μŠ€μ—μ„œ λΉ„κ³΅κ°œ (private) κ°€ μ•„λ‹Œ 멀버λ₯Ό λͺ¨λ‘ λ¬Όλ €λ°›λŠ”λ‹€.
  • ν™•μž₯ 클래슀λ₯Ό μΆ”μƒν΄λž˜μŠ€μ˜ μ„œλΈŒνƒ€μž… (subtype) 으둜 λ§Œλ“ λ‹€.
ν™•μž₯ 클래슀 (μ„œλΈŒ 클래슀) -> 좔상 클래슀 (슈퍼 클래슀)

10.5 λ©”μ„œλ“œμ™€ ν•„λ“œ μ˜€λ²„λΌμ΄λ“œ

μŠ€μΉΌλΌμ—μ„œλŠ” ν•„λ“œμ™€ λ©”μ„œλ“œκ°€ 같은 λ„€μž„μŠ€νŽ˜μ΄μŠ€μ— μ†ν•œλ‹€.

class CompilesFine {
  private int f = 0;
  public int f() {
    return 1;
  }
}

μœ„ μžλ°” μ½”λ“œλŠ” λ¬Έμ œμ—†μ΄ 컴파일 ν•  수 μžˆμ§€λ§Œ μ•„λž˜ 슀칼라 μ½”λ“œλŠ” ν•„λ“œμ™€ λ©”μ„œλ“œκ°€ 같은 μ΄λ¦„μœΌλ‘œ 컴파일 ν•  수 μ—†λ‹€.

class WontCompile {
  private var f = 0
  def f = 1
}

μžλ°”μ—λŠ” 4개의 λ„€μž„μŠ€νŽ˜μ΄μŠ€ (ν•„λ“œ, λ©”μ„œλ“œ, νƒ€μž…, νŒ¨ν‚€μ§€) κ°€ μžˆμ§€λ§Œ
μŠ€μΉΌλΌμ—λŠ” 2개의 λ„€μž„μŠ€νŽ˜μ΄μŠ€ (κ°’, νƒ€μž…) 만 μžˆλ‹€.

10.6 νŒŒλΌλ―Έν„° ν•„λ“œ μ •μ˜

class Cat {
  val dangerous = false
}

class Tiger (
  override val dangerous: Boolean,
  private var age: Int
) extends Cat

μ•„λž˜ 두 λ©€λ²„λŠ” 각각 λŒ€μ‘ν•˜λŠ” 인자둜 μ΄ˆκΈ°ν™” λœλ‹€.

인자의 이름을 μž„μ˜λ‘œ param1, param2 라고 λΆ™μ˜€λ‹€.

class Tiger(param1: Boolean, param: Int) extends Cat {
  override val dangerous = param1
  private var age = param2
}

μ€‘μš”ν•œ 것은 인자의 이름이 μŠ€μ½”ν”„μ— μžˆλŠ” λ‹€λ₯Έ 이름과 μΆ©λŒν•˜μ§€ μ•Šμ•„μ•Ό ν•œλ‹€λŠ” 것이닀.

10.7 슈퍼 클래슀 μƒμ„±μž 호좜

class LineElements(s: String) extends ArrayElement(Array(s)) {
  override def width = s.length
  override def height = 1
}

LineElement ν΄λž˜μŠ€λŠ” Array(s) λ₯Ό ArrayElement λ’€μ–΄ κ΄„ν˜Έλ‘œ λ¬Άμ–΄ ν‘œκΈ°ν•¨μœΌλ‘œμ¨ ArrayElement 의 μ£Ό μƒμ„±μžμ— μ „λ‹¬ν•œλ‹€.

10.8 override μˆ˜μ‹μž μ‚¬μš©

μŠ€μΉΌλΌμ—μ„œλŠ” λΆ€λͺ¨ ν΄λž˜μŠ€μ— μžˆλŠ” ꡬ체 (concrete) 멀버λ₯Ό μ˜€λ²„λΌμ΄λ“œ ν•˜λŠ” λͺ¨λ“  멀버에 override μˆ˜μ‹μžλ₯Ό λΆ™μ—¬μ•Ό ν•œλ‹€.

10.9 λ‹€ν˜•μ„±κ³Ό 동적 바인딩

μƒμœ„ 클래슀λ₯Ό 상속 λ°›λŠ” ν΄λž˜μŠ€κ°€ μ—¬λŸ¬ νƒ€μž…μ˜ 객체λ₯Ό μ°Έμ‘°ν•  수 μžˆμŒμ„ λ‹€ν˜•μ„± (polymorphism) 이라고 ν•œλ‹€.

λ³€μˆ˜λ‚˜ ν‘œν˜„μ‹μ— λŒ€ν•œ λ©”μ„œλ“œ ν˜ΈμΆœμ„ λ™μ μœΌλ‘œ 바인딩 ν•œλ‹€λŠ” 점이닀.

μ΄λŠ” μ‹€ν–‰μ‹œμ μ— μ‹€μ œλ‘œ κ·Έ 객체가 μ–΄λ–€ νƒ€μž…μΈκ°€λ₯Ό λ”°λ₯Έλ‹€λŠ” λœ»μ΄λ‹€.

10.10 final 멀버 μ„ μ–Έ

상속 ν΄λž˜μŠ€κ°€ μ˜€λ²„λΌμ΄λ“œ ν•˜μ§€ λͺ»ν•˜κ²Œ 막고 μ‹Άμ„λ•Œ μ‚¬μš©

class ArrayElement extends Element {
  final override def demo() = {
    println("ArrayElement's implementation invoked")
  }
}

10.11 상속과 ꡬ성 μ‚¬μš©

ꡬ성과 상속은 이미 μ‘΄μž¬ν•˜λŠ” 클래슀λ₯Ό μ΄μš©ν•΄ μƒˆλ‘œμš΄ 클래슀λ₯Ό μ •μ˜ν•˜λŠ” 두 가지 방법이닀.

10.12 above, beside, toString κ΅¬ν˜„

abstract class Element {
  def contents: Array[String]
  
  def width: Int = 
    if (height == 0) 0 else contents(0).length
  
  def height: Int = content.length
  
  def above(that: Element): Element = 
    new ArrayElement(this.contents ++ that.contents)

  def beside(that: Element): Element = 
    new ArrayElement(
      for (
        (line1, line2) <- this.contnets zip that.contnets
      ) yield line + line2
    )

  override def toString = contents mkString "\n"
}

10.13 νŒ©ν† λ¦¬ 객체 μ •μ˜

νŒ©ν† λ¦¬ κ°μ²΄λŠ” λ‹€λ₯Έ 객체λ₯Ό μƒμ„±ν•˜λŠ” λ©”μ„œλ“œλ₯Ό μ œκ³΅ν•˜λŠ” κ°œμ²΄λ‹€.

new λ₯Ό μ΄μš©ν•˜μ—¬ 직접 객체λ₯Ό λ§Œλ“€κΈ° λ³΄λ‹€λŠ” νŒ©ν† λ¦¬ λ©”μ„œλ“œλ‘œ 객체λ₯Ό μƒμ„±ν•œλ‹€.

νŒ©ν† λ¦¬ λ©”μ„œλ“œλ₯Ό μƒμ„±ν•˜λŠ” 이점은 생성 κΈ°λŠ₯을 ν•œκ³³μ— λͺ¨μ•„ μ œκ³΅ν•˜κ³  ꡬ체적인 λ‚΄λΆ€ ν‘œν˜„μ„ 감좜수 μžˆλ‹€λŠ” 점이닀.

μ΄λ ‡κ²Œ 세뢀사항을 숨기면 ν΄λΌμ΄μ–ΈνŠΈλŠ” 라이브러리λ₯Ό μ’€ 더 μ‰½κ²Œ 이해 κ°€λŠ₯ν•˜κ³ , λ‚˜μ€‘μ— ν΄λΌμ΄μ–ΈνŠΈμ˜ μ½”λ“œλ₯Ό 깨지 μ•Šκ³  κ΅¬ν˜„μ„ λ³€κ²½ν•˜κΈ°μ—λ„ μœ λ¦¬ν•˜λ‹€.

object Element {
  def elem(contents: Array[String]): Element = 
    new ArrayElement(contents)
  
  def elem(chr: Char, width: Int, height: Int): Element = 
    new UniformElement(chr, width, height)
  
  def elem(line: String): Element =
    new LineElement(line)
}

10.14 높이와 λ„ˆλΉ„ 쑰절

예제 μ½”λ“œ μ„€λͺ…

10.15 ν•œλ° λͺ¨μ•„ μ‹œν—˜ν•΄λ³΄κΈ°

import Element.elem

object Spiral {
  val space = elem(" ")
  val corner = elem("+")

  def spiral(nEdges: Int, direction: Int): Element = {
    if (nEdges == 1) 
      elem("+")
    else {
      val sp = spiral(nEdges - 1, (direction + 3) % 4)
      def verticalBar = elem('|', 1, sp.height)
      def horizontalBar = elem('-', sp.width, 1)
      if (direction == 0)
        (corner beside horizontalBar) above (sp beside space)
      else if (direction == 1)
        (sp above space) beside (corner above verticalBar)
      else if (direction == 2)
        (space beside sp) above (horizontalBar beside corner)
      else 
        (verticalBar above corner) beside (space above sp)
    }
  }

  def main(args: Array[String]) = {
    val nSides = args(0).toInt
    println(spiral(nSides, 0))
  }
}

10.16 κ²°λ‘ 

객체 지ν–₯의 λ§Žμ€ κ°œλ…μ„ μ‚΄νŽ΄λ³΄μ•˜λ‹€.