449
10
장
스칼라 객체 시스템 I
드의 반대 ) 메서드로 컴파일할 수 있다. 하지만 실행 시점에 그 메서드가 호출되면 여기 있는
???
메서드가 호출되면서 실제로는
NotImplementedError
(
http
://
bit
.
ly
/
1G2zzia
)를
던진다. 이 메서드는
8
.
9
절 ‘내포된 타입’에서 가장 먼저 소개했다.
●
def
identity
[
A
] (
x
:
A
):
A
그냥 인자
x
를 반환한다. 아무런 변화가 필요 없을 때 콤비네이터 메서드에 전달할 함수로
이 메서드가 유용하다. 예를 들어 어떤 작업 흐름에서
map
을 호출해서 컬렉션의 원소를 변
환하는 경우, 해당 변환에 사용자가 원하는 설정 가능한 함수를 전달할 수 있다. 하지만 아
무 변환이 필요 없다면 이
identity
메서드를 대신 전달하면 된다.
●
def
implicitly
[
T
] (
implicit
e
:
T
):
T
[
T
:
M
]
이라는 맥락 바운드로 암시적 인자 목록이 지정된 경우, 컴파일러는
(
implicit
arg
:
M
[
T
])
형태의 암시적 인자 목록을 추가하게 된다 (실제 이름은
arg
가 아니며, 컴파
일러가 만들어낸 유일한 이름이 된다 ).
implicitly
를 호출하면 인자인
arg
를 반환한다.
이에 대해서는
5
.
1
.
1
절 ‘
implicitly
사용하기’에서 설명했다.
이제 객체지향 설계에서 아주 중요한 주제인 객체의 동등성 검사를 다루자.
10.6
객체의 동등성
인스턴스에 대한 신뢰할 만한 동등성 검사를 제대로 구현하기는 어렵다. 조슈아 블로크
Joshua
Block
의 유명한 책 『
Effective
Java
』(애디슨 웨슬리 )
2
나
AnyRef
.
eq
(
http
://
bit
.
ly
/
1yMkEDW
)의
스칼라독 페이지에서는 좋은 동등성 검사에 대한 요구 사항을 정리하고 있다.
마틴 오더스키
Martin
Odersky
, 렉스 스푼
Lex
Spoon
, 빌 베너스
Bill
Venners
도
equals
와
hashCode
메서
드를 작성하는 방법에 대한 좋은 글, “
How
to
Write
an
Equality
Method
in
Java
”(
http
://
bit
.
ly
/
13a2sBR
)를 썼다. 케이스 클래스에 대해서는 이런 메서드가 자동으로 생성된다는 점
을 기억하자.
사실 나는
equals
와
hashCode
메서드를 직접 사용해본 적이 결코 없다. 내가 동등성 검사를 필
2
역주_ 『이펙티브자바(
2
판)』(이병준역,인사이트)
450
2
부
기본기 다지기
요로 하거나,
Map
에서 키로 사용 (이 경우
hashCode
를 사용한다 )해야 하는 객체는 모두 케이스
클래스라는 사실을 발견했다!
CAUTION
_
동등성 메서드 중 일부는 다른 언어의 동등성 메서드와 이름이 같다. 하지만 그 의미가 다를 때
가 있다!
동등성을 검사하기 위해 사용하는 다른 메서드를 살펴보자.
10.6.1
equals
메서드
케이스 클래스를 사용해서 서로 다른 동등성 메서드의 동작을 보여줄 것이다.
//
src
/
main
/
scala
/
progscala2
/
objectsystem
/
person
-
equality
.
sc
case class Person
(
firstName
:
String
,
lastName
:
String
,
age
:
Int
)
val p1a
=
Person
("
Dean
",
"
Wampler
",
29
)
val p1b
=
Person
("
Dean
",
"
Wampler
",
29
)
val p2
=
Person
("
Buck
",
"
Trends
",
30
)
equals
메서드는 값 사이의 동등성을 검사한다. 즉,
obj1
equals
obj2
는
obj1
과
obj2
가 같은
값인 경우에만 참이다. 이 둘이 같은 인스턴스를 가리킬 필요는 없다.
p1a equals p1a
//
=
true
p1a equals p1b
//
=
true
p1a equals p2
//
=
false
p1a equals null
//
=
false
null equals p1a
//
java
.
lang
.
NullPointerException
을
던진다
.
null equals null
//
java
.
lang
.
NullPointerException
을
던진다
.
따라서
equals
는 예를 들면 자바의
equals
메서드나 루비의
eql
?
메서드와 같다.
451
10
장
스칼라 객체 시스템 I
10.6.2
==와 != 메서드
==
는 여러 다른 언어에서 연산자지만, 스칼라에서는 메서드다. 스칼라
2
.
10
에서
==
는
Any
에서
final
로 정의되어 있고,
equals
에 위임한다.
2
.
11
에서는 다른 구현을 사용하지만, 동작은 기본
적으로 동일하다.
p1a
==
p1a
//
=
true
p1a
==
p1b
//
=
true
p1a
==
p2
//
=
false
따라서 이 메서드는
equals
와 완전히 동일하며, 값의 동등성을 검사한다. 예외는
null
이 왼쪽
에 있는 경우뿐이다.
p1a
==
null
//
=
false
null
==
p1a
//
=
false
null
==
null
//
=
true
(
컴파일러는
항상
true
가
나온다고
경고를
표시한다
.)
null
==
null
이 참이어야 할까? 실제로는 경고를 발생시킨다.
<
console
>
:
8
:
warning
:
comparing values of types Null and Null using
`
==
'
will always yield true
여러분이 예상할 수 있듯이
!
=
는
==
를 반전시킨 것이다. 즉, 이는
!(
obj1
==
obj2
)
와 같다.
p1a
!
=
p1a
//
=
false
p1a
!
=
p1b
//
=
false
p1a
!
=
p2
//
=
true
p1a
!
=
null
//
=
true
null
!
=
p1a
//
=
true
null
!
=
null
//
=
false
(
컴파일러는
항상
false
가
나온다고
경고를
표시한다
.)
452
2
부
기본기 다지기
NOTE
_
자바,
C
#에서
==
연산자는 참조 동등성을 검사하지, 값 동등성을 검사하지 않는다. 반면 스칼라의
==
연산자는 값 동등성을 검사한다.
10.6.3
eq
와
ne
메서드
eq
메서드는 참조 동등성을 검사한다. 즉,
obj1
eq
obj2
는
obj1
과
obj2
가 메모리의 같은 위치
를 가리킬 때 참을 반환한다. 이런 메서드는
AnyRef
에서만 정의된다.
p1a eq p1a
//
=
true
p1a eq p1b
//
=
false
p1a eq p2
//
=
false
p1a eq null
//
=
false
null eq p1a
//
=
false
null eq null
//
=
true
(
컴파일러는
항상
true
가
나온다고
경고를
표시한다
.)
컴파일러는
null
==
null
에 대해 경고를 표시하는 것처럼
null
eq
null
에 대해서도 경고를 표
시한다.
따라서
eq
는 자바,
C
#의
==
연산자처럼 작동한다.
ne
메서드는
eq
를 반전시킨 것이다. 즉,
ne
는
!(
obj1
eq
obj2
)
와 같다.
p1a ne p1a
//
=
false
p1a ne p1b
//
=
true
p1a ne p2
//
=
true
p1a ne null
//
=
true
null ne p1a
//
=
true
null ne null
//
=
false
(
컴파일러는
항상
false
가
나온다고
경고를
표시한다
.)
10.6.4
Array
의 동등성과
sameElements
메서드
스칼라에서 두
Array
의 내용을 비교한 결과는 당연히 그래야만 할 것 같은 결과와는 다르다.
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.