Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
Tags
- Fisher discriminant analysis
- MySQL
- SCPC
- 근구하기
- 인공지능
- 로지스틱 회귀
- undirected graphical model
- 자바ORM표준JPA프로그래밍
- Numerical optimization
- 알고리즘
- vector미분
- graphical models
- chapter02
- 알고리즘대회
- CH01
- 선형분류
- 1차예선
- falsePosition
- Perceptron Convergence theorem
- 이것이 MySQL이다
- chapter01
- directed graphical model
- 델타 rule
- secant
- bisection
- 선형판별분석
- 5397번
- 개발순서
- 2018
- 스터디
Archives
- Today
- Total
computer_study
[Kotlin] 09. 제네릭스 본문
알지 못하는 타입의 데이터를 조작하는 코드를 작성할 수 있게 해준다.
9.1 타입 파라미터
9.1.1 제네릭 선언
class TreeNode<T>(val data: T){
private val _children = arrayListOf<TreeNode<T>>()
var parent: TreeNode<T>? = null
private set
...
fun addChild(data: T) =
...
}
fun main(){
val root = TreeNode("Hello").apply{
addChild("World")
addChild("!!!")
}
...
}
- 타입 파라미터는 클래스 이름 바로 뒤에
- 타입 파라미터는 관습적으로 T, U, V등의 짧은 대문자를 사용한다.
- java처럼 raw타입을 사용할 수 없고, TreeNode<String> 처럼 구체적인 타입을 지정하거나 TreeNode<U>처럼 타입 인자로 받은 타입을 지정해주어야 한다.
- 제네릭 클래스에서와 달리 프로퍼티나 함수를 제네릭으로 선언할 때는 타입 파라미터를 fun이나 val/var 바로 뒤에 위치 시킨다
9.1.2 바운드와 제약
데이터 타입에 정보가 필요한 경우에 상위 바운드에 선언하여 제약을 할 수 있다.
fun <T : Number>TreeNode<T>.average(): Double{
var count = 0
var sum = 0.0
...
return sum/count
}
///////
val StringTree = TreeNode("Hello").apply{
addChildren("World", "!!!")
}
println(stringTree.average()) // 이렇게 호출한다면 제약이 있기에 컴파일 오류가 발생한다
- 자바는 T extends Number이지만 코틀린은 T: Number이다.
- 타입 파라미터를 널이 아닌 타입으로 제한하는 경우에도 사용
fun <T: Any> notNullTreeOf(data: T) = TreeNode(data)
9.1.3 타입 소거와 구체화
JVM은 기존 자바와 새 버전의 자바 호환을 위해, 새 타입 인자에 대한 정보가 코드에서 지워지고(타입 소거) 다른 타입으로 합쳐진다.
자바에선 해결을 위해 케스트나 리플렉션을 사용하지만 코틀린에선 구체화를 사용한다.
(인라인한 함수에 대해서만 구체화한 타입 파라미터 사용 가능)
fun <T>TreeNode<T>.cancellableWalkDepthFirst(
onEach: (T) -> Boolean
): Boolean{
...
}
inline fun <reified T> TreeNode<*>.isInstanceOf() =
cancellableWalkDepthFirst{ it is T }
////// 호출 시
fun main(){
val tree = TreeNode<Any>("abc").addChild("def").addChild(123)
println(tree.isInstanceOf<String>())
}
//// 아래와 같아진다
fun main(){
val tree = TreeNode<Any>("abc").addChild("def").addChild(123)
println(tree.cancellableWalkDepthFirst { it is String })
}
9.2 변성
9.2.1 변성: 생산자와 소비자 구분
- 생산자
- T타입의 값을 반환하는 연산만 제공하고 T 타입의 값을 입력으로 받는 연산은 제공하지 않는 제네릭 타입
- X가 생산자 역할을 한다면, T를 공변적으로 선언할 수 있고, A가 B의 하위 타입이면 X<A>가 X<B>의 하위 타입이 된다.
- 소비자
- T타입의 값을 입력으로 받기만 하고 결코 T타입의 값을 반환하지 않는 제네릭 타입
- X가 소비자 역할을 한다면 T를 반공변적으로 선언할 수 있고, B가 A의 하위 타입이면 X<A>가 X<B>의 하위 타입이 된다.
9.2.2 선언 지점 변성
타입 파라미터의 변성을 선언 자체에 지정하는 방법
interface List<out T>{ // T에 대해 공변적으로 만드는 방법
val size: Int
fun get(index: Int): T
}
/////
// List<Int>가 List<Number의 하위타입
- 어떤 타입 파라미터가 항상 out위치에서 쓰이는 경우에만 파라미터를 공변적으로 선언할 수 있다
class Writer<in T>{
fun write(value: T){
println(value)
}
}
- 반공변인 타입 파라미터 앞에 in 키워드를 붙일 수 있다.
- 제네릭 타입이 소비자 역할을 할 때 타입 파라미터를 in으로 표시할 수 있다.
9.2.3 프로젝션을 사용한 사용 지점 변성
프로젝션 : 제네릭 타입을 사용하는 위치에서 특정 타입 인자 앞에 in/out을 붙이는 방법.
코틀린의 프로젝션은 자바의 extends/super 와일드카드와 같은 역할을 한다
- TreeNode<out Number>
- 자바에선 TreeNode<? extends Number>
- TreeNode<in Number>
- 자바에선 TreeNode<? super Number>
9.2.4 스타 프로젝션
*로 표기된다.
타입 인자가 타입 파라미터의 바운드 안에서 아무 타입이나 될 수 있다는 사실을 표현
코틀린의 스타 프로젝션은 자바의 ? 와일드 카드에 대응
- TreeNode<*>
- 자바에선 TreeNode<?>
9.3 타입 별명
제네릭 타입을 다룰 때 도움이 되는 언어 기능
긴 이름을 짧게 부를 수 있도록 해준다.
typealias IntPredicate = (Int) -> Boolean // typealias [별명] = [실제 타입]
typealias IntMap = HashMap<Int, Int>
fun readFirst(filter: IntPredicate) =
generateSequence{ readLine()?.toIntOrNull() }.firstOrNull(filter)
fun main(){
val map = IntMap().also{
it[1] = 2
it[2] = 3
}
}
// 파라미터 포함도 가능
typealias ThisPredicate<T> = T.() -> Boolean
typealias MultiMap<K, V> = Map<K, Collection<V>>
'스터디 > 코틀린 완벽 가이드' 카테고리의 다른 글
[Kotlin] 12. 자바 상호 운용성 (0) | 2022.06.08 |
---|---|
[Kotlin] 08. 클래스 계층 이해하기 (0) | 2022.06.03 |
[Kotlin] 07. 컬렉션과 I/O 자세히 알아보기 (0) | 2022.06.03 |
[Kotlin] 06. 특별한 클래스 사용하기 (0) | 2022.05.27 |
[Kotlin] 05. 고급 함수와 함수형 프로그래밍 활용하기 (0) | 2022.05.26 |
Comments