본문 바로가기
책 정리/Kotlin IN ACTION

3. 함수 정의와 호출

by 이석준석이 2021. 8. 29.


1. 함수 파라미터에 Defualt 값을 정의하면, 다양한 생성자를 정의할 필요성이 줄어든다, 또한 이름붙인 파라미터를 사용하면 함수 호출의 가독성을 향상시킬 수 있다.

  • 자바와는 다르게, 파라미터에 어떤 인자를 세팅할 것인지 명시할 수 있다.
  • 명시되지 않은 값은 Default 값으로 초기화된다.
class Person (
    val age: Int = 0,
    val name: String = "홍길동"
) {

}

fun main() {
    val person1 = Person()
    assertEquals(0, person1.age)
    assertEquals("홍길동", person1.name)

    val person2 = Person(age = 10)
    assertEquals(10, person2.age)
    assertEquals("홍길동", person2.name)

    val person3 = Person(age = 30, name = "둘리")
    assertEquals(30, person3.age)
    assertEquals("둘리", person3.name)
}

2. 최상위 함수를 직접 선언할 수 있다.

  • 클래스 내에 함수를 선언하는 것이 아닌, 소스코드 내 최상위에 함수를 선언할 수 있다.
    • 자바에서는, @NoArgsConstructor(access=AccessLevel.Private) 로 선언한 뒤, 공통함수를 선언하는 것을
    • 코틀린에서는 최상위 함수로 해결한다.
// xxx.kt 클래스에 최상위로 함수를 선언할 수 있다.
// import 하여 사용하면 된다.

fun sum(a : Int, b: Int) : Int {
    return a + b
}

fun sub(a : Int, b : Int) = a - b

3. 최상위 프로퍼티를 직접 선언할 수 있다.

  • 최상위 함수와 마찬가지로 최상위 프로퍼티를 선언할 수 있다.
// xxx.kt 클래스에 최상위로 함수를 선언할 수 있다.
// import 하여 사용하면 된다.

const val constVal = 1
val valueTest = 2
var variableTest = 3

// 자바로 디컴파일한 결과
public final class HighestValueKt {
   public static final int constVal = 1;
   private static final int valueTest = 2;
   private static int variableTest = 3;

   public static final int getValueTest() {
      return valueTest;
   }

   public static final int getVariableTest() {
      return variableTest;
   }

   public static final void setVariableTest(int var0) {
      variableTest = var0;
   }
}

4. 확장함수를 사용하여 외부 라이브러리에 정의된 클래스를 소스코드 변경없이 확장할 수 있다.

  • 이 확장은 런타임에 부가적인 비용이 들지 않는다.
// 자바의 Integer 클래스를 확장하여, 받은 숫자보다 큰지 확인하는 메소드를 만들었다.
fun String.longerThan(num: Int) = length > num

fun main() {
    assertTrue("abcdefg".longerThan(5))
    assertFalse("abcdefg".longerThan(10))
}

 

런타임에 부가적인 비용이 들지 않는 이유

  • 자바에서는 위의 확장함수를 정적함수로 변환하며 (우리는 그저 정적함수를 한개 만든 것일 뿐이다!)
    • 첫번째 파라미터로 수신 객체 타입(확장을 적용한 클래스) 을 준다.
    • 두번째 이후 파라미터로, 확장함수의 파라미터를 준다.
public final class Chapter3Kt {
   public static final boolean longerThan(@NotNull String $this$longerThan, int num) {
      Intrinsics.checkNotNullParameter($this$longerThan, "<this>");
      return $this$longerThan.length() > num;
   }
}

5. 중위(infix) 호출을 통해 인자가 하나 밖에 없는 메소드를 깔끔한 구문으로 호출할 수 있다.

  • map 에 값을 추가하는 과정에서 아래와 같은 코드를 볼 수 있다.
fun main() {
    val map = mapOf<Int, String>(1 to "one", 2 to "two", 3 to "three")
}
  • [to] 함수의 내부를 확인해보면
    • A.to(B) 인 경우 Pair(a, b) 를 반환한다.
    • map 의 원소를 저장할 때, Pair 를 저장할 수 있으므로, 위의 코드를 사용하여 Pair값을 map 에 저장할 수 있었다.
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
  • 중위 (infix) 함수는 파라미터가 한개인 경우, 확장함수를 깔끔한 구문으로 사용할 수 있다.
fun main() {
    val map = mapOf<Int, String>(1 key_val "one", 2.key_val("two"))
}

infix fun <A, B> A.key_val(that: B) : Pair<A, B> = Pair(this, that)

6. 3중따옴표를 이용한 정규식에서는 역슬래시(\) 를 제외하고는 이스케이프(\\) 할 필요가 없다.


7. 로컬함수를 이용하여 코드를 더 깔끔하게 유지하고, 중복을 제거할 수 있다.

  • 로컬 함수는 함수 내에서 함수를 사용하는 방식이다.
    • 로컬함수는 바깥 함수의 파라미터에 접근 가능하다.
  • 자바에서는 private 메소드로 계속 추출하여 코드를 이해하기 어려울 수 있는 점을 코틀린에서는 로컬 함수를 통해 해결했다.
class Person (
    val name: String,
    val phone: String
)

fun validatePerson(person: Person): Boolean {
    fun validateName() = person.name.length in 2..4
    fun validatePhone() = person.phone.matches("""^\d{2,3}-\d{3,4}-\d{4}${'$'}""".toRegex())

    return validateName() && validatePhone()
}

fun main() {
    val p = Person("홍길동", "010-1234-1234")
    assertTrue(validatePerson(p))
}
  • 위의 코드를 Person 에 대한 확장함수로 바꾼 뒤, 로컬함수로도 사용할 수 있다.
class Person (
    val name: String,
    val phone: String
)

fun Person.validatePerson(): Boolean {
    fun validateName() = name.length in 2..4
    fun validatePhone() = phone.matches("""^\d{2,3}-\d{3,4}-\d{4}${'$'}""".toRegex())

    return validateName() && validatePhone()
}

fun main() {
    val p = Person("홍길동", "010-1234-1234")
    p.validatePerson()
}

'책 정리 > Kotlin IN ACTION' 카테고리의 다른 글

4. 클래스, 객체 인터페이스  (0) 2021.09.10
2. 코틀린 기초  (0) 2021.08.28
1. 코틀린이란 무엇이며, 왜 필요한가?  (0) 2021.08.28