코틀린에서는 두 가지 타입의 변수를 선언할 수 있다.
val name: String = "HSK" // 불변 변수, 읽기만 가능, 수정 불가
var age: Int = 27 // 가변 변수
코틀린에서는 주요 자료형으로 Boolean, Numeric, Characters, String, Arrays 등을 지원하며 각 자료형은 객체로 취급되며, 그에 따라 함수를 가질 수 있다.
val myBoolean: Boolean = true
val myInt: Int = 10
val myLong: Long = 10L
val myFloat: Float = 10.0f
val myDouble: Double = 10.0
val myChar: Char = 'A'
val myString: String = "Hello, Kotlin!"
val myArray: Array<Int> = arrayOf(1, 2, 3)
코틀린의 제어문은 if, when 등을 제공한다. 이는 조건에 따라 다른 코드를 실행하는데 사용되며, 코틀린의 특징 중 하나는 if와 when이 표현식(expression)
이라는 점이다. 이로 인해 값을 반환할 수 있다.
val max = if (a > b) a else b
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> print("x is neither 1 nor 2")
}
코틀린의 반복문은 for, while, do-while 등을 제공한다.
val numbers = arrayOf(1, 2, 3)
for (number in numbers) {
println(number)
}
var x = 5
while (x > 0) {
println(x--)
}
do {
val y = retrieveData()
} while (y != null) // repeat while data is found
// for loop: 1부터 5까지의 숫자를 출력한다. ".." 연산자를 이용해 범위를 지정함
for (i in 1..5) {
println(i)
}
// until: 1부터 4까지의 숫자를 출력한다. "until"은 마지막 범위를 포함하지 않는다.
for (i in 1 until 5) {
println(i)
}
// step: 1부터 5까지 2씩 증가하며 숫자를 출력한다.
for (i in 1..5 step 2) {
println(i)
}
// downTo: 5부터 1까지 감소하며 숫자를 출력한다.
for (i in 5 downTo 1) {
println(i)
}
코틀린의 함수 선언은 fun
키워드를 사용한다. 함수는 매개변수를 가질 수 있으며, 매개변수는 타입과 함께 선언된다.
또한 함수는 반환 타입을 지정할 수 있다.
fun add(x: Int, y: Int): Int {
return x + y
}
println(add(5, 3)) // Output: 8
코틀린의 클래스는 class 키워드를 사용해 선언한다. 주 생성자와 보조 생성자를 가질 수 있으며 상속, 추상화, 인터페이스 등의 객체 지향 프로그래밍 특징을 지원한다.
class Person(name: String, age: Int) {
// Class Body
}
데이터 클래스는 'data' 키워드를 붙여 선언하며, 데이터를 보관하는 용도로 사용된다.
데이터 클래스를 생성하면 자동으로 'equals()', 'hashCode()', 'toString()', 'copy()' 등의 함수를 생성해준다.
data class Person(val name: String, val age: Int)
Sealed 클래스는 자신을 상속하는 클래스를 제한하며, 주로 when문에서 사용한다. 이를 통해 모든 경우의 수를 컴파일러 타임에 체크할 수 있어 런타임 에러를 방지
할 수 있다.
sealed class Result {
data class Success(val data: String): Result()
class Error(val error: Exception): Result()
}
Object 키워드를 사용하여 선언하는 클래스는 싱글턴 패턴을 구현할 때 사용된다. 이 클래스는 자동으로 한 개의 인스턴스만을 생성하고, 이 인스턴스를 통해 함수와 속성에 접근할 수 있다.
object Singleton {
fun doSomething() {
println("Do something")
}
}
자바의 정적 메서드 (static method)와 유사하게 사용된다. 클래스의 인스턴스를 생성하지 않고도 메서드를 호출 할 수 있다.
class MyClass {
companion object {
fun create(): MyClass = MyClass()
}
}
코틀린의 가장 강력한 특징 중 하나는 null 안전성이다.
자바와 같은 언어에서는 null 참조를 통해 오류가 발생할 가능성이 항상 있었다. 이러한 문제는 코드의 안전성을 해칠 뿐 아니라 버그를 유발하는 주요 원인이다.
코틀린에서는 이러한 문제를 방지하기 위해 null을 허용하는 타입
과 null을 허용하지 않는 타입
을 구분한다. 예를 들어, 'String?'는 nullable(null이 될 수 있는 타입)
이며, 'String'은 항상 non-null(null값을 가질 수 없는 타입)
이다. 이를 통해 컴파일 타임에서 null 참조 오류를 방지할 수 있다.
var name: String = "HSK" // Non-Null
name = null // 컴파일 오류
var nullableName: String? = "HSK" // Nullable
nullableName = null // 가능
그리고 null이 될 수 있는 타입에 접근할 때는 null 체크를 하거나, 안전 호출('?.
'), 엘비스 연산자('?:
'), non-null 단언 연산자('!!
')등을 사용하여 null 처리를 할 수 있다.
var nullableName: String? = "HSK"
println(nullableName.length) // 컴파일 오류
// Null 체크
if (nullableName != null) {
println(nullableName.length) // 가능
}
// 안전 호출
println(nullableName?.length) // 가능, nullableName이 null이면 null 반환
// 엘비스 연산자
println(nullableName?.length ?: "unknown") // 가능, nullableName이 null이면 "unknown" 반환
// non-null 단언 연산자
println(nullableName!!.length) // 가능, nullableName이 null이면 NullPointerException 발생
코틀린은 함수를 일급 객체로 취급하는 언어이다. 일급 객체란 함수를 변수에 할당하거나, 다른 함수에 인자로 전달하거나, 함수의 결과로 반환할 수 있다는 것을 의미한다.
이런 특징을 이용해 고차 함수와 람다식을 사용할 수 있다.
고차 함수는 다른 함수를 매개변수로 받거나 함수를 반환하는 함수를 의미한다.
이를 통해 함수의 로직을 동적으로 바꿀 수 있고, 코드의 재사용성을 높일 수 있다.
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
fun sum(a: Int, b: Int) = a + b
fun multiply(a: Int, b: Int) = a * b
fun main() {
val resultSum = calculate(10, 20, ::sum)
val resultMultiply = calculate(10, 20, ::multiply)
println("resultSum: $resultSum, resultMultiply: $resultMultiply")
}
위의 예시에서 calculate는 (Int, Int) -> Int 타입의 함수를 매개변수로 받는 고차 함수다. calculate 함수에 sum 함수나 multiply 함수를 인자로 전달해 함수의 동작을 바꿀 수 있다.
람다식은 이름 없는 함수로서, 코드의 간결성을 증가시키는데 유용하다.
람다식은 { 매개변수들 -> 본문 }
의 형태로 표현된다.
val sum: (Int, Int) -> Int = { a, b -> a + b }
val multiply: (Int, Int) -> Int = { a, b -> a * b }
위의 sum과 multiply는 각각 두 정수를 더하거나 곱하는 람다식이다. 이런 람다식을 고차 함수에 전달할 수 있다.
val resultSum = calculate(10, 20, sum)
val resultMultiply = calculate(10, 20, multiply)
또한 람다식은 고차 함수의 마지막 매개변수로 사용될 때, 괄호 밖에 위치할 수 있다. 이를 통해 DSL(Domain-Specific Language)과 같은 표현이 가능해진다.
val resultSum = calculate(10, 20) { a, b -> a + b }
val resultMultiply = calculate(10, 20) { a, b -> a * b }
'일급 객체'는 프로그래밍 언어에서 일부 데이터 형식이 다음과 같은 세 가지 특성을 모두 충족하는 경우를 의미합니다:
- 변수에 할당될 수 있어야 합니다.
- 객체의 인자로 전달될 수 있어야 합니다.
- 객체의 반환값으로 사용될 수 있어야 합니다.
이런 특성이 충족될 때 그 언어의 데이터 형식(함수, 숫자, 문자열 등)을 '일급 객체'라고 합니다. 일급 객체는 일급 시민(First-Class Citizen)이라고도 불리며, 이것은 해당 객체가 언어의 핵심 부분으로 취급된다는 의미입니다.
함수가 일급 객체인 언어에서는 함수를 변수에 할당하거나, 다른 함수의 인자로 전달하거나, 함수의 반환값으로 사용할 수 있습니다. 이러한 특성은 고차 함수(Higher-Order Functions)를 가능하게 합니다.
고차 함수는 함수를 매개변수로 받거나 함수를 결과로 반환하는 함수를 말합니다. 즉, 고차 함수는 함수가 일급 객체인 언어에서 가능한 개념입니다.
따라서, 일급 객체는 고차 함수와는 다른 개념이지만, 함수가 일급 객체인 특성이 고차 함수를 가능하게 하는 기반이라고 할 수 있습니다. 일급 객체는 언어의 더 광범위한 개념이며, 고차 함수는 그 특성을 활용하는 좁은 범위의 개념입니다.
코틀린에서는 let
, run
, with
, apply
, also
와 같은 스코프 함수를 제공한다. 이 함수들은 기본적으로 객체의 범위(스코프)를 지정
하고, 객체 내의 멤버들을 좀 더 효과적으로 활용
하게 도와준다.
let
함수는 주로 null 검사 및 처리
에 사용한다.
val list: List<String>? = null
list?.let {
// 이 블록 내에서 list는 null이 아님을 보장받음
println("List size is ${it.size}")
} ?: println("List is null.")
run
함수는 객체 내에서 여러 작업을 수행한 후 결과를 반환
할 때 주로 사용한다. run은 리시버 객체에서 호출
되며, 마지막 표현식의 결과를 반환
한다.
val result = "Hello, Kotlin!".run {
println(this)
length // 마지막 표현식인 length가 반환됨
}
println("String length: $result")
with 함수는 run과 비슷하지만, 리시버를 인자로 받아 리시버의 멤버에 접근
할 수 있다.
data class Person(var name: String, var age: Int)
val hsk = Person("HSK", 20)
with(john) {
println("Person's name: $name, age: $age")
age += 1
}
apply 함수는 리시버의 멤버를 변경하거나 초기화할 때 유용
하다. **apply는 리시버 객체를 반환
**한다.
data class Person(var name: String, var age: Int)
val hsk = Person("hsk", 20).apply {
age = 21
}
println("hsk's age: ${hsk.age}")
also 함수는 apply와 비슷하지만, 블록의 결과 대신 리시버 객체
를 반환한다. also는 주로 추가적인 연산을 체인으로 연결할 때 사용된다.
data class Person(var name: String, var age: Int)
val hsk = Person("hsk", 20).also {
println("Creating person with name ${it.name}")
}
println("Person's name: ${hsk.name}")
글 잘 봤습니다.