중요한 점! inline 키워드는 Deprecated 됨. 대신 value 키워드와 @JvmInline 어노테이션 사용
- 하나의 값을 보유하는 객체 또한 inline으로 만들 수 있다
- 기본 생성자 프로퍼티가 하나인 클래스 앞에 inline을 붙이면, 해당 객체를 사용하는 위치가 모두 해당 프로퍼티로 교체
- inline 클래스의 메소드는 모두 정적 메소드로 만들어진다.
@JvmInline
value class Name(private val value: String) {
fun greet() {
print("Hello, $value")
}
}
- 인라인 클래스는 다른 자료형을 wrapping 해서 새로운 자료형을 만들 때 많이 사용
- 측정 단위를 표현하거나 타입 오용으로 발생하는 문제를 막을 때 사용
측정 단위를 표현할 때
interface Timer {
fun callAfter(time: Int, callback: () -> Unit)
}
- callAfter 함수의 time 파라미터는 어떤 단위를 받는지 알 수 없음
- 밀리초를 받는지, 초를 받는지, 분을 받는지 알 수 없어 여러 문제가 발생할 수 있음
- 파라미터 이름에 측정 단위를 붙여줌으로서 해결할 수 있지만, 함수를 사용할 때 이름이 노출되지 않을 수 있으므로 문제가 발생할 가능성이 있음
- 또한 리턴 값에는 이름을 붙일 수 없음
- 타입에 제한을 걸면 이러한 오류를 해결할 수 있고 inline 클래스를 활용하면 더 효율적으로 만들 수 있다
@JvmInline
value class Minutes(val minutes: Int) {
fun toMillis(): Millis = Millis(minutes * 60 * 1000)
}
@JvmInline
value class Millis(val milliseconds: Int) {
}
interface User {
fun decideAboutTime(): Minutes
fun wakeUp()
}
interface Timer {
fun callAfter(time: Millis, callback: () -> Unit)
}
- 프론트엔드 개발에서는 px, mm, dp 등 다양한 단위를 사용하는데 이러한 단위를 제한할 때 활용하면 좋다
- 또한 객체 생서을 위해서 DSL-like 확장 프로퍼티를 만들어 두어도 좋다
타입 오용으로 발생하는 문제를 막을 때
- 어떠한 Entity가 여러 ID를 가지고 있을 때 모두 같은 Int 자료형이라면, 실수로 잘못된 값을 넣을 수 있다.
- 이럴 경우 Int 자료형의 값을 inline 클래스로 만들어 활용하여 해결할 수 있다.
@JvmInline
value class StudentId(val studentId: Int)
@JvmInline
value class TeacherId(val TeacherId: Int)
@JvmInline
value class SchoolId(val schoolId: Int)
class Grades(
val studentId: StudentId,
val TeacherId: TeacherId,
val schoolId: SchoolId
) {
}
인라인 클래스와 인터페이스
- 인라인 클래스도 인터페이스를 구현할 수 있다
package chapter7.item47
interface TimeUnit {
val millis: Long
}
@JvmInline
value class MinutesWithInterface(private val minutes: Long): TimeUnit {
override val millis: Long
get() = minutes * 60 * 1000
}
@JvmInline
value class MillisWithInterface(private val milliseconds: Long): TimeUnit {
override val millis: Long
get() = milliseconds
}
fun setUpTimerWithInterface(time: TimeUnit) {
val millis = time.millis
}
fun main() {
setUpTimerWithInterface(MinutesWithInterface(1000))
setUpTimerWithInterface(MillisWithInterface(1000))
}
- 하지만 이 코드는 클래스가 inline으로 동작하지 않는다.
- 따라서 해당 콛는 클래스를 inline으로 만들었을 때 얻을 수 있는 장점이 없다
- 인터페이스를 통해서 타입을 나타내려면, 객체를 래핑해서 사용해야하기 때문
typealias
- typealias 를 사용하면, 타입에 새로운 이름을 붙여 줄 수 있음
typealias nanos = Int
typealias hours = Int
val nano: nanos = 10
val hour: hours = 10
- 하지만 두 typealias 모두 단순하게 Int를 나타내기 때문에 실수로 둘을 혼용해서 잘못입력할 수 있음
- 따라서 단위 등을 표현하려면, 파라미터 이름 또는 클래스, 인라인 클래스를 이용하는게 바람직하다
'Reading Record > 이펙티브 코틀린' 카테고리의 다른 글
[이펙티브 코틀린] Item 48. 더 이상 사용하지 않는 객체의 레퍼런스를 제거하라 (0) | 2022.06.13 |
---|---|
[이펙티브 코틀린] Item 46. 함수 타입 파라미터를 갖는 함수에 inline 한정자를 붙여라 (0) | 2022.06.12 |
[이펙티브 코틀린] Item 45. 불필요한 객체 생성을 피하라 (0) | 2022.06.12 |
[이펙티브 코틀린] Item 38. 연산 또는 액션을 전달할 때는 인터페이스 대신 함수 타입을 사용하라 (0) | 2022.06.07 |
[이펙티브 코틀린] Item 37. 데이터 집합 표현에 data 한정자를 사용하라 (0) | 2022.06.07 |