84
1
부
스칼라와의 만남
//
줄이
쉼표
,
마침표
,
연산자로
끝나면
다음
줄에
이어지는
코드가
더
있다는
뜻이다
.
def commas
(
s1
:
String
,
s2
:
String
)
=
Console
.
println
("
comma
:
"
+
s1
+
",
"
+
s2
)
컴파일러와 비교했을 때
REPL
은 좀 더 공격적으로 줄 끝을 식의 끝으로 판단한다. 따라서 여
러 줄에 걸친 식을 입력하는 경우에는 위 예제에서와 같이 (마지막 줄을 제외한) 각 줄을 식을
계속 이어가는 문자로 끝내는 것이 좋다.
반대로 한 줄에 여러 식을 넣을 때는 세미콜론으로 구분할 수 있다.
TIP
REPL
에서 세미콜론 추론이 너무 공격적이거나 또는 여러 식을 한꺼번에 붙여 넣어야 하는 경우 :
paste
모드
를 활용하라. :
paste
를 입력하고 여러분이 원하는 코드를 입력한 다음
Ctrl
-
D
를 눌러서 모드를 끝내라.
2.2
변수 정의
스칼라에서는 변수
variable
가 불변(읽기 전용)인지 아닌지 (읽기
-
쓰기 ) 선언 시 지정할 수 있다.
우린 이미 변경 불가능한 ‘변수’
1
를
val
이라는 키워드로 선언할 수 있다는 것을 안다 (이를 값
객
체
value
object
라고 생각하라 ).
val array: Array[String] = new Array(5)
대부분의 변수가 힙에 할당된 객체를 참조한다는 점에서 스칼라는 자바와 비슷하다. 방금 본
array
라는 참조는 다른
Array
를 가리키도록 재할당될 수 없다. 하지만 배열의 원소는 다음과
같이 변경 가능하다.
1
역주_ 변수(
variable
)라는 말 자체가 변할 수 있는 값이란 뜻이다. 하지만 프로그램 안에서 어떤 값에 이름을 붙이는 경우 변수라고 하는
경우도 많다. 그래서
val
변수,
var
변수라고 말하기도 한다. 따라서 스칼라에서 변수라는 말이 항상 참조 대상을 대입을 통해 바꿀 수 있
는 이름만을 지칭하지는 않는다는 점에 유의하라. 사실 함수형 언어 계통에서는
val
로 선언한 것을 변수라고 부르기보다는 그냥 값이나
이름이라고 부르는 것을 더 좋아한다.
85
2
장
입력은 조금만, 일은 더 많이
scala
>
val array
:
Array
[
String
]
=
new Array
(
5
)
array
:
Array
[
String
]
=
Array
(
null
,
null
,
null
,
null
,
null
)
scala
>
array
=
new Array
(
2
)
<
console
>
:
8
:
error
:
reassignment to val
array
=
new Array
(
2
)
scala
>
array
(
0
)
=
"
Hello
"
scala
>
array
res1
:
Array
[
String
]
=
Array
(
Hello
,
null
,
null
,
null
,
null
)
val
은 선언 시 반드시 초기화해야 한다.
이와 비슷하게 변경 가능한 변수는
var
라는 키워드로 선언할 수 있다. 이런 변수는 변경 가능하
므로 나중에 바꿀 수 있지만, 그럼에도 불구하고 반드시 선언할 때 초기화해야 한다.
scala
>
var stockPrice
:
Double
=
100
.
0
stockPrice
:
Double
=
100
.
0
scala
>
stockPrice
=
200
.
0
stockPrice
:
Double
=
200
.
0
분명히 하자면 우리는
stockPrice
자체의 값을 바꿨다. 하지만
stockPrice
가 가리키는 ‘객체’
를 변경할 수는 없다.
Double
이 불변이기 때문이다.
자바에서 기본 타입
primitive
type
이라고 부르는
char
,
byte
,
short
,
int
,
long
,
float
,
double
,
boolean
은 근본적으로 객체(참조 타입)ㄱ와 다르다. 실제로 이런 기본 타입에는 객체도 참조
도 존재하지 않는다. 단지 ‘원래의’ 값만 존재한다. 스칼라는 좀 더 일관성 있게 객체지향적이기
위해 노력하고 있다. 그래서 스칼라에서는 이런 타입도 참조 타입과 마찬가지로 실제로 메서드
가 있는 객체다 (
8
.
2
절 ‘참조 타입과 값 타입’을 보라 ).
val
이나
var
선언 시 반드시 초기화해야 한다는 규칙에는 몇 가지 예외가 있다. 예를 들어 타입
의 생성자 매개변수에
val
이나
var
를 사용할 수 있다. 그러면 매개변수가 그 타입의 필드가 된
다. 이때
val
을 사용하면 변경 불가능,
var
를 사용하면 변경 가능 필드다.
86
1
부
스칼라와의 만남
다음
REPL
세션을 보자. 여기서는
Person
클래스를 정의하면서 변경 불가능한 이름 (
name
)과
변경 가능한 나이(
age
) 필드를 만든다 (아마도 시간이 지남에 따라 사람들이 나이를 먹기 때문
이라고 생각한다 ).
//
src
/
main
/
scala
/
progscala2
/
typelessdomore
/
person
.
sc
scala
>
class Person
(
val name
:
String
,
var age
:
Int
)
defined class Person
scala
>
val p
=
new Person
("
Dean Wampler
",
29
)
p
:
Person
=
Person
@
165a128d
scala
>
p
.
name
//
name
값을
보여준다
.
res0
:
String
=
Dean Wampler
scala
>
p
.
age
//
age
값을
보여준다
.
res2
:
Int
=
29
scala
>
p
.
name
=
"
Buck Trends
"
//
변경할
수
없다
!
<
console
>
:
9
:
error
:
reassignment to val
p
.
name
=
"
Buck Trends
"
^
scala
>
p
.
age
=
30
//
변경할
수
있다
!
p
.
age
:
Int
=
30
NOTE
_
var
나
val
키워드는 어떤 참조가 다른 객체를 참조하도록 변경될 수 있는지(
var
), 또는 없는지(
val
)
여부만 지정한다. 참조가 가리키는 대상 객체의 내부 상태를 변경 가능한지 여부는 지정하지 않는다.
변경으로 인해 생길 수 있는 버그 유형을 방지하기 위해 가능한 한 변경 불가능한 값을 활용하라.
예를 들어 해시 기반의 맵에 변경 가능한 객체를 키로 사용하는 것은 위험하다. 해당 객체의 내
용이 바뀌면
hashCode
메서드의 반환값이 달라질 것이다. 그래서 바뀐 해시값으로는 원래 객
체와 대응시켰던 값의 원래 위치를 찾지 못할 수도 있다.
더 흔한 것은 여러분이 사용 중인 객체를 다른 누군가가 변경해서 생기는 예기치 못한 동작이다.
양자 물리에서 빌려온 용어를 사용해서 이런 버그를 유령 같은 원격 작용
spooky
action
at
a
distance
이
Get 프로그래밍 스칼라: 실용적인 스칼라 활용법을 익히는 가장 확실한 실전 바이블 (2.11.x 버전 기반) now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.