1. 제네릭 (Generic)
fun <T> toFunction(value: T): () -> T = { value }
fun main(args: Array<String>) {
val func: () -> Int = toFunction<Int>(1170)
println(func())
}
2. 여러 타입을 인수로 받기
fun <T, R> toFunction(value1: T, value2: R): () -> T = { value1 }
fun main(args: Array<String>) {
val func: () -> Int = toFunction<Int, String>(1170, "test")
println(func())
}
3. 구체화된(Reified) 타입 매개변수
타입 매개변수는 is 연산자의 피연산자로 사용할 수 없다.
fun <T> check() {
val number = 0
if (number is T) // 오류
println("T는 Int 타입입니다.")
}
타입 매개변수를 is 연산자의 피연산자로 사용하고 싶으면 함수는 inline으로 선언 한 뒤, 타입 매개변수 앞에 reified를 붙여주면 된다.
inline fun <reified T> check() {
val number = 0
if (number is T)
println("T는 Int 타입입니다.")
}
4. 제네릭이 적용된 클래스 / 인터페이스 상속, 구현하기
interface Plusable<T> {
operator fun plus(other: T): T
}
class Rectangle(val width: Int, val height: Int) : Plusable<Rectangle> {
override fun plus(other: Rectangle): Rectangle {
return Rectangle(width + other.width, height + other.height)
}
}
5. 특정 타입을 상속, 구현하는 타입만 인수로 받기
특정 타입을 구현하는 타입만 인수로 받으려면, 상속을 할 때처럼 타입 매개변수 뒤에 :타입이름 을 적어준다.
: 타입1, 타입2 와 같이 적으면 여러 개를 지정할 수도 있다.
interface ValueContainer {
fun getValue(): Int
}
class AAA : ValueContainer {
override fun getValue(): Int {
return 1102
}
}
fun <T : ValueContainer> T.printValue() {
println(this.getValue())
}
fun main(args: Array<String>) {
AAA().printValue()
}
6. in / out 키워드
out T는 자바의 ? extends T와 같고, in T는 자바의 ? Super T와 같다. 타입 인수를 *로 지정하면, 타입 인수가 무엇이든 상관없이 AAA 타입을 대입할 수 있다.
class AAA<out T>
class BBB<in T>
fun main(args: Array<String>) {
val aaaSub = AAA<Int>()
val aaaSup: AAA<Any> = aaaSub
val bbbSub = BBB<Any>()
val bbbSup: BBB<Int> = bbbSub
val star: AAA<*> = aaaSub
}
7. .. 연산자와 범위 표현식
fun main(args: Array<String>) {
val intRange: IntRange = 1..10
intRange.forEach { print("$it ") }
val charRange: CharRange = 'A'..'Z'
if ('B' in charRange) {
println("대문자입니다.")
}
}
8. 배열 (Array)
fun main(args: Array<String>) {
val integers: Array<Int> = arrayOf(10, 20, 30) // 배열 초기화
println(integers.size)
println(integers[2])
for (i in integers) {
print("$i ")
}
}
val size = 10
var array = Array(size) { 0 } // 0으로 초기화
9. 배열을 가변 인수로 활용하기
vararg 키워드를 사용하여 배열 속에 들어있는 원소들을 가변 인수로 활용할 수 있다. vararg 키워드는 java의 ... 키워드와 동일한 역할을 한다.
fun printAll(vararg tokens: String) {
for (token in tokens) {
print("$token ")
}
}
fun main(args: Array<String>) {
val numbers = arrayOf("what's", "your", "name?")
printAll(*numbers)
printAll("hello", "kotlin")
}
void printAll(String... tokens){
}
10. 열거 클래스 (Enum)
열거 클래스는 정해진 집합 내의 값을 표현하기 위해 사용한다. 열거 클래스에 들어가는 식별자를 열거 상수(Enum Constant)라고 한다.
enum class Mode {
SELECTION, PEN, SHAPE, ERASER
}
fun main(args: Array<String>) {
val mode: Mode = Mode.PEN
when (mode) {
Mode.SELECTION -> println("선택 모드")
Mode.PEN -> println("펜 모드")
Mode.SHAPE -> println("도형 모드")
Mode.ERASER -> println("지우개 모드")
}
}
11. 열거 클래스에 프로퍼티와 멤버 함수 선언하기
enum class Mode(val number: Int) {
SELECTION(0),
PEN(1),
SHAPE(2),
ERASER(3);
fun printNumber() {
println("모드 $number")
}
}
fun main(args: Array<String>){
val mode: Mode = Mode.ERASER
println(mode.number) // 3
mode.printNumber() // 모드 3
}
12. 열거 클래스 활용하기
enum class Mode {
SELECTION, PEN, SHAPE, ERASER
}
fun main(args: Array<String>) {
val shapeMode: Mode = Mode.SHAPE
println(shapeMode.name) // 열거 상수의 이름
println(shapeMode.ordinal) // 열거 상수의 순서
val modes: Array<Mode> = Mode.values() // 모든 열거 상수들을 배열로 반환
for(mode in modes){
println(mode)
}
println(Mode.valueOf("PEN").ordinal)
}
13. sealed 클래스
sealed 클래스는 자신의 중첩 클래스에만 상속을 허용하는 클래스이다.
sealed class Outer {
class One : Outer()
class Two : Outer()
}
class Three : Outer() // 1.1 버전 이후로는 같은 파일 내에서 가능
fun main(args: Array<String>) {
val instance: Outer = Outer.One()
val text: String = when (instance) {
is Outer.One -> "첫 번째"
is Outer.Two -> "두 번째"
is Three -> "세 번째"
}
}
14. 위임된 프로퍼티 (Delegated Property)
코틀린에서는 Getter / Setter 구현을 다른 객체에 맡길 수 있는 문법을 제공한다.
class Sample {
var number: Int by OnlyPositive()
}
class OnlyPositive {
private var realValue = 0
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
return realValue
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
realValue = if (value > 0) value else 0
}
}
fun main(args: Array<String>){
val sample = Sample()
sample.number = -50
println(sample.number)
sample.number = 100
println(sample.number)
}
프로퍼티를 대리하는 객체는 아래의 두 함수를 멤버 함수로 갖고 있어야 한다.
operator fun getValue(thisRef: Any?, property: KProperty<*>): T
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T)
15. 클래스 위임 (Class Delegation)
코틀린에서는 인터페이스의 구현을 다른 클래스에 맡길 수 있는 문법도 제공한다.
interface Interface {
fun abc()
}
class ClassDelegator : Interface {
override fun abc() {
println("기본 구현")
}
}
class Sample : Interface by ClassDelegator()
fun main(args: Array<String>) {
Sample().abc()
}
16. Pair 클래스 : 두 변수를 하나로 묶기
Pair 클래스를 이용하면 두 변수를 하나로 묶을 수 있다.
fun divide(a: Int, b: Int): Pair<Int, Int> = Pair(a / b, a % b)
fun main(args: Array<String>) {
val (q, r) = divide(10,3)
println("몫: $q, 나머지: $r")
}
17. to 확장 함수 : 두 값을 간단히 Pair로 묶기
to는 모든 타입에 적용되는 확장 함수이다. to 확장 함수를 이용하여 Pair 객체를 간단히 생성할 수 있다.
fun main(args: Array<String>) {
val test: Pair<Int, Double> = 10 to 3.14
println(test) // (10, 3.14)
}
18. Triple 클래스 : 세 변수를 하나로 묶기
Triple 클래스는 제네릭을 이용하여 세 가지 타입의 값을 보관한다.
fun calculateCircle(r: Int): Triple<Int, Double, Double> =
Triple(2 * r, 2 * r * 3.14, r * r * 3.14)
fun main(args: Array<String>) {
val (diameter, _, area) = calculateCircle(5)
println("지름 : $diameter")
println("넓이 : $area")
}
19. Comparable 인터페이스 : 클래스를 비교 가능하게 만들기
class Node(var value: Int) : Comparable<Node> {
override fun compareTo(other: Node): Int =
when {
this.value < other.value -> -1
this.value > other.value -> 1
else -> 0
}
}
fun main(args: Array<String>) {
val node1 = Node(10)
val node2 = Node(20)
println(node1 < node2) // true
}
20. ClosedRange 인터페이스 : 닫힌 구간을 표현하는 인터페이스
fun main(args: Array<String>) {
val intRange = 1..10
val longRange = 1L..100L
val floatRange = 1.0..2.0
val charRange = 'A'..'Z'
println(intRange.start) // 1
println(longRange.endInclusive) // 100
println(floatRange.contains(1.1)) // true
println(charRange.isEmpty()) // false
}
ClosedFloatRange와 ClosedDoubleRange 클래스는 in 연산자를 사용할 수 없다.
21. Iterable 인터페이스 : 클래스가 반복자를 지원하도록 하기
fun main(args: Array<String>) {
val prog: IntProgression = 3..7
println(prog.first) // 3
println(prog.last) // 7
println(prog.step) // 1
prog.forEach { print("$it ") } // 3 4 5 6 7
}
22. Progression과 관련된 함수
fun main(args: Array<String>) {
val prog1 = 7 downTo 3 // 7 6 5 4 3
val prog2 = (3..7).reversed() // 7 6 5 4 3
println(prog1 == prog2) // true
val prog3 = (1..10) step 3 // 1 4 7 10
val prog4 = 10 downTo 2 step 3 // 10 7 4
val prog5 = 2 until 5 // 2 3 4
}
출처 : 초보자를 위한 코틀린 200제 / 엄민석
'Kotlin' 카테고리의 다른 글
[Kotlin] inline에 대하여 - inline, noinline, crossinline, reified (4) | 2020.10.11 |
---|---|
[Kotlin] Kotlin의 Delegates 알아보기 - observable, vetoable (0) | 2020.10.01 |
[Kotlin] 코틀린 문법 정리 - 03 (0) | 2020.04.11 |
[Kotlin] 코틀린 문법 정리 - 02 (0) | 2020.04.05 |
[Kotlin] 코틀린 문법 정리 - 01 (0) | 2020.04.03 |