안녕하세요 이번엔 변수, 함수, 클래스 등 코틀린에서는 어떻게 선언하는지 알아보겠습니다.
1. Hello, Kotlin !
모든 언어를 시작할 때 가장 먼저 하는 거라고 할 수 있는"Hello, World"를 찍는 프로그램을 실행해 봤습니다.
fun main(){
println("Hello, Kotlin")
}
이런 간단한 코드에서도 코틀린의 문법 특성을 알 수 있습니다.
- 함수를 선언할 때 fun 키워드를 사용합니다.
- 함수를 최상위 수준에 정의할 수 있습니다. 자바와 달리 꼭 클래스 안에 함수를 넣어야 할 필요가 없습니다.
- 배열도 일반적인 클래스와 마찬가지로 코틀린에서는 자바와 달리 배열 처리를 위한 문법이 따로 존재하지 않습니다.
- System.out.println 대신에 println이라고 씁니다.
- 최신 프로그래밍 언어 경향과 마찬가지로 줄 끝에 세미콜론(;)을 붙이지 않아도 됩니다.
2. 함수
의미 있는 결과를 반환하는 함수의 경우 반환값의 타입을 어디에 지정해야 하는지를 알아보겠습니다.
fun max(a: Int,b: Int): Int { return if (a>b) a else b }
fun main(){
print(max(1,2))
}
코틀린의 함수 선언은 fun 키워드로 시작합니다. fun 다음에는 함수 이름이 오게 되고, 함수 이름 뒤에는 괄호 안에 파라미터 목록이 옵니다. 함수의 반환 타입은 파라미터 목록의 닫는 괄호 다음에 노는데, 괄호와 반환 타입 사이를 콜론(:)으로 구분해야 합니다.
자세하게 위 코드를 예시로 알아보겠습니다.
❤️ : 함수 이름
💛 : 파라미터 목록
💚 : 반환타입
💙 : 함수 본문
잠깐 알아가는 문(statement)과 식(expression)의 구분
코틀린에서 if는 식이지 문이 아닙니다. 식은 값을 만들어 내며 다른 식의 하위 요소로 계산에 참여할 수 있는 반면 문은 자신을 둘러싸고 있는 가장 안쪽 블록의 최상위 요소로 존재하며 아무런 값을 만들어내지 않는다는 차이가 있습니다. 자바에서는 모든 제어 구조가 문인 반면 코틀린에서는 루프를 제외한 대부분의 제어 구조가 식입니다. 제어 구조를 다른 식으로 엮어낼 수 있으면 여러 일반적인 패턴을 아주 간결하게 표현할 수 있습니다. 반면 대입문은 자바에서는 식이였으나 코틀린에서는 문이 되었습니다. 그로 인해 자바와 달리 대입식과 비교식을 잘못 바꿔 써서 버그가 발생하는 경우가 없습니다.
위의 함수를 더욱더 간결하게 표현할 수 있습니다.
앞의 함수 본문은 if 식 하나로만 이뤄져 있습니다. 이런 경우 중괄호를 없애고 return을 제거하면서 등호를 식 앞에 붙이면 더 간결한 함수를 표현할 수 있습니다.
fun max(a: Int,b: Int): Int = if (a>b) a else b
fun main(){
print(max(1,2))
}
본문이 중괄호로 둘러싸인 함수를 블록이 본문인 함수라 부르고, 등호와 식으로 이뤄진 함수를 식이 본문인 함수라고 부릅니다.
코틀린에서는 식이 본문인 함수가 자주 쓰입니다.
그런 함수의 본문 식에는 단순한 산술식이나 함수 호출 식뿐 아니라 if, when, try 등의 더 복잡한 식도 자주 쓰입니다.
반환 타입을 생략하면 위 함수를 더 간략하게 만들 수 있습니다.
fun max(a: Int,b: Int) = if (a>b) a else b
fun main(){
print(max(1,2))
}
여기서 반환 타입을 생략할 수 있는 이유는 코틀린은 "정적 타입 지정 언어이므로 컴파일 시점에 모든 식의 타입을 지정해야 하지 않나?"라는 생각을 할 수 있고 실제로 모든 변수나 모든 식에는 타입이 있으며, 모든 함수는 반환 타입이 정해져야 합니다. 하지만 식이 본문인 함수의 경우 굳이 사용자가 반환 타입을 적지 않아도 컴파일러가 함수 본문 식을 분석해서 식의 결과 타입을 함수 반환 타입으로 정해줍니다.
우리는 이런 기능을 앞서 배웠듯이 타입추론이라고 부르죠 !
🚨 주의해야 할 점은 식이 본문인 함수의 반환 타입만 생략 가능하다는 점에 유의하시면 됩니다! 🚨
📝 블록이 본문인 함수가 값을 반환한다면 반드시 반환 타입을 지정하고 return문을 사용해 반환 값을 명시해야 합니다.
3. 변수
코틀린에서는 타입 지정을 생략하는 경우가 흔하다고 볼 수 있습니다. 타입으로 변수 선언을 시작하면 타입을 생략할 경우 식과 변수 선언을 구별할 수 없죠. 그런 이유로 코틀린에서는 키워드로 변수 선언을 시작하는 대신 변수 이름 뒤에 타입을 명시하거나 생략하게 허용합니다.
// 예시
val question = "공공돌의 나이는?"
// 타입 표기 생략
val answer = 25
// 타입 표기
val answer: Int = 25
만약 초기화 식이 없다면 변수에 저장될 값에 대해 아무 정보가 없기 때문에 컴파일러가 타입을 추론할 수 없습니다.
따라서 그런 경우 타입을 반드시 지정해야 합니다.
변경 가능한 변수와 변경 불가능한 변수
변수 선언 시 사용하는 키워드는 두 가지가 있습니다.
- val(값을 뜻하는 value에서 가져옴) : 변경 불가능한(immutable) 참조를 저장하는 변수입니다. val로 선언된 변수는 일단 초기화하고 나면 재대입이 불가능합니다. 스위프트로 말하자면 let 변수와 같습니다.
- var(변수를 뜻하는 variable에서 가져옴) : 변경 가능한(mutable) 참조입니다. 이런 변수의 값은 바뀔 수 있으며, 스위프트의 var 변수랑 동일한 이름으로 사용되고 있습니다.
📌 기본적으로 모든 변수를 val 키워드를 사용해 불변 변수로 선언하고, 나중에 꼭 필요할 때만 var로 변경하자
val 변수는 블록을 실행할 때 정확히 한 번만 초기화돼야 한다. 하지만 어떤 블록이 실행될 때 오직 한 초기화 문장만 실행됨을 컴파일러가 확인할 수 있다면 조건에 따라 val 값을 여러 다른 값으로 초기화할 수 있다.
val message : String
if (canPerformOpertion()) {
message = "Success"
//...연산 수행
}
else {
message = "Failed"
}
📌 val 참조 자체는 불변일지라도 그 참조가 가리키는 객체의 내부 값은 변경될 수 있다는 것을 기억하자
// 불변 참조 선언
val languages = arrayListOf("Java")
// 참조가 가리키는 객체 내부 변경
languages.add("Kotlin")
4. 문자열 형식 지정 : 문자열 템플릿
object Main {
fun main(args: Array<String>) {
val name = if (args.size > 0) args[0] else "Kotlin"
println("Hello $name")
}
}
이 코드는 name이라는 변수를 선언하고 그다음 줄에 있는 문자열 리터럴 안에서 그 변수를 사용했다. 여러 스크립트 언어와 비슷하게 코틀린에서도 변수를 문자열 안에 사용할 수 있다. 문자열 리터럴의 필요한 곳에 변수를 넣되 변수 앞에 $를 추가해야 한다.
📌 여기서 잠깐 !!
fun main(args: Array<String>) {
val name = if (args.size > 0) args[0] else "Kotlin"
println("Hello $name")
}
이렇게 쓸 경우 오류가 발생하게 되는데 그 이유를 설명해 드리겠습니다.
이는 메서드 본문 어디에서도 호출하지 않는 메서드 매개변수를 정의할 때 나타나는 경고일 뿐입니다.
경고는 컴파일 과정에 실패하는 것이 아니라 오류가 발생하는 것입니다.
하지만 우리의 프로그램은 예상대로 실행이 돼야 합니다.
그런데 Kotlin에서는 main()매개변수 없이 함수를 작성할 수 있으므로 args: Array<String>를 제거하면 경고가 제거됩니다.
그럼에도 나는 args: Array<String>을 쓰고 싶다 하시는 분들은 아래와 같이 실행시켜 주세요.
package samplePackage // optional package name
fun main(args: Array<String>) {
}
object Main {
fun main(args: Array<String>) {
}
}
자 그럼 위 코드에서 args: Array<String>을 빼면 어떻게 구현하나요? 라는 궁금증을 가지신 분들을 위해 코드를 하나 더 보여드리겠습니다.
fun main() {
val args = emptyArray<String>()
val name = if (args.size > 0) args[0] else "Kotlin"
println("Hello $name")
}
아래와 같이 해결을 하셔도 동일한 값을 구할 수 있습니다.
저는 이게 너무너무 궁금해서 찾아보게 되었네요 여러분들도 궁금증이 해소되셨으면 좋겠습니다.
이어서 말하자면 $문자를 문자열에 넣고 싶으면 println("\$x")와 같이 \를 사용해 $를 이스케이프(escape) 시켜야 합니다.
println("\$x")는 화면에 x값을 출력하지 않고 $x를 출력하게 됩니다.
문자열 템플릿 안에 사용할 수 있는 대상은 간단한 변수 이름만으로 한정되지 않습니다.
복잡한 식도 중괄호{ } 로 둘러싸서 문자열 템플릿 안으로 넣을 수 있습니다.
📌 한글을 문자열 템플릿에 사용할 경우 주의할 점
문자열 템플릿 안에 $로 변수를 지정할 때 변수명 바로 뒤에 한글을 붙여서 사용하면 코틀린 컴파일러는 영문자와 한글을 한 번에 식별자로 인식하여 unresolved reference 오류를 발생시킵니다. 이 문제를 해결하는 방법은 '${name} 님 안녕하세요 !' 처럼 변수 이름을 중괄호 { }로 감싸는 것입니다. 문자열 템플릿 안에서 변수 이름만 사용하는 경우라도 중괄호로 변수명을 감싸는 습관을 들이면 더 좋습니다. 필요할 때 정규식 등을 통해 검색하거나 일괄 변환할 때도 중괄호를 쓴 경우 처리가 더 쉽고 코드를 사람이 읽을 때도 문자열 템플릿 안에서 변수가 쓰인 부분을 더 쉽게 식별할 수 있습니다.
'Android' 카테고리의 다른 글
[ Kotiln Code conventions ] 서식 지정(Formatting) 2 (2) | 2023.10.30 |
---|---|
[ Kotiln Code conventions ] 서식 지정(Formatting) 1 (2) | 2023.10.30 |
[ Kotlin Code conventions ] 명명규칙(Naming rules) (2) | 2023.10.29 |
[ Kotlin Code conventions ] 소스코드 구성(Source code organization) (1) | 2023.10.22 |
코틀린(Kotlin) 이란? (1) | 2023.10.18 |