[Programming in Scala] 7. 내장 제어 구문

스칼라의 내장 제어구문은 if, while, for, try, match, 함수호출이 전부다.
설계 초기부터 함수 리터럴을 포함했기 때문이다. 또 내장 제어 구문은 결과를 리턴하도록 설계되어 있다. 이는 프로그램 전체를 값을 계산하는 관점에서 바라보고, 프로그램 구성요소 또한 값을 도출해야 한다는 함수 언어적 접근을 채용한 결과다

7.1 if 표현식

val filename = 
if (args.isEmpty == false) args(0)
else “default.txt”

filename을 var가 아닌 val을 사용했다. val은 코드를 읽는 사람에게 그 변수의 값이 결코 바뀌지 않음을 알려주고, 해당 변수의 값이 바뀌었는지를 찾아보기 위해 코드에서 그 변수의 모든 스코프를 다 뒤지는 일이 없게 해준다. 또한 val을 사용함에 따라 동일선 추론에 더욱 유리하다. 자바에서는 이렇게 만드려면 복잡해진다.

7.2 while 루프

def gcdLoop(x: Long, y: Long) : Long = {
var a = x
var b = y
while (a != 0) {
val temp = a
a = b%a
b = temp
}
b
}

while의 결과는 특정값이 아니기 때문에 타입이 Unit이다. Unit 타입에는 유니트값(unit value)밖에 없고, 이 값을 빈 괄호 ()로 표기한다. ()라는 값이 존재한다는 점에서 자바의 void와 스칼라의 Unit은 다르다.

scala> def greet() { println(“hi”) }
greet: ()Unit
scala> greet() == ()
hi
res0: Boolean = true

아래 코드는 동작하지 않는다.

var line = “”
while ( (line = readLine()) != “” )
println (“Read: “ + line)

순수 함수형 언어에서는 while문을 종종 제외시킨다. while 루프의 결과가 특정 값이 아니기 때문이다.

함수형 언어에서는 재귀를 사용해 while문을 대체하기도 한다

7.3 for 표현식

7.3.1 컬렉션 순회
아래 두 코드는 같은 결과가 나온다

scala> for (i <- 1 to 4)
scala> for (i <- 1 until 5)

아래와 같이 파일의 개수만큼 순회를 할 수 있지만 권장하지 않는다.
스칼라에서는 직접 순회하는 코드를 권장한다

for (i <- 0 to files.length -1)

7.3.2 필터링
모든 원소를 순회하지 않는 경우 필터를 추가해 필요한 리스트만 순회한다

for (
file <- filesHere
if file.getName.endWith(“.scala”)
) println (file)

7.3.3 중첩 순회
여러개의 <-절을 추가하면 중찹 루프를 작성 할 수 있다

for (
file <- filesHere
if file.getName.endWith(“.scala”)
line <- fileLines(file)
) println (line)

7.3.4 for 중에 변수 바인딩하기
새로운 변수에 결과를 할당해 사용

def grep(pattern: String) =
for {
file <- filesHere
if file.getName.endsWith(“.scala”)
line <- fileLines(file)
trimmed = line.trim
if trimmed.matches(pattern)
} println(file + “: “ + trimed)

7.3.5 새로운 컬렉션 만들어내기

수회의 반복 결과를 저장하기 위한 값을 만들려면 for 표현식의 본문 앞에 yield라는 키워드를 사용한다

def scalFiles = 
for {
file <- filesHere
if file.getName.endsWidth(“.scala”)
} yield file

yield는 전체 코드 블록(for의 본문)이 순회마다 만들어내는 결과 값을 모은다

7.4 try 표현식으로 예외 다루기

스칼라에서는 throw가 Nothing 이라는 타입이 있는 표현식이다.

val res = try {
val half =
if (n % 2 == 0)
n/2
else
throw new RuntimException(“n must be even”)
} catch {
case ex: FileNotFoundException =>
case ex: IOException =>
} finally {
-1
}

위에서 n의 값이 2라면 half의 값은 1이 된다.
finally절에 결과 값이 있다면 버려진다. finally 절은 파일을 닫는등의 정리 작업만 수행해야 한다.
명시적으로 return을 표시하면 리턴된다.

7.5 match 표현식
자바의 switch는 이넘이나 정수형만 올 수 있는데 반해 스칼라에서는 다양한 상수 형태를 지원한다. 또한 case문마다 break문이 암묵적으로 있다.
디폴트 case는 밑줄(_)로 표시한다.

val firstArg = if (args.length > 0) args(0) else “”
val friend = firstArg match {
case “salt” => “pepper”
case “chips” => “salsa”
case _ => “huh?”
}

7.6 break와 continue 문 없이 살기

continue -> if, break문을 불리언 변수로 대체

breakable로 이동하게 해주는 break가 있다.

breakable {
while ( ture ) {
println(“? “)
if ( in.readLine() == “”) break;
}
}

7.7 변수 스코프

스칼라에서는 내부 스코프에 동일한 이름의 변수를 정의해도 되는 점을 제외하곤 자바와 규칙이 거의 동일

자바는 바깥쪽 스코프에서 존재하는 것과 동일한 이름의 변수를 안쪽 스코프에 선언하지 못한다

7.8 명령형 스타일 코드 리팩토링

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.