반응형
Notice
Recent Posts
Recent Comments
Link
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Tags
more
Archives
Today
Total
관리 메뉴

안드로이드 개발자 노트

[코틀린 완벽 가이드] 2장 : 코틀린 언어 기초 본문

Kotlin/코틀린 완벽 가이드

[코틀린 완벽 가이드] 2장 : 코틀린 언어 기초

어리둥절범고래 2022. 9. 13. 09:51
반응형

1. 기본 문법


1. 주석

 

  • 한 줄짜리 주석 : // 로 시작하며 줄이 끝나면 주석도 끝난다.
  • 여러 줄 주석 : /* 로 시작하고 */ 로 끝난다.
  • KDoc 여러 줄 주석 : /** 로 시작하고 */ 로 끝난다.

 

/*
여러 줄 주석
/* 주석 안에 내포된 주석 */
*/
println("Hello") // 한 줄짜리 주석

 

자바와 달리 코틀린에서는 여러 줄 주석을 여러 번 내포시킬 수 있다.

 


2. 변수 정의하기

 

val timeInSeconds = 15

 

코틀린에서 변수를 정의하는 요소들

 

  • val 키워드 : 값을 뜻하는 value에서 유래했다.
  • 변수 식별자 : 새 변수에 이름을 부여하고, 나중에 이를 가리킬 때 사용한다.
  • 변수의 초깃값을 정의하는 식 : = 기호 뒤에 온다.

 

코틀린은 타입추론이 가능하다.

변수 타입을 지정하지 않아도 프로그램이 성공적으로 컴파일되고 실행된다.

필요할 때는 타입을 명시해도 된다. 타입을 명시하려면 변수 이름 뒤에 콜론(:)을 표시하고, 그 뒤에 타입을 적는다.

 

val n: Int = 100
val text: String = "Hello!"

 

자바도 자바10 부터 코틀린과 비슷한 지역 변수 타입 추론을 도입했다.

 


3. 식별자

 

식별자는 변수나 함수 등 프로그램에 정의된 대상에 붙은 이름이다.

코틀린 식별자는 두 가지로 구분된다.

첫 번째는 다음 규칙을 만족하는 임의의 문자열이다.

 

  • 식별자는 오직 문자, 숫자, 밑줄 문자(_)만 포함한다.
  • 식별자는 숫자로 시작하면 안된다.
  • 밑줄로만 이뤄질 수도 있다. 하지만 이런 식별자는 모두 미리 예약된 식별자이므로 일반적으로 사용될 수 없다.
  • 하드 키워드를 식별자로 쓸 수는 없다.

 

두 번째는 작은역따옴표(`)로 감싼 식별자로, 두 작은역따옴표 사이에는 빈 문자열을 제외한 아무 문자열이나 와도 된다.

 

val `fun` = 1
val `name with spaces` = 2

 


4. 가변 변수

 

지금까지 살펴본 변수는 불변(immutable) 변수다.

불변 변수는 한번 초기화하면 다시는 값을 대입할 수 없는 변수다.

불변 변수를 사용하면 함수가 부수 효과를 일으키지 못하기 때문에 가능하면 불변 변수를 많이 사용해야 한다.

하지만 필요한 경우 val 대신 var 키워드를 사용해 가변(mutable) 변수를 정의할 수 있다.

 

var sum = 1
sum = sum + 2
sum = sum + 3

 

자바와 달리 코틀린 대입은 문(statement)이다. 이로 인해 코틀린에서는 자바의 a = b = c 와 같은 대입문 연쇄를 쓸 수 없다.


5. 식과 연산자

 

단항과 이항 연산마다 연산 순서를 결정하는 우선순위가 정해져 있다.

 

우선순위 분류 연산자
1 후위 ++ --
2 전위 + - ++ -- !
3 곱셈 * / %
4 덧셈 + -
5 중위 이름이 붙은 중위 연산자들 (or, and)
6 비교 < > <= >=
7 동등 == !=
8 논리곱 &&
9 논리합 ||
10 대입 =  +=  -=  *=  /=  %=

 


 

2. 기본 타입

 


1. 정수 타입

 

이름 크기(Byte) 범위 대응하는 자바타입
Byte 1 -128 .. 127 Byte
Short 2 -32768 .. 32767 Short
Int 4 -2^31 .. (2^31)-1 Int
Long 8 -2^63 .. (2^63)-1 Long

 

리터럴에 _를 넣어서 가독성을 높일 수 있다. 리터럴이 아주 큰 수를 나타낼 때 _가 유용하다

 

val n1 = 12345
val n2 = 32_721_189

 


2. 부동소수점 수

 

코틀린은 부동소수점 수를 따르는 flaot 과 Double 을 제공한다.

정수부분과 소수부눈을 나눠 소수점(.)을 찍어 놓는다.

 

val quarter = .25 // 정수 부분이 비어있는 경우 0으로 간주한다.
val one = 1.      // Error: 소수점을 남기면서 소수 부분을 생략할 수는 없다.

 

코틀린은 과학적 표기법 리터럴을 허용한다.

과학적 표기법에는 e나 E 뒤에 10을 몇 번 거듭제곱하는지를 알려주는 숫자가 온다.

과학적 표기법에서는 소수 부분(소수점 포함)을 생략할 수 있다.

 

val pi = 0.314E1        // 3.14 = 0.314*10
val pi100 = 0.314E3     // 314.0 = 0.314*1000
val pi0ver100 = 3.14E-2 // 0.0314 = 3.14/100
val thousand = 1E3      // 1000.0 = 1*1000

 

디폴트로 부동소스점 리터럴은 Double 타입이다. f나 F를 리터럴 뒤에 붙이면 Float 타입이 된다.

 


3. 산술 연산

 

모든 수 타입은 기본 산술 연산을 지원한다

 


4. 비트 연산

 

Int 와 Long 은 비트 수준의 연산을 지원한다.

 

연산 해당하는 자바 연산
shl 왼쪽 시프트(shift) <<
shr 오른쪽 시프트 >>
ushr 부호 없는 오른쪽 시프트 >>>
and 비트 곱(AND) &
or 비트 합(OR) |
xor 비트 배타합(XOR) ^
inv 비트 반전(inversion) ~

 


5. 문자 타입 Char

 

Char 타입은 유니코드 한 글자를 표현하며 16비트다.

이 타입의 리터럴은 작은따옴표(') 사이에 문자를 넣으면 된다.

 

val z = 'z'

 

새줄 문자와 같은 특수 문자를 위해 코틀린은 이스케이프를 제공한다.

\t는 탭, \b는 백스페이스, \n은 새줄, \r은 캐리지 리턴, \'는 작은따옴표, \"는 큰따옴표, \\는 역슬래시, \$는 달러표시다.

 

val quote = '\''
val newLine = '\n'

 

유니코드 문자 집합 내에서의 몇 가지 산술 연산을 허용한다.

 

  • +/- 연산자를 사용해 문자에 수를 더하거나 뺄 수 있다. 더하거나 뺀 수만큼 코드포인트가 이동한 새 문자를 반환한다.
  • 두 문자로 뺄셈을 하면 두 문자의 코드포인트 간 거리를 얻을 수 있다.
  • 문자를 ++ 또는 -- 로 증가시키거나 감소시킬 수 있다.

 

var a = 'a'
var h = 'h'
/* 'a'보다 뒤에 있는 다섯 번째 글자 */ println(a+5) // f
/* 'a'보다 앞에 있는 다섯 번째 글자 */ println(a-5) // \
/* 'a'와 'h' 사이의 거리 */ println(h-a)         // 7
/* 'h' 바로 앞 글자 */ println(--h)             // g
/* 'a' 바로 뒤 글자 */ println(++a)             // b

 

자바에서는 문자(char)에 대한 산술 연산 결과가 암시적으로 정수로 변환된다. 반면 코틀린에서 Char에 대한 연산은(두 문자의 차이는 제외) Char를 결과로 돌려준다.

 


6. 수 변환

 

각 수 타입마다 값을 다른 수 타입으로 변환하는 연산이 정의돼 있다.

예를 들어 toByte(), toShort(), toInt(), toLong(), toFloat(), toDouble(), toChar() 등이다.

자바와 달리 코틀린에서는 범위가 큰 타입이 사용돼야 하는 문맥에 범위가 작은 타입을 쓸 수 없다.

 

val n = 100     // Int
val l: Long = n // Error: 범위가 작은 Int타입을 범위가 큰 Long타입에 대입할 수 없다.

 


7. 불 타입과 논리 연산

 

코틀린은 참(true)이나 거짓(false) 중 하나로 판명되는 불(Boolean) 타입과 논리 연산을 제공한다.

불이 지원하는 연산은 다음과 같다.

 

  • ! : 논리 부정
  • or, and, xor : 즉시 계산 방식의 논리합, 논리곱, 논리배타합
  • ||, && : 지연 계산 방식의 논리합, 논리곱

 

지연 계산 연산자(||, &&)는 자바와 동일 연산자와 똑같은 의미를 제공한다.

||의 왼쪽 피연산자가 참이면 오른쪽 피연산자를 계산하지 않는다.

&&의 왼쪽 피연산자가 거짓이면 오른쪽 피연산자를 계산하지 않는다.

 


8. 비교와 동등성

 

지금까지 언급한 모든 타입은 몇 가지 비교 연산을 제공한다.


==(같다), !=(같지 않다), <(~보다 작다), <=(~보다 작거나 같다), >(~보다 크다), >=(~보다 크거나 같다)가 비교 연산이다.

일반적으로 동등성 연산인 ==와 !=를 모든 타입의 값에 적용할 수 있지만 수 타입이나 Char와 Boolean의 경우 예외가 있다. 기본적으로 코틀린 타입은 두 인자가 모드 같은 타입일 때만 ==와 !=를 허용한다.

 

val a = 1               // Int
val b = 2L              // Long
println(a==b)           // Error: comparing Int and Long
println(a.toLong()==b)  // Ok: 두 타입 모두 Long임

 

Char와 Boolean 값도 비교 연산을 지원한다. 하지만 같은 타입의 값과만 비교할 수 있다.

 

false == true // false
false < true  // true
false > 1     // Error: comparing Boolean and Int
'a' < 'b'     // true
'a' > 0       // Error: comparing Int and Char

 


 

3. 문자열

 


1. 문자열 템플릿

 

문자열 리터럴을 정의하는 가장 간단한 방법은 큰따옴표(")로 문자열을 감싸는 것이다.

 

val hello = "Hello, world!"

 

문자열에 새줄 같은 특수 문자가 들어가면 이스케이프 시퀀스를 사용해야 한다.

코틀린은 이와 더불어 여러 가지 식에 문자열을 합성해내는 훨씬 더 강력한 방법을 지원한다.

 

import java.util.Date
fun main() {
  val name = readLine()
  println("Hello, $name!\n Today is ${Date()}")
}

 

기본적으로 ${}의 중괄호 사이에 넣기만 하면, 코틀린 식을 문자열에 넣을 수 있다.

위의 $name과 같이 변수 참조인 경우에는 중괄호를 생략할 수 있다.

 

다른 문자열 유형으로 로우 문자열이 있다.

로우 문자열을 사용하면 이스케이프 시퀀스를 사용하지 않고도 문자열을 작성할 수 있다.

이러한 리터럴은 큰따옴표 세 개로 둘러싸여 있고, 새줄 문자를 포함한 임의의 문자를 포함할 수 있다.

드물겠지만, 로우 문자열에 특수 문자를 추가하고 싶은 경우에는 ${} 안에 특수 문자를 넣으면 된다.

 

val message = """
  Hello, $name!
  Today is ${Date()}
  This is triple quote: '${"\"\"\""}'
 """.trimIndent() // trimIndent()는 여러 줄에 공통된 최소 들여쓰기를 제거헤준다.

 


2. 기본 문자열 연산

 

모든 String 인스턴스는 문자열에 든 문자 수를 표현하는 length와 문자열의 마지막 문자 인덱스를 표현하는 lastIndex 프로퍼티를 제공한다.

 

"Hello!".length    // 6
"Hello!".lastIndex // 5(첫 번째 문자의 인덱스가 0이므로)

 

+ 연산자를 이용해 두 문자열을 연결할 수 있으며 문자열은 ==와 !=를 사용해 동등성을 비교할 수 있다.

또한, 문자열은 사전식 순서로 정렬되기 때문에 <, >, <=, => 같은 연산자를 사용해 문자열을 비교할 수 있다.

 

val s = "The sum is: " + sum  // "The sum is: $sum" 으로 대신할 수 있음
val s1 = "Hello!"
val s2 = "Hel" + "lo!"
println(s1 == s2)             // true
println("abc" < "cba")        // true
println("123" > "34")          // false

 

자바는 ==와 != 연산자는 참조 동등성을 비교하기 때문에 실제 문자열 내용을 비교하려면 equals() 메서드를 사용해야 한다. 코틀린에서는 ==가 기본적으로 equals()를 가리키는 편의 문법이기 때문에 ==를 사용하면 직접 equals()를 호출하므로 따로 equals()를 호출할 필요가 없다.

다음은 문자열이 제공하는 유용한 함수들이다.

 

isEmpty
isNotEmpty
문자열이 비어있는지 검사한다. "Hello".isEmpty()
"".isEmpty()
"Hello".isNotEmpty()
false
true
true
substring 부분 문자열을 추출한다. "Hello".substring(2)
"Hello".substring(1,3)
"llo"
"el"
startsWith
endsWith
접두사나 접미사인지 검사한다. "Hello".startsWith("Hel")
"Hello".endsWith("lo")
true
true
indexOf 인자로 받은 문자나 문자열이 수신 객체인 문자열에 나타나는 첫 번째 인덱스를 반환한다. // 맨 앞부터 찾기
"abcabc".indexOf('b')
"abcabc".indexOf('ca')
"abcabc".indexOf('cd')
// 주어진 인덱스부터 찾기
"abcabc".indexOf('b', 2)
"abcabc".indexOf('ab', 2)

1
2
-1

4
3

 


 

4. 배열

 


1. 배열 정의하기

 

배열 구조를 구현하는 가장 일반적인 코틀린 타입은 Array<T>다.

여기서 T는 원소의 타입을 뜻한다.

 

val a = emptyArray<String>()      // Array<String> 원소 0개
val b = arrayOf("hello", "world") // Array<String> 원소 두 개
val c = arrayOf(1,4,9)            // Array<Int> 원소 세 개

 

인덱스로부터 원소를 만들어내는 방법을 기술해 배열을 생성하는 더 유연한 방법도 있다.

 

val size = readLine()!!.toInt()
val squares = Array(size) { (it + 1)*(it + 1) }

 

중괄호({}) 안에 들어있는 언어 요소를 람다라고 부른다.

람다는 인덱스를 기반으로 값을 계산하는 식을 정의한다.

배열 인덱스는 0부터이기 때문에 이 배열에는 1, 4, 9 등의 값이 들어간다.

 

코틀린은 ByteArray, ShortArray, IntArray, LongArray, FloatArray, DoubleArray, CharArray, BooleanArray라는 특화된 배열 타입을 제공한다.

이런 특화된 배열에도 arrayOf()나 Array()에 해당하는 함수가 함께 따라온다.

 

val operations = charArrayOf('+', '-', '*', '/', '%')
val squares = IntArray(10) { (it + 1)*(it + 1) }

 

자바와 달리 코틀린에서는 new 연산자가 없기 때문에 배열 인스턴스 생성이 일반 함수 호출처럼 보인다. 코틀린에서는 배열 원소를 명시적으로 초기화해야 한다는 점에도 유의해야한다.

 


2. 배열 사용하기

 

배열 타입은 문자열 타입과 꽤 비슷하다.

 

val squares = arrayOf(1, 4, 9, 16)
squares.size      // 4 (String의 length에 해당)
squares.lastIndex // 3
squares[3]        // 16
squares[1]        // 4

 

하지만 문자열과 달리 배열에서는 원소를 변경할 수 있다.

 

squares[2] = 100 // squares: 1, 4, 100 ,16
squares[3] += 9  // squares: 1, 4, 100 ,25
squares[0]--     // squares: 0, 4, 100 ,25

 

자바와 마찬가지로 배열 타입의 변수 자체에는 실제 데이터에 대한 참조를 저장한다.

이로 인해 배열 변수에 다른 배열을 대입하면 같은 데이터 집합을 함께 공유한다.

원본과 별도로 배열을 만들고 싶다면 copyOf() 함수를 사용해야 한다.

 

코틀린 배열 타입은 모든 다른 배열 타입과 서로 하위 타입 관계가 성립하지 않는다고 간주된다.

String은 Any의 하위 타입이지만 Array<String>은 Array<Any>의 하위타입이 아니다.

 

val strings = arrayOf("one", "two", "three")
val objects: Array<Any> = strings // 예외

 

배열을 생성하고 나면 그 길이를 바꿀 수 없지만, + 연산을 사용해 원소를 추가한 새로운 배열을 만들 수는 있다.

 

val b = intArrayOf(1, 2, 3) + 4                // 원소를 하나만 추가 : 1, 2, 3, 4
val c = intArrayOf(1, 2, 3) + intArrayOf(5, 6) // 다른 배열을 추가 : 1, 2, 3, 4, 5, 6

 

문자열과 달리 배열에 대한 ==와 != 연산자는 원소 자체를 비교하지 않고 참조를 비교한다.

배열 내용을 비교하고 싶으면 contentEquals() 함수를 사용하라.

 

intArrayOf(1, 2, 3) == intArrayOf(1, 2, 3)             // false
intArrayOf(1, 2, 3).contentEquals(intArrayOf(1, 2, 3)) // true
반응형