jam 블로그

러닝스칼라 3장 - 표현식과 조건문 본문

IT Book Study/러닝 스칼라

러닝스칼라 3장 - 표현식과 조건문

kid1412 2020. 9. 28. 23:11
728x90

표현식

표현식(expression) 은 값을 반환하는 코드의 단위입니다.

// String 리터럴
"hello"
"hel"+'l'+'o'

표현식으로 값과 변수 정의하기

아래와 같이 표현식의 반환값을 값 또는 변수에 할당하는 식으로 나타낼 수 있습니다.

val <식별자>[: <타입>] = <표현식>

표현식 블록

표현식 블록 은 중괄호({,})를 사용하여 하나로 묶어서 사용합니다.

두 표현식

val x = 5 * 20; val amount = x + 10

표현식 블록

val amount = { val x = 5 * 20; x + 10}

여러 줄로 표현

val amount = {
  val x = 5 * 20
  x + 10
}

삼중 구조 후반부에 제어 구조를 다룰 때 다룹니다.

{ val a = 1; { val b = a * 2; { val c = b + 4; c}}}

문장(statement)

문장(statement) : 값을 반환하지 않는 표현식

문장 블록(Statement block) : 표현식 블록과 다르게 값을 반환하지 않습니다. * 결과 값이 없기 때문에 보편적으로 기존 데이터를 수정하거나 애플리케이션 범위 밖을 변경하는데 사용 합니다.

If .. Else 표현식 블록

If 표현식

if (<부울식>) <표현식>

if ( 47 % 3 > 0 )  println("Not a multiple of 3")

If-Else 표현식

if (<부울식>) <표현식> else <표현식>

val x = 10 
val y = 20 
val max = if (x > y) x else y // 20
  • 다른 언어에서 지원하는 삼항 표현식을 사용하지 않는 이유는 간결하게 표현할 수 있기 때문

매치 표현식

switch문과 유사합니다.

<표현식> match { case <패턴 매치> => <표현식> [case ...] }

If .. else와 같은 방식의 match

val x = 10 
val y = 20 
val max = x > y match { 
    case true => x 
    case false => y 
} //max = 20s

Request Status Code

val status = 500
val message = status match { 
    case 200 => “ok” 
    case 400 => { 
        println("ERROR - we called the service incorrectly.") 
        "error"
    } 
    case 500 => { 
        println("ERROR - the service encountered an error.") 
        "error" 
    } 
} 
// ERROR - the service encountered an error 
// message : error

여러 패턴을 동일한 case 블록 사용하기

val day = "MON" 
val kind = day match { 
    case "MON" | "TUE" | "WED" | "THU" | "FRI" => { 
        "weekday" 
    } 
    case "SAT" | "SUN" => { 
        "weekend" 
    } 
} 
//kind = "weekday"

Error

"match me" match {
    case "nope" => "sorry"
} 
// scala.MatchError

위처럼 에러를 방지하기 위해 와일드 카드로 매칭하여 예외처리 합니다.

와일드카드로 매칭하기

  • 값 바인딩(value binding)

    • case 블록이 유지되는 동안만 정의됩니다.

      val message = "FAIL"
      val status = message match {
      case "OK" => 200
      case other => {
        println(other) // "FAIL"
        -1
      }
      }
  • 와일드 카드(_, underscore)

    • _를 사용하며 값 바인딩과 다르게 해당 값에 대해서 접근할 수 없습니다.

      val status = message match {
      case "OK" => 200
      case _ => {
        -1
      }
      }

패턴 가드를 이용한 매칭

기존의 if문과 다르게 둘러싸고 있는 ()가 필요 없습니다.

case <패턴> if <부울식> => <하나 이상의 표현식>

val response: String = null
response match {
  case s if s != null => println(s"Received '$s'")
  case s => println("Error!")
}
// "Error!"

패턴 변수를 이용한 타입 매칭

패턴 변수는 다른 타입의 값으로 전환할 수 있습니다. 패턴 변수에서의 제한은 반드시 소문자로 시작해야합니다.

case <identifier>: <type> => <one or more expressions>

패턴 변수 사용법

val y:Any = 12345

y match {
  case x: String => s"'$x'"
  case x: Double => f"$x%.2f"
  case x: Float => f"$x%.2f"
  case x: Long => s"${x}l"
  case x: Int => s"${x}i"
}
//12345i

루프

숫자 범위 정의하기
<시작 정수값> [to|until] <끝 정수값> [by increment]

기본 for 루프로 반복하기
for (<식별자> <- <반복자>)[yield] [<표현식>]

for (x <- 1 to 7) {println(s"Day $x:")}
/*
    Day 1:
    Day 2:
    Day 3:
    Day 4:
    Day 5:
    Day 6:
    Day 7:
*/

만약 for loop시에 하나의 컬렉션에 넣어서 반환하려면 yield를 사용합니다.

for (x <- 1 to 7) yield { s"Day $x:"}
// res0: IndexedSeq[String] = Vector(Day 1:, Day 2:, Day 3:, Day 4:, Day 5:, Day 6:, Day 7:)

반복자 가드

for (<identifier> <- <iterator> if <Boolean expression>) ...

아래는 3의 배수로 이루어진 컬렉션을 만드는 예제입니다.

val threes = for (i <- 1 to 20 if i % 3 == 0) yield i 

val threes_multi_line = for {
  i <- 1 to 20
  if i % 3 == 0
} yield i
// threes_multi_line: IndexedSeq[Int] = Vector(3, 6, 9, 12, 15, 18)

중첩된 반복자

for 루프에 추가된 부가적인 반복자로, 전체 반복 횟수를 자신의 반복 횟수만큼 반복합니다.

val two_dimension = for {
  x <- 1 to 2
  y <- 1 to 3  
} {print(s"($x, $y)")}
// (1, 1)(1, 2)(1, 3)(2, 1)(2, 2)(2, 3)two_dimension: Unit = ()

값 바인딩

for 루프 정의에서 값 바인딩을 사용하여 좀 더 깔끔한 코드를 만들 수 있습니다.

for (<식별자> <- <반복자> ; <식별자> = <표현식>) ...

예시로 아래에 0에서 8까지 2의 거듭 제곱 값을 계산하는 for 루프 입니다. 값 바인딩을 사용하지 않았을 경우 코드가 좀 길어집니다.

val powersOf2 = for (i <- 0 to 8) yield {
  val pow = 1 << i
  pow
}
// powersOf2: IndexedSeq[Int] = Vector(1, 2, 4, 8, 16, 32, 64, 128, 256)

값 바인딩을 사용하면 아래와 같이 깔끔하게 정의할 수 있습니다.

val powerOf2 = for (i <- 0 to 8; pow = 1 << i) yield pow
// powersOf2: IndexedSeq[Int] = Vector(1, 2, 4, 8, 16, 32, 64, 128, 256)

위에서 사용한 <<(shift 연산자)는 비트를 옮기는 역할을 합니다.

대략적인 ...
1 : 0b000000001
2 : 0b000000010
4 : 0b000000100
8 : 0b000001000
...
256 : 0b100000000

While과 Do/While 루프

while (<부울식>) 표현식

var x = 10
while (x > 0) x -= 1

var x = 10
do x -= 1 while ( x > 0 )

FAQ

  1. yield 사용 시 동작 방법
    1. for loop에서는 map function처럼 동작 합니다.
      1. https://docs.scala-lang.org/tutorials/FAQ/yield.html
    2. yield 앞에 사용법에 따라서 동작 방식이 달라질 듯 합니다.
Comments