포스트

Kotlin의 다양한 함수 다루기


확장함수


Kotlin은 Java와 100% 호환을 추구한다.


1
2
3
4
5
6
7
// 확장 함수
// String. -> String Class를 확장 -> 수신객체 타입
// 함수 안에서는 this를 통해 인스턴스 접근
// this -> 수신객체
fun String.lastChar(): Char {
    return this[this.length - 1]
}


실제 사용 예시

1
2
    val str = "ABC"
    println(str.lastChar())
  • 출력 : C
  • 수신객체 타입을 String으로 설정 했기 때문에 str에 바로 lastChar 메소드를 호출 가능


의문

  • 확장함수public이고 확장함수에서 수신객체 클래스private함수를 가져오면 캡슐화가 깨지는거 아닌가?
    • 그래서 확장함수는 클래스에 있는 private 또는 protected멤버를 가져올 수 없다


  • 맴버함수와 확장함수의 시그니처(이름)가 같다면?

Java 메소드

1
2
3
4
public int nextYearAge() {
    System.out.println("멤버 함수");
    return this.age + 1;
  }

Kotlin 메소드

1
2
3
4
fun Person.nextYearAge(): Int {
    println("확장 함수")
  return this.age + 1
}


위와 같이 Java의 맴버 함수와 Kotlin의 확장 함수 중 어떤 것을 호출 하나?

1
2
3
4
fun main() {
    val person = Person("A", "B", 100)
  person.nextYearAge()
}
  • 출력 : 멤버 함수
  • 확장 함수멤버 함수 중에서 멤버 함수를 우선적으로 호출한다.
  • 확장 함수를 만들었지만, 다른 기능의 똑같은 멤버 함수가 생기면 오류 발생


확장 함수가 오버라이딩되는 경우

  • 타입을 우선(해당 변수의 현재 타입)으로 두고 호출하게 된다.


확장함수 요악

  1. 확장함수는 원본 클래스의 private, protected멤버 전근이 안된다.
  2. 멤버함수, 확장함수 중 멤버함수에 우선권이 있다.
  3. 확장함수는 현재 타입을 기준으로 호출

Java에서 Kotlin의 함수를 사용하는 법

  • Kotlin에 존자하는 함수를 정적 메소드를 부르는 것처럼 사용 가능
  • ex). StringUtilsKt.lastChar("ABC"); 처럼 Kt를 붙인 정적 메소드로 호출 가능
  • 확장함수는 확장프로퍼티와도 연결된다.


확장 프로퍼티

1
2
val String.lastChar: Char
  get() = this[this.length - 1]
  • 확장 프로퍼티의 원리 : 확장함수 + custom getter와 동일




infix함수 (중위함수)


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

  • downTo, step (중위 함수 호출)
  • 변수,함수이름(argument)가 아니라, 변수 함수이름 argument (중위 함수 호출)


infix함수 예시

1
2
3
4
5
6
7
8
9
// 일반적인 함수
fun Int.add(other: Int): Int {
    return this + other
}

// infix함수
infix fun Int.add2(other: Int): Int {
    return this + other
}
  • infix는 멤버함수에도 붙일 수 있다.
  • infix함수는 두가지 방법으로 호출 가능
    • 3.add2(4)
    • 3 add2 4




inline함수

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

inline함수 예시

1
2
3
inline fun Int.add(other: Int): Int {
  return this + other
}
  • inline은 함수를 호출하는 것이 아닌, 로직 자체가 함수를 부르는 쪽에 복붙 된 것!
  • 함수를 파라미터로 전달할 때 오버헤드를 줄일 수 있기 때문에 사용
    • 함수를 중첩해서 쓰는 경우, 함수가 함수를 부르는 과정이 반복되기 때문에 call chainoverhead발생

하지만, inline은 성능 측정과 함께 신중하게 사용해야 한다.

  • Kotlin라이브러리는 최적화가 잘되어 있기 때문에 적절하게 inline이 붙어 있어 쓸일이 많지 않음.




지역함수


함수안에 함수를 선언할 수 있다.


중복되는 코드

1
2
3
4
5
6
7
8
9
10
11
fun createPerson(firstName: String, lastName: String): Person {
  if (firstName.isEmpty()) {
    throw IllegalArgumentException("firstName은 비어있을 수 없습니다 : $firstName")
  }

  if (lastName.isEmpty()) {
    throw IllegalArgumentException("lastName은 비어있을 수 없습니다 : $lastName")
  }

  return Person(firstName, lastName, 1)
}


수정된 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
fun createPerson(firstName: String, lastName: String): Person {

  fun validateName(name: String, fieldName: String) {
    if (name.isEmpty()) {
      throw IllegalArgumentException("${fieldName}은 비어있을 수 없습니다 : $name")
    }
  }

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

  return Person(firstName, lastName, 1)
}
  • validateName이라는 함수를 createPerson함수 안에 선언
    • fun 안에 fun

함수를 추출하면 좋을 때, 함수 내에서만 사용하고 싶을 때 사용

  • 단점 : depth가 깊어 지기도 하고, 코드가 깔끔하지 않다.
  • 사실상 쓸 일이 별로 없을 듯
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.