함수 정의와 호출 2

함수 정의와 호출 1에 이어 함수 정의와 호출 2를 시작한다.


확장 프로퍼티

확장 프로퍼티를 사용하면 기존 클래스 객체에 대한 프로퍼티 형식의 구문으로 사용할 수 있는 API를 추가할 수 있다. 확장 프로퍼티로 작성하면 아무 상태도 가질 수 없지만 (확장 함수와 같다) 코드를 더 짧게 작성할 수 있어서 편한 경우가 있다.

1
2
val String.lastChar: Char
get() = get(length - 1)

가변 인자

코틀린과 자바에서의 가변 인자의 차이점은 두 가지이며 나머지는 모두 동일하다.

  • 자바에서는 …를 사용하지만 코틀린에서는 vararg를 파라미터 앞에 붙인다.
  • 자바에서는 배열을 그대로 파라미터로 넘겼지만 코틀린에서는 스프레드(*)로 풀어서 넘겨야 한다.
    1
    2
    3
    4
    fun main(args: Arrays<String>) {
    val list = listOf("args: ", *args)
    println(list)
    }

중위 호출

중위 호출은 수신 객체의 인자가 하나뿐인 일반 메소드나 하나뿐인 확장 함수에 중위 호출을 사용할 수 있다. 호출 시에는 수신 객체와 유일한 메소드 인자 사이에 메소드 이름을 넣는다. 이때 객체, 메소드 이름, 유일한 인자 사이에는 공백이 들어가야 한다.

1
2
1.to("one") // <- "to" 메소드를 일반적인 방식으로 호출함
1 to "one" // <- "to" 메소드를 중위 호출 방식으로 호출함

구조 분해 선언

구조 분해 선언은 Pair와 같은 순서쌍을 표현하는 클래스에 대해 분해 후 즉시 초기화를 할 수 있는 기능을 얘기한다. 위에서 예를 들었던 1 to "one"은 그 결과가 Pair이다. 이 결과로 변수를 즉시 초기화 할 수 있다.

1
val (number, name) = 1 to "one"

문자열과 정규식

코틀린에서는 문자열의 split함수를 조금 더 다루기 쉽고 명확하게 할 수 있도록 노력했다. 코틀린 문자열의 split함수는 일반 문자열과 정규화 두 개를 모두 전달 받을 수 있는데 정규화의 경우 Regex 타입의 값만 받을 수 있도록 하였는데 "\\!|-".toRegex()와 같은 방식으로 Regex 타입을 만든다.

정규화 문법을 작성 시 이스케이프 문자로 \을 넣는데 """ ... """와 같이 3중 따옴표로 문자열을 묶을 경우 이스케이프 문자가 필요 없어 다음과 같이 정규화 문법을 작성할 수 있다.

1
2
3
4
5
6
7
8
fun ParsePath(path: String) {
val regex = """(.+)/(.+)\.(.+)""".toRegex()
val matchResult = regex.matchEntire(path)
if (matchResult != null) {
val (directory, filename, extension) = matchResult.destructed
println("Dir: $directory, name: $filename, ext: $extension")
}
}

로컬 함수와 확장

코틀린에서는 함수에서 추출한 함수를 원 함수 내부에 중첩시킬 수 있다. 그렇게 하면 문법적인 부가 비용을 들이지 않고도 깔끔하게 코드를 조직할 수 있다. 자바에서는 함수 안에서 함수를 다시 정의하지 못하므로 클래스 내부에 같은 레벨의 함수로 정의하거나 별도의 내부 클래스로 함수를 넣어 사용하기도 하지만 코틀린은 함수 안에서 또 다른 함수를 선언할 수 있다. 아래는 그 예다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class User(val id: Int, val name: String, val address: String)

// 1. 일반적인 코드
fun saveUser(user: User) {
if (user.name.isEmpty()) {
throw IllegalArgumentException("Can't save user ${user.id}: empty Name")
}
if (user.address.isEmpty()) {
throw IllegalArgumentException("Can't save user ${user.id}: empty Address")
}
// user 저장
}

// 2. 로컬 함수 사용
fun saveUser(user: User) {
fun validate(user: User, value: String, field: String) {
if (value.isEmpty()) {
throw IllegalArgumentException("Can't save user ${user.id}: empty $field")
}
}
validate(user, user.name, "Name")
validate(user, user.address, "Address")
// user 저장
}

// 3. 바깥 함수 파라미터 접근
fun saveUser(user: User) {
fun validate(value: String, field: String) {
if (value.isEmpty()) {
throw IllegalArgumentException("Can't save user ${user.id}: empty $field")
}
}
validate(user.name, "Name")
validate(user.address, "Address")
// user 저장
}

// 4. 확장 함수로 변경
fun Uuser.validateBeforeSave() {
fun validate(value: String, field: String) {
if (value.isEmpty()) {
throw IllegalArgumentException("Can't save user ${id}: empty $field")
}
}
validate(name, "Name")
validate(address, "Address")
}

fun saveUser(user: User) {
user.validateBeforeSave()
// user 저장
}

출처 : Kotlin in Acation

#

댓글

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×