Home Kotlin - 코틀린의 다양한 메서드
Post
Cancel

Kotlin - 코틀린의 다양한 메서드

코틀린 메서드

  • 확장 함수
  • infix 함수 (중위 함수)
  • inline 함수
  • 지역 함수

확장 함수

우선 확장 함수가 나타나게 된 배경부터 알아보자.

Kotlin은 Java와 100% 호환하는 것을 목표로 한다.

이런 목표로 인해 기존 Java 코드 위에 자연스럽게 Kotlin 코드를 추가할 수 있는 방안에 대해 고민하게 된다.

이 부분이 가능하다면 Java 코드에서 새로운 기능을 만들 때 val/var, null-safety 같은 코틀린의 특성을 활용할 수 있게 된다는 장점을 갖는다.

이러한 부분을 충족시키기 위해 고민하다가 나온 방안이 어떤 클래스 안에 있는 메서드처럼 호출할 수 있지만, 함수는 밖에 만들 수 있도록 한다. 이다.

밖에 있는 메서드를 마치 클래스 안에 있는 멤버 함수처럼 쓸 수 있도록 하자는 것이다.

위 개념이 확장 함수이다.

1
2
3
4
5
6
7
8
fun main() {
	val str = "ABC"
	println(str.lastChar())
}

fun String.lastChar(): Char {
	return this[this.length - 1]
}
  • 위의 예시는 문자열의 마지막 글자를 가져오는 메서드이다.
  • String.lastChar()
    • String 클래스를 확장하는 것이다.
    • this를 이용해 실제 클래스의 값에 접근할 수 있다. (수신 객체)
  • str.lastChar()
    • 마치 원래 String에 존재했던 멤버함수 처럼 사용할 수 있다.

그런데 확장함수가 public이고 그 내부에서 수신객체 클래스의 private 함수를 가져온다면?

캡슐화가 깨진다.

  • 따라서 확장함수는 클래스에 있는 private 또는 protected 멤버를 애초에 가져올 수 없다.

만약 멤버함수와 확장함수의 시그니처가 같다면?

1
2
3
4
5
6
7
public class Person {
	public int nextYearAge() {
		System.out.println("멤버 함수");
		return this.age + 1;
	}
	//...
}
1
2
3
4
fun Person.nextYearAge(): Int {
	println("확장 함수")
	return this.age + 1
}
  • 멤버함수가 우선적으로 호출된다.
  • 따라서 확장 함수를 만들어 놨는데 후에 다른 기능의 같은 멤버 함수가 생긴다면 멤버 함수에 우선순위가 생기기 때문에 예기치 않은 오류가 발생할 수 있어 주의해야 한다.

확장 함수가 오버라이드 된다면?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
open class Train(
	val name: String = "새마을기차",
	val price: Int = 5_000,
)

fun Train.isExpensive(): Boolean {
	println("Train 확장함수")
	return this.price >= 10000
}

class Srt : Train("SRT", 40_000)

fun Srt.isExpensive(): Boolean {
	println("Srt 확장함수")
	return this.price >= 20000
}

이 경우 어떤 것이 우선순위를 가질까?

1
2
3
4
5
6
val train: Train = Train()
train.isExpensive() // Train의 확장함수

val srt1: Train = Srt() // Train의 확장함수

val srt2: Srt = Srt() // Srt의 확장함수
  • 즉 변수를 선언한 타입에 따라 해당 확장 함수가 호출되는 것을 알 수 있다.
    • 어떤 객체인지는 중요하지 않다.
    • 해당 변수의 현재 타입이 우선순위를 갖는다.

infix 함수 (중위 함수)

함수를 호출하는 새로운 방법이다.

이전 포스트에서의 downTo, step과 같은 함수이다.

  • 변수.method(argument) 대신 변수 method argument 의 형식으로 사용한다.
1
2
3
4
5
6
7
fun Int.add(other: Int): Int {
	return this + other
} //확장 함수

infix fun Int.add2(other: Int): Int {
	return this + other
}
1
2
3
4
5
6
7
//사용

3.add(4) // 확장 함수

3.add2(4) // 가능

3 add2 4 // 중위 함수의 활용

inline 함수

함수가 호출되는 대신, 함수를 호출한 지점에 함수 본문을 그대로 복사 붙여넣기 하고 싶은 경우에 사용한다.

예시를 보자.

  • 함수를 파라미터로 전달할 때의 함수를 계속 중첩해서 쓰는 경우 함수 call chain에 오버헤드가 생겨 inline 함수를 사용하게 되는데 이 때오버헤드를 줄일 수 있다.
    • 그러나 inline 함수의 사용은 성능 측정과 함께 신중하게 사용되어야 한다.

지역 함수

함수 안에 함수를 선언할 수 있는 것을 뜻한다.

1
2
3
4
5
6
7
8
9
10
11
fun createPerson(firstName: String, lastName: String): Person {
	if (firstName.isEmpty()) {
		throw IllegalArgumentException()
	}

	if (lastName.isEmpty()) {
		throw IllegalArgumentException()
	}

	return Person(firstName, lastName, 1)
}
  • 조건문이 중복된 부분을 줄이고 싶게 생겼다.
  • 이 때 지역 함수를 활용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
fun createPerson(firstName: String, lastName: String): Person {
	fun validateName(name: String, fieldName: String) {
		if (name.isEmpty()) {
			throw IllegalArgumentException()
		}
	}

	validateName(firstName, "firstName")
	validateName(lastName, "lastName")

	return Person(firstName, lastName, 1)
}
  • 메서드 내부에 메서드를 만들어 활용했다.
  • 함수로 추출하면 좋을 것 같은 부분이지만 추출한 메서드가 현재 함수 내에서만 사용될 것 같을 때 사용할 수 있다.

그런데 depth가 깊어지기도 하고 코드가 그렇게 깔끔하지 않다는 것을 느낄 수 있다.

따라서 잘 사용되지 않는다. 오히려 Person 클래스와 같은 곳에서 저러한 검증 메서드를 만들어주는 것이 더 깔끔하다.

정리

  • Java 코드가 있는 상황에서 Kotlin 코드로 추가 기능 개발을 하기 위해 확장 함수와 확장 프로퍼티가 등장했다.
    • 확장 함수는 원본 클래스의 private, protected 멤버 접근이 되지 않는다.
    • 멤버함수와 확장함수 중 멤버함수에 우선권이 부여된다.
    • 확장함수는 현재 타입을 기준으로 호출된다.
    • Java에서는 static 함수를 쓰는 것 처럼 Kotlin의 확장함수를 사용할 수 있다.
  • 함수 호출 방식을 바꿔주는 infix 함수가 존재한다.
  • 함수를 복사 - 붙여넣기 하는 inline 함수가 존재한다.
  • Kotlin에서는 함수 내부에 함수를 선언할 수 있고 이를 지역함수라고 부른다.
This post is licensed under CC BY 4.0 by the author.