-
Notifications
You must be signed in to change notification settings - Fork 36
7장 built in control structures
- 스칼라의 제어구문(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 = truescala> 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)
- Iteration through collections
- 콜렉션의 요소로 반복문을 수행한다.
- 콜렉션에 직접 접근한다.
- Filtering
- for문 안에 if절을 넣어 필터링을 할 수 있다.
- for문은 표현식.(타입을 가진 콜렉션이 결과값으로 나오기 때문)
- Nested iteration
- <- 절을 추가하여 중첩루프로 쓸 수 있다.
- {}를 () 대신 쓸 수 있다.(;을 안써도 된다.)
- Mid-stream variable bindings
- non-trivial이면 변수에 대입하여 사용할 수 있다.(변수는 val)
- Producing a new collection
- for clauses yield body 키워드의 위치에 주의.
- yield에 대한 토론
###7.4 Exception handling with try expressions
- 예외를 던져 메소드를 종료시킬 수 있다.
- Throwing exceptions
- throw new exception
- throw는 반환타입을 가지는 표현식.
- 타입은 Nothing.
- Catching exceptions
- catch 절에서는 패턴매칭을 이용하여 exception을 처리한다.
- The finally clause
- 구문이 종료되는 것과 상관없이 항상 수행되어야 하는 코드를 처리한다.
- Yielding a value
- try-catch-finally도 값을 도출한다.
- finally 절에서는 파일닫기와 같은 일(정리정돈?)을 해주는게 좋다.
###7.5 Match expressions
- switch문처럼 여러 대안을 선택할 수 있다.
- _(underscore)는 와일드카드
- 자바의 switch문과는 다르다.
- 다양한 종류의 타입을 쓸 수 있다.
- break가 없다.
- 값이 도출된다.
###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;
{
...
}
}
skip
Outsider
- 스칼라의 대부분 제어문은 값이 된다. 이는 함수형 언어의 접근이다.
- val을 최대한 사용해라. 읽기 쉽고 리팩토링이 쉽게 만들어준다.
-
while
과do-while
을 loops라고 부르고 expression이 아니다. 결과로 값이 되지 않고 Unit이 된다. - unit value라고 부르고 ()로 작성한다. ()의 존재가 자바의 void와 다른 점이다.
- 할당은 항상 결과가 unit value ()가 된다.
-
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
-
예외를 던지는 것은 자바와 동일하다.
throw new IllegalArgumentException
-
스칼라에서는
throw
도 결과값을 갖는다. 기술적으로는throw
는Nothing
타입이 된다. -
catch문의 문법은 패턴매칭문을 동일하다.
try {} catch { case ex: FileNotFoundException => case ex: IOException => } finally {}
-
예외가 던져졌을때 catch되지 않으면 finally에서 계산된 값도 버려진다. 그렇지 않으면 try나 catch문의 결과가 결과값이 된다.
-
매치문은 switch대신 쓸 수 있다.
-
기본케이스는 언더스코어(_)를 쓴다.
a match { case "a" => body case "b" => body case _ => body }
-
break문이 없어도 다음 조건으로 넘어가지 않는다.
-
match문도 결과값이 된다.
-
스칼라에는 break와 continue가 없다.
-
모든 continue는 if문으로 break문은 boolean값으로 바꿀 수 있다.
-
scala.util.control.Breaks
클래스에 break 메서드를 제공해서 breakble키워드로 된 블럭에서 사용할 수 있다.import scala.util.control.Breaks._ breakable { while (true) { if () break } }
- 스칼리에서는 중첩된 범위에서는 같은 변수명을 정의할 수 있다.
- 변수선언은 scope를 갖는다. 일반적으로 중괄호의 범위이다.
- 외부의 변수와 같은 이름인 내부변수를 shadow라고 부른다.
- 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부분