코틀린
[Kotlin In Action] 3장. 함수 정의와 호출
newwisdom
2021. 9. 1. 08:49
반응형
Kotlin in Action 책에서 각 챕터의 Summary를 보며 부족한 키워드만 후라닥 정리하는 글.
안드정이 코틀린 인 액션 책 스터디하면서 정리한 자료도 참고할 예정 땡큐땡큐
컬렉션 정의
- 코틀린에서 컬렉션은 두가지로 분리됨
- Collection : 불변
- MutableCollection : 가변
- 자체 콜렉션이 아닌 자바 콜렉션 사용: 자바 코드와 상호작용 용이
함수를 호출하기 쉽게 만들기
이름있는 인자
fun <T> joinToString(
collection: Collection<T>,
separator: String = ", ",
prefix: String = "",
postfix: String = ""
): String
joinToString(collection, separator = " ", prefix = " ", postfix = ".")
- 인자 중 하나라도 이름을 명시하면, 그 뒤 에 오는 모든 인자는 이름을 명시해야 함
- 이름있는 인자 사용하면 오버라이드 할 필요성이 사라지고, 인자값 이름으로 파라미터를 쉽게 구별할 수 있다.
디폴트 파라미터 값
- 이름 없는 인자: 일부를 생략하면 뒷부분의 인자들 생략
- 이름 붙인 인자: 지정하고 싶은 인자를 이름을 붙여 지정
joinToString(collection, ", ", "", "")
joinToString(collection)
joinToString(collection, "; ")
joinToString(collection,
postfix = ";", prefix = "# ")
최상위 함수
- 자바의 정적 메서드로 변환됨
package strings
fun joinToString(...): String { ... }
최상위 프로퍼티
- const는 원시 타입과 String에만 가능
- 정적 변수로 변환됨
// 함수 호출될 때마다 증가하는 변수 용도
var opCount = 0
fun performOperation() {
opCount++
// ...
}
fun reportOperationCount() {
println("Operation performed $opCount times")
}
확장 함수
- 어떤 클래스의 멤버 함수인 것처럼 호출할 수 있지만, 그 클래스의 밖에 선언된 함수
package strings
fun String.lastChar(): Char = this[this.length -1]
"mazzi".lastChar()
- 여기서 클래스의 이름인 String은 수신 객체 타입
- 확장 함수가 호출되는 대상이 되는 값(객체)인 this를 수신 객체라 함
- this는 생략 가능
- 확장함수는 오버라이딩할 수 없음
- 확장 함수 안에서 수신 객체의 메서드나 프로퍼티 사용 가능 (private 멤버나 protected 멤버만 접근 불가)
- 확장 함수 이름과 클래스 멤버 함수 이름이 같을 경우 멤버 함수가 우선순위가 더 높음
- 확장 함수를 임포트할 때 as로 다른 이름으로 임포트 가능(이름이 충돌할 경우 주로 사용)
import strings.lastChar as last
val c = "mazzi".last()
확장 프로퍼티
- 기존 클래스 객체에 대한 프로퍼티 형식 구문으로 사용할 수 있는 API 추가
- 상태를 저장할 방법이 없지만, 프로퍼티 문법으로 더 짧게 코드를 작성할 수 있음
- 초기화가 불가능하고, get()을 필수 구현해야함
val String.first: Char
get() = get(0)
var StringBuilder.lastChar: Char
get() = get(length ‐ 1)
set(ch: Char) {
this.setCharAt(length ‐ 1, ch)
}
➕ 더 보면 좋을 자료
컬렉션 처리
가변 길이 인자
- 파라미터 앞에 vararg를 붙음
- * 연산자로 배열 내용을 펼칠 수도 있음
fun listOf<T>(vararg values: T): List<T> { ... }
fun main(args: Array<String>) {
val list = listOf(1, 2, 3, 4)
// 배열은 스프레드 연산자(*)로 전달
val arglist = listOf("args: ",*args)
// listOf(args) ‐‐> List<Array<String>>이 됨
}
중위 호출 (infix 수식어)
- 일반 메서드를 중위 호출이 가능하게 만들기 위해 infix 변경자를 메서드 앞에 선언해야 함
- 중위 호출의 인수는 한개만 가능함
- `객체 메서드이름 유일인자` 순으로 작성
infix fun Any.to(other: Any) = Pair(this, other)
1.to("one")
1 to "one"
val (number, name) = 1 to "one"
- Pair의 실제 선언은 제네릭 타입이지만, 이를 생략중
구조 분해 선언
- 객체가 가지고 있는 여러 값을 분해해서 여러 변수에 한꺼번에 초기화할 수 있음
- 구조 분해 선언 내부에서는 각 변수를 초기화하기 위해 componentN이라는 함수 호출
val (number, name) = Pair(1, "one")
val (_, name) = Pair(1, "one") // 사용하지 않는 변수
for ((index, element) in list.withIndex()) { // IndexedValue<Int>
}
map.mapValues { (key, value) ‐> "$value!" } // 람다에서의 분해 선언
map.mapValues { (_, value) ‐> "$value!" }
- 데이터 클래스 주 생성자에 있는 프로퍼티에 대해서는 컴파일러가 자동으로 componentN 함수를 만들어줌
- 일반 클래스에서는 다음과 같이 구현
class Crew(val name: String, val nickname: String) {
operator fun component1() = name
operator fun component2() = nickname
}
코드 다듬기
로컬 함수
- 함수 내부에 함수를 중첩해서 만듦
- 로컬 함수는 바깥 함수의 파라미터 변수에 접근 가능
- 로컬 함수에 파라미터 전달하여 사용 가능
fun saveUser(user: User) {
// 로컬 함수
fun validate(value: String, fieldName: String) {
if (value.isEmpty()) {
// user.id : 자신이 속한 바깥 함수의 파라미터와 변수 사용할 수 있음
throw IllegalArgumentException("Can't save user ${user.id}: " +
"empty $fieldName")
}
}
validate(user.name, "Name")
validate(user.address, "Address")
}
중복 코드를 줄일 수 있으며, 작게 쪼개진 함수들이 많은 경우 로컬 함수를 사용해 공통처리
➕ 더 보면 좋을 강추 자료
반응형