Kotlin 기본 문법
08 Dec 2021함수
fun max(a: Int, b: Int): Int {
return if (a > b) a else b
}
-
함수는
fun
키워드로 선언한다. - 파라미터 이름 뒤에 타입을 쓴다.
- 최상위 수준에 정의할 수 있다.
- 블록이 본문인 함수
문(statement) vs. 식(expression)
코틀린의 if는 문장이 아닌 식으로서 결과를 만들 수 있다. 또한, 식은 다른 식의 하위 요소로 계산에 참여할 수 있지만, 문은 자신을 둘러싸는 가장 안쪽 블록의 최상위 요소로 존재하고 아무런 값을 만들어내지 않는다.
fun max(a: Int, b: Int): Int = if (a > b) a else b
// 반환 타입 생략
fun max(a: Int, b: Int) = if (a > b) a else b
- 식이 본문인 함수
- 반환 타입을 적지 않아도 컴파일러가 본문을 해석하면서 결과 타입을 함수 반환 타입으로 정한다.
- 타입 추론(type inference): 컴파일러가 타입을 분석해 구성 요소 타입을 정해주는 기능
변수
val question = "How many Harry Potter movies are there?"
val answer = 7
val anotherAnswer: int = 7
val year: Int
year = 2021
- 키워드로 변수 선언 시작
val
은 변경 불가능한 참조를 저장하는 변수로 초기화한 후에 재대입이 불가능하다var
은 값을 변경할 수 있으며 변수 타입은 바뀌지 않는다.₩- 타입 지정을 생략할 수 있다.
- 타입 지정을 할 경우, 변수 이름 뒤에 명시한다.
- 타입을 지정하지 않으면 컴파일러가 초기화식을 분석해서 변수 타입으로 지정한다.
- 초기화를 하지 않고 변수를 선언할 때는 타입 추론이 어려우므로 변수 타입을 명시해야 한다.
val message: String
if (canPerformOperation()) {
message = "Success"
} else {
message = "Failure"
}
- val 변수는 블록을 실행할 때 한 번만 초기화 되어야 한다.
- 컴파일러가 확인할 수 있다면 조건에 따라 여러 값으로 초기화할 수 있다.
val languages = arrayListOf("java")
languages.add("kotlin")
- val 참조 자체는 불변이지만, 참조가 가리키는 객체의 내부 값은 변경될 수 있다.
var x = 0
fun incrementX() {
x += 1
}
- 변수를 최상위 수준에 정의할 수 있다.
문자열 템플릿
fun main(args: Array<String>) {
val name = if (args.size > 0) args[0] else "World"
println("Hello $name")
}
fun main2(args: Array<String>) {
if (args.size > 0) {
println("Hello ${args[0]}")
}
}
fun main3(args: Array<String>) {
println("Hello ${if (args.size > 0) args[0] else "World"}")
}
-
$
를 변수 앞에 추가해서 문자열 안에 변수를 사용할 수 있다. -
변수 이름이 아닌 식도 중괄호({})로 싸서 문자열 템플릿 안에 넣을 수 있다.
-
중괄호로 둘러싼 식 안에는 큰 따옴표(““)를 쓸 수 있다.
클래스
class Person{
val name: String,
var isMarried: Boolean
}
val person = Person("Harry", true)
println(person.name) // "Harry"
println(person.isMarried) // true
person.isMarried = false
- 필드와 접근자 메서드를 프로퍼티가 대신한다.
- val로 선언한 프로퍼티는 읽기 전용
- 읽기 전용 프로퍼티는 getter만 선언
- var로 선언한 프로퍼티는 변경 가능
- 변경 가능한 프로퍼티는 getter, setter 모두 선언
- 프로퍼티를 직접 사용해도 자동으로 getter를 호출한다.
- 프로퍼티를 변경할 때도 직접 사용해서 변경한다.
class Rectangle(var height: Int, var width: Int) {
val isSquare: Boolean
get() {
return height == width
}
// get() = height == width 도 가능
}
fun main() {
r = Rectangle(12, 12)
println(r.isSquare)
}
- 값을 필드에 저장하지 않고 프로퍼티 게터를 선언하여 접근할 때마다 확인할 수 있다.
enum & when
enum class Color (
val r: Int, val g: Int, val b: Int // 상수 프로퍼티 정의
) {
// 상수를 생성할 때 프로퍼티 값 지정
RED(255, 0, 0), ORANGE(255, 165, 0), YELLOW(255, 255, 0),
GREEN(0, 255, 0), BLUE(0, 0, 255), INDIGO(75, 0, 130), VIOLET(238, 130, 238);
fun rgb() = (r * 256 + g) * 256 + b
}
fun main() {
println(Color.BLUE.rgb()) // 255
}
-
enum은 soft keyword로 다른 곳에서는 이름에 사용할 수 있다.
- enum 클래스 안에 프로퍼티나, 메소드 정의가 가능하다.
- 클래스 안에 메서드를 정의할 때는 상수와 메서드 사이에
;
을 사용해야 한다.
fun getMnemonic(color: Color) =
when (color) {
Color.RED -> "Richard"
Color.ORANGE -> "Of"
Color.YELLOW -> "York"
Color.GREEN -> "Gave"
Color.BLUE -> "Battle"
Color.INDIGO -> "In"
Color.VIOLET -> "Vain"
}
fun main() {
println(getMnemonic(Color.GREEN)) // "Gave"
}
if
처럼when
도 값을 만들어내는 식이다.- 분기 끝에 break를 붙이지 않아도 된다.
fun getWarmth(color: Color) = when (color) {
Color.RED, Color.ORANGE, Color.YELLO -> "warm"
Color.GREEN -> "neutral"
Color.BLUE, Color.INDOGO, Color.VIOLET -> "cold"
}
fun main() {
println(getWarmth(Color..BLUE)) // "cold"
}
- 하나의 분기에서 여러 값을 사용할 때는
,
를 이용하여 구분한다.
import Color.*
fun mix(c1: Color, c2: Color) =
when(setOf(c1, c2)) {
setOf(RED, YELLOW) -> ORANGE
setOf(YELLOW, BLUE) -> GREEN
setOf(BLUE, VIOLET) -> INDIGO
else -> throw Exception("Dirty color")
}
fun main() {
println(mix(BLUE, YELLOW)) // "GREEN"
}
- when의 분기 조건에서 임의의 객체를 허용한다.
import Color.*
fun mixOptimized(c1: Color, c2: Color) =
when {
(c1 == RED && c2 == YELLOW) || (c1 == YELLOW && c2 == RED) -> ORANGE
(c1 == YELLOW && c2 == BLUE) || (c1 == BLUE && c2 == YELLOW) -> GREEN
(c1 == BLUE && c2 == VIOLET) || (c1 == VIOLET && c2 == BLUE) -> INDIGO
else -> throw Exception("Dirty Color")
}
fun main() {
println(mixOptimized(BLUE, YELLOW))
}
- 인자가 없는 when 식을 사용하여 불필요한 객체 사용을 막을 수 있다.
- when에 인자가 없으려면 분기의 조건이 boolean 결과를 계산하는 식이어야 한다.