7장 built in control structures - codeport/scala GitHub Wiki

  • 스칼라의 제어구문(syntax)
    if, while, for, try, match, function calls.

###7.1 If expressions

  • 일반적인 if문의 기능을 수행한다.

  • if(expression) result1 else result2 삼항연산처럼 표현할 수 있다.(scala에는 삼항연산이 없음)

  • 위의 방식을 사용하면 코드가 짧아진다.

    • val을 사용하면 좋아요!
    • 자바의 final변수처럼 사용할 수 있다.
    • 등식추론에 더 도움이 된다. "equational reasoning"
    • 읽기도 쉽고 리팩토링하기도 쉽다.

    Q)이런 결과도 있다. 왜 다를까?
    scala> val a = if(true) true
    a: AnyVal = true

    scala> val a = if(true) true else false
    a: Boolean = true

###7.2 While loops

  • 일반적인 while문의 기능을 수행한다.
  • do-while문도 있다.
  • 반환형이 Unit이기 때문에 표현식이 아니라 루프라고 한다.
    Unit타입이 반환하는 값는 unit value라고 하며 () 로 표기한다.
    • 자바와는 다르다.
    • 자바의 void와는 다르게 함수의 값을 비교할 수 있다.
    • 대입식을 비교하는 구문으로 사용하면 루프를 쓰지 말아야 한다.
      (대입하면 스칼라에서는 결과가 unit value, ()라서 ""이 될 수 없다. > 무한루프로 빠진다. pg.118)
  • while문 대신 함수형으로 재귀호출을 쓸 수 있다.

###7.3 For expressions

  • 스칼라의 for문은 다양한 방법으로 사용할 수 있다.
  • for(generator)
  1. Iteration through collections
    • 콜렉션의 요소로 반복문을 수행한다.
    • 콜렉션에 직접 접근한다.
  2. Filtering
    • for문 안에 if절을 넣어 필터링을 할 수 있다.
    • for문은 표현식.(타입을 가진 콜렉션이 결과값으로 나오기 때문)
  3. Nested iteration
    • <- 절을 추가하여 중첩루프로 쓸 수 있다.
    • {}를 () 대신 쓸 수 있다.(;을 안써도 된다.)
  4. Mid-stream variable bindings
    • non-trivial이면 변수에 대입하여 사용할 수 있다.(변수는 val)
  5. Producing a new collection

###7.4 Exception handling with try expressions

  • 예외를 던져 메소드를 종료시킬 수 있다.
  1. Throwing exceptions
    • throw new exception
    • throw는 반환타입을 가지는 표현식.
    • 타입은 Nothing.
  2. Catching exceptions
    • catch 절에서는 패턴매칭을 이용하여 exception을 처리한다.
  3. The finally clause
    • 구문이 종료되는 것과 상관없이 항상 수행되어야 하는 코드를 처리한다.
  4. Yielding a value
    • try-catch-finally도 값을 도출한다.
    • finally 절에서는 파일닫기와 같은 일(정리정돈?)을 해주는게 좋다.

###7.5 Match expressions

  • switch문처럼 여러 대안을 선택할 수 있다.
  • _(underscore)는 와일드카드
  • 자바의 switch문과는 다르다.
    1. 다양한 종류의 타입을 쓸 수 있다.
    2. break가 없다.
    3. 값이 도출된다.

###7.6 Living without break and continue

  • 스칼라에는 break와 continue가 빠져있다.
  • scala.util.control패키지에 있는 Breaks클래스에서 break메소드를 제공한다.
  • Breaks클래스는, breakable메소드에서 처리하는 예외를 던져서 break를 구현한다.
  • Breaks

###7.7 Variable scope

  • 변수를 선언하면 변수는 scope를 가지며 일반적으로 {}로 표기된다.
  • 같은 scope에서는 동일한 이름의 변수를 쓸 수 없다.(scope이 다르면 쓸 수 있다는 말~)
  • 변수는 새 이름으로 의미있게!

###7.8 Refactoring imperative-style code

  • imperative 코드를 functional하게 바꿔보자.

kingori

###7.0

Scala의 대부분의 제어 구문은 값을 반환함. <- functional language들이 이렇게 동작한다고 함. Java의 ternary operator인 ? 의 경우, Scala의 if 로 대체 가능함. 이는 if 나 else 블럭의 마지막 평가값이 return되기 때문으로 이해했음. 이런 형태를 취함으로써 임시 변수의 필요성을 줄일 수 있다고 함. for, try, match 도 마찬가지로 값을 반환함.

 int a = 1 > 10 ? 1 : 0; //java
 val a:Int = if( 1 > 10 ) 1 else 0 //scala

 scala> val k = try { val a = 1; }  
 k: Unit = () 

 scala> val a = 1 match { case 1 => 1; case 2 => 2; }
 a: Int = 1

###7.1

if 구문이 return value를 갖는다는 점을 제외하면 java와 크게 다른 점은 없어 보임.

질문: 7.1 끝부분에 나오는 equational reasoning 이 무슨 말인지? side effect가 없는 표현식의 경우, 결과 값은 항상 원래의 표현식으로 대치할 수 있다고 이해했음

var보단 val을 권장하는 설명이 있음. java에서 final을 사용하라는 충고랑 같은 내용이라고 생각함.

###7.2

while도 다른 언어와 거의 비슷. do-while도 있음. while과 do-while은 의미있는 값을 반환하지 않으므로 expression이라는 표현 대신 loop이란 표현을 사용했음. Unit 값을 반환하기는 함.

scala> val a = while( false) { }
a: Unit = ()

java의 할당문은 할당된 값을 반환하지만, Scala의 할당문은 Unit 값을 반환함.

//java
public class A {
    public static void main(String[] args)
    {
    String a = null;
    System.out.println( a= "a");
    }
}

a //실행결과

//scala
scala> val a = { val b = 3; }
a: Unit = () 

###7.3

scala의 for 문은 상당히 강력하다.

  • collection iteration ** for ( file <- files ) : file <- files 문법을 generator라고 함. 질문: <- 는 그냥 외워야 하는 건지? 어떻게 이게 동작하는 걸까? 23장을 봐도 딱히 <- 의 동작 방식에 대해선 안나와 있는 듯 한데.
  • filtering: if 문으로 filter를 추가. 필요한 만큼 쭉 if 를 붙이면 됨. && 로 덧붙이는 게 아님. 질문: && 로 덧붙이는 것이랑 if 를 여러개 붙이는 것이랑 차이가 있을까? -> 별 차이 없는 듯 한데.
  • nested iteration: 여러 개의 generator
  • mid-stream variable binding : 23장에선 definition이라고 명시했음. 각 iteration마다 대입될 값을 정의. val로 동작
  • producing new collection: yield를 사용. 주의: body는 yield 다음에 나옴.

for의 () 안에 들어갈 내용이 많아 ; 를 쓰기 거추장스럽다면 { } 로 묶자. 이렇게 하면 ; 를 쓰지 않아도 된다.

 scala> val a = for( i <- 1 to 10 ; if i %2 == 0 ;  if i %3 == 0 ) yield i
 a: scala.collection.immutable.IndexedSeq[Int] = Vector(6)
 val a = for( i <- 1 to 10 ; if i %2 == 0 && i %3 == 0 ) yield i
 a: scala.collection.immutable.IndexedSeq[Int] = Vector(6) 

###7.4

  • throw : throw도 result type이 있다. 어떤 타입도 될 수 있으며, 이 return 값을 사용할 수는 없다. 타입은 Nothing 임. --> 이건 126pg 에서 else 문에 throw가 들어가도 문법에 어긋나지 않음을 설명하기 위함이라고 봄.
  • catch : catch는 pattern matching을 이용함. catch되지 않았다면 예외는 호출자에게 전달됨.
  • finally : 자바랑 다를 바 없는 듯. 9.4절에 나오는 loan pattern을 고려할 수 있다고 함.

try, catch, finally 도 value를 반환함. (java랑 다름!) 다만 finally의 평가 결과는 무시됨. 따라서 finally에서 명시적으로 return을 하지 않는 이상 finally의 평가 값은 버려짐.

###7.5

match

  • default는 _

  • int, enum만 쓸 수 있는 java의 switch 보다 훨씬 강력

  • case 뒤에 break;를 붙일 필요 없음. 무조건 break.

  • match 표현식도 값을 반환함.

    대상 match { case 1 => expr1 case 2 => expr2 ... case _ => default }

###7.6

scala엔 break와 continue가 없음. boolean 타입의 필드를 사용하면 break, continue를 쓰지 않을 수 있음. 그래도 break를 써야겠다면 scala.util.control.Breaks 의 break 메서드를 쓸 수 있음.

breakable {
   .... break
}

###7.7

scope - java와 유사. 단, 하위 scope에 상위 scope에 이미 선언된 변수를 선언할 수 있음(java에선 안됨). repl 에서 중복 선언이 가능한 것도 이런 특성에 기인함. repl에선 매 문장마다 nested scope를 만들기 때문이라 함

val a = 1;
{
  val a = 2;
  {
    ...
  }
}

7.8

skip

옥토버


Outsider

  • 스칼라의 대부분 제어문은 값이 된다. 이는 함수형 언어의 접근이다.

7.1 If expressions

  • val을 최대한 사용해라. 읽기 쉽고 리팩토링이 쉽게 만들어준다.

7.2 While loops

  • whiledo-while을 loops라고 부르고 expression이 아니다. 결과로 값이 되지 않고 Unit이 된다.
  • unit value라고 부르고 ()로 작성한다. ()의 존재가 자바의 void와 다른 점이다.
  • 할당은 항상 결과가 unit value ()가 된다.

7.3 For expressions

  • for문의 for <- filesHere를 genertator라고 부른다.

  • for문에는 Ranges 문법(1 to 5)을 사용할 수 있다.

  • 마지막 값을 빼려면 1 until 5를 사용한다.

  • for문은 결과값이 된다.

  • for문에 if문으로 필터를 사용할 수 있다.

    for (item <- items if item > 0) body

  • 필터는 여러개 사용할 수 있다.

    for ( item <- items if item > 0 if item < 10 ) body

  • 중첩 for문을 위해서 <-문을 여러개 사용할 수 있다.

    for ( item <- items if item > 0; file <- files if file < 10 ) body

  • 제너레이터와 필터에 괄호대신 중괄호를 사용할 수 있는데 중괄호를 사용하면 세미콜론을 생략할 수 있다.

  • 순회시 각 값을 기억되지 않기 때문에 yield를 사용하면 기억할 수 있다.

    for ( item <- items if item > 0 ) yield item

  • yield 문법은 다음과 갖다

    for clauses yield body

7.4 Exception handling with try expressions

  • 예외를 던지는 것은 자바와 동일하다.

    throw new IllegalArgumentException

  • 스칼라에서는 throw도 결과값을 갖는다. 기술적으로는 throwNothing타입이 된다.

  • catch문의 문법은 패턴매칭문을 동일하다.

    try {} catch { case ex: FileNotFoundException => case ex: IOException => } finally {}

  • 예외가 던져졌을때 catch되지 않으면 finally에서 계산된 값도 버려진다. 그렇지 않으면 try나 catch문의 결과가 결과값이 된다.

7.5 Match expressions

  • 매치문은 switch대신 쓸 수 있다.

  • 기본케이스는 언더스코어(_)를 쓴다.

    a match { case "a" => body case "b" => body case _ => body }

  • break문이 없어도 다음 조건으로 넘어가지 않는다.

  • match문도 결과값이 된다.

7.6 Living without break and continue

  • 스칼라에는 break와 continue가 없다.

  • 모든 continue는 if문으로 break문은 boolean값으로 바꿀 수 있다.

  • scala.util.control.Breaks클래스에 break 메서드를 제공해서 breakble키워드로 된 블럭에서 사용할 수 있다.

    import scala.util.control.Breaks._ breakable { while (true) { if () break } }

7.7 Variable scope

  • 스칼리에서는 중첩된 범위에서는 같은 변수명을 정의할 수 있다.
  • 변수선언은 scope를 갖는다. 일반적으로 중괄호의 범위이다.
  • 외부의 변수와 같은 이름인 내부변수를 shadow라고 부른다.

7.8 Refactoring imperative-style code

질문

  • A second advantage to using a val instead of a var is that it better supports equational reasoning.(p 161)
    • equational reasoning이 뭔가요?
  • Listing 7.9를 잘 이해못하겠습니다.
  • 171페이지의 Note부분