코틀린에서 변수 선언은 최상위(클래스 외부), 클래스 내부, 함수 내부에서 할 수 있다. 변수는 자동으로 초기화되지 않으므로 코드에서 직접 초기화해야 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | val topData1: Int //error val topDate2: String //error class User{ val objData1: String //error val objDate2: String //error fun some() { val localData1: Int var localData2: String println(localdata1) //error(초기화 하지 않아 error) localData2 = "hello" println(localData2) } } |
위 코드에서 최상위 레벨은 error, 클래스 내부에서 선언한 것은 error이 발생한다. 함수 내부에서는 변수 선언과 동시에 초기화하지 않아도 에러가 발생하지 않는다. 하지만 함수 내부의 변수들도 자동으로 초깃값이 대입되지 않으므로 이 변수들을 사용하려면 반드시 초기화 해야 한다.
정리하자면 코틀린의 변수는 자동으로 초기화되지 않으므로 코드에서 직접 초깃값을 대입해 주어야 한다. 위의 코드가 정상적으로 사용하기 위해서는 초기값을 넣어주자.
코틀린은 null 안정성을 위해 기법을 제공한다. 어떤 변수에 null값을 대입하면 타입에 (?) 기호를 이용하여 명시적으로 null이 될 수 있음을 선언해야 한다.
1 2 3 4 5 6 7 8 9 | val nonNullData: String = null //error val nullableData1: String? = null var nullableData2: String? = null fun main(args: Array<String>) { nonNullData = "hello" //error nullableData2 = "hello" //success } |
코틀린에서 val은 상수 변수인가 ?
코틀린에서 val은 변경 불가능하지만, 일반적인 프로그래밍 언어에서의 상수 변수와는 차이가 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var myBool = false val myVal: String = "hello" get() { if(myBool) return field else return field.toUpperCase() } fun main(args: Array<String>) { println(myVal) //Hello myBool = true println(myVal) //hello } |
위의 결과는 다른 결과를 보여준다. 왜냐하면 코틀린에서 변수는 프로퍼티이기 때문이다. 위 코드에서 field는 코틀린 인 액션에서 말하는 뒷받침하는 필드를 뜻하는데 프로퍼티와 이 뒷받침하는 필드를 설명은 나중에.. 아무튼 코틀린에서 val은 상수 변수가 아니라는 것을 알면 된다.
코틀린에서 상수 변수를 사용하려면 const를 사용하면 된다.
코틀린에서 Default 파라미터로 값주기
자바에서는 파라미터로 널 값을 비교해야하지만 코틀린에서는 ? 표시로 쉽게 널체크를 할 수 있다. 아래 예제를 자바로 변환한다고 생각한다면 if else 가 있어 코드가 길어지는 단점이 생긴다.
1 2 3 4 5 6 7 8 9 | fun sayHello(name: String? = "ktko") { println("$name Hello") } fun main(args: Array<String>) { sayHello() //ktko Hello sayHello("theo") //theo Hello } |
코틀린에서 중위 표현식 함수 호출
과연 이게 쓸일이 있을까 싶다... 그냥 이런게 있구나 하고 넘어가보고 그냥 정리만..
중위 표현식은 1 + 2 를 예를 들어서 연산자와 피연산자 중간에 +라는 연산자를 놓았을 때 중위 표현식을 사용한다고 하는데, 이 중위 표현식을 함수 호출에 사용할 수 있다.(진짜 쓸일 있을까..)
중위 표현식으로 사용한다는 것이 무슨 의미냐면 아래 예제에서 호출을 할 때 .으로 호출을 하는 방식 외에 띄어 쓰기를 넣어서 함수를 호출하는 것을 볼 수 있다. 함수를 중위 표현식으로 이용하려면 infix라는 예약어로 사용해야 한다.
근데 또 infix를 사용하려면 조건이 필요하다.
클래스의 멤버 함수로 선언하거나 클래스의 확장 함수일 때, 매개변수가 하나인 함수일 때 사용이 가능하다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | infix fun Int.myFun(x: Int): Int { return this * x } class InFixCls { infix fun infixFun(x: Int): Int { return x * x } } fun main(args: Array<String>) { println(10.myFun(5)) //50 println(10 myFun(5)) //25 val infixObj = InFixCls() println(infixObj.infixFun(5)) //25 println(infixObj infixFun(5)) //25 } |
코틀린 함수에서 재귀함수를 사용하려면 tailrec 예약어를 사용하자
아래 코틀린 예제는 특정 동작을 반복하려고 할 때 while 또는 재귀함수를 이용함을 알 수 있다. 또한 재귀함수를 선언하여 whie 보다는 더 코드가 간결해지고 편하게 작성할 수 있다.(책에서 그렇게 써있지만 나는 개인적으로 for문이 제일 편하다... 케바케인듯)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | fun main(args: Array<String>) { loopPrint(4) recursiveLoopPrint(4) } fun loopPrint(count: Int) { var i = 0; while(i < count) { println("loop Print"); i++ } } fun recursiveLoopPrint(no: Int = 1, count: Int = 1) { println("recursiveLoopPrint") return if(no == count) return else recursiveLoopPrint(no - 1, count) } |
여기에서 말하고 싶은 것은 재귀 함수를 편하게 사용하기 위해 tailrec 예약어를 이용 하여 재귀 함수를 좀 더 편하게 사용할 수 있다는 것이다.
1 2 3 4 5 6 7 8 | fun main(args: Array<String>) { tailrecPrint(4) } tailrec fun tailrecPrint(no: Int = 1, count: Int = 1) { println("tailrecPrint") return if(no == count) return else tailrecPrint(no - 1, count) } |
위에 코드에서 5번 라인에 tailrec 예약어를 추가하였다. tailrec는 'tail recusrsion'의 약어로 꼬리 재귀함수라 한다. 근데 자세히 보면 이전에 했던 재귀함수와 차이는 tailrec 예약어가 사용되었다는 차기만 있고, 로직 작성이나 결과값에 특별한 차이가 없어 보인다.
tailrec 예약어를 이용하면 소스코드가 자바로 변경될 때 재귀함수가 아닌 일반적인 반복문으로 변형된다. 재귀 조건을 잘못 설정했을 경우 StackOverflowError가 발생한다. 근데 tailrec를 이용하면 재귀함수가 반복믄으로 구현된 일반 함수로 컴파일 되므로 StackOverflowError의 위험 부담에서 벗아날 수 있다.
주의해야 할 점은 tailrec 예약어를 사용할 때 재귀함수에서 자신을 다시 호출하는 구문은 함수의 맨 마지막 작업으로 작성해야 한다.
코틀린에서는 const로 최상위 레벨에 상수 변수를 선언한다.
자바는 일반적으로 상수 변수를 선언할 때 아래와 같이 선언한다.
1 | public static final int NAMESPACE = "NAMESPACE" |
자바의 이런 표현은 코틀린에서 아래와 같다.
1 | const val NAMESPACE = "NAMESPACE" |
코틀린에서 const는 최상위 레벨로 선언되어 객체 멤버에 포함되지 않으며 const로 선언되어 상수 변수가 된다. 코틀린에서는 static 예약어 자체가 없다.
코틀린은 변수값이 자동으로 초기화 되지 않는다.
자바에서 클래스의 멤버 변수는 코드에서 직접 값을 선언하지 않아도 기본값으로 자동 초기화 된다.
1 2 3 4 5 6 7 8 9 10 | public class Test { String name; int no; boolean isBoolean; public static void main(String[] arts) { Test test = new Test(); System.out.println(test.name + "::" + test.no + "::" + test.isBoolean); } } |
위의 예제에서 Test 객체에서 선언된 값들은 각각 name은 null, no는 0, isBoolean은 false로 대입된다.
하지만 코틀린에서는 변수가 자동으로 초기화되지 않기 때문에 나중에 명시적으로 초기값을 대입하여 사용하거나, 물음표(?)를 이용해 nullable으로 선언하여 null 값을 초기화 하고 사용해야 한다.
'Kotlin 코틀린' 카테고리의 다른 글
코틀린의 null 안전 관련 연산자 (0) | 2019.02.12 |
---|---|
코틀린 변수와 자바 변수의 차이점 (0) | 2019.02.09 |
코틀린의 Any 그리고 Any? 대입 비교하기 (0) | 2019.02.06 |
코틀린의 클래스, 객체, 인터페이스 (0) | 2019.01.08 |
코틀린의 함수 (0) | 2019.01.04 |