기본 문법
주석
코틀린에서는 3가지 형태의 주석이 있습니다.
1줄 주석: //
여러줄 주석: /* */
KDoc 주석: /** */
// 1줄 주석
/*
여러줄
주석
*/
/**
KDoc
주석
*/
KDoc은 Rich Text Documentation을 생성하기 위해 사용합니다.
변수
코틀린에서 변수는 아래와 같이 정의합니다.
val name: String = "정석준" // String 타입의 name 변수에 "정석준" 문자열 할당
val name = "정석준" // 초기값이 있다면 타입 선언은 생략 가능
val name: String // 초기값이 없다면 에러 발생
val name = "정석준" // 불변변수
name = "dino" // val은 수정 할 수 없어서 에러 발생
var name = "정석준" // 가변변수
name = "dino" // var은 수정 할 수 있어서 에러 x
식별자(변수명)
코틀린에서 식별자의 규칙이 있습니다.
- 문자, 숫자, _(underscore)만 포함가능하고 숫자로 시작할 수 없습니다.
- 하드 키워드(val, fun 등)은 사용할 수 없습니다.
- 다만 `(backqoute)를 사용하면 하드 키워드를 사용 할 수 있습니다.
- `여기에는 공백도 가능 합니다.`
val _name1 = "정석준"
val `fun` = "함수"
val `class` = "클래스"
val `fun generate()` = "생성 함수"
연산자 우선순위
코틀린에서 값을 연산하는 연산자에는 우선순위가 있습니다.
후위 -> 전위 -> 사칙연산 -> 비교 -> 동등 -> 논리곱 -> 논리합 -> 대입
보통 사칙연산과 비교와 동등 빼고는 괄호를 넣어서 코드를 읽기 쉽게 하는게 좋다
/*
후위
++, --
*/
a*b++ // a*(b++)
++b-- // ++(b--)
a*b.foo() // a*(b.foo())
/*
전위
+ - ++ -- !
*/
+a * b // (+a) * b
++a * b // (++a) * b
!a || b // (!a) || b
/*
사칙연산
* / %
+ -
*/
*/
a * b + c // (a * b) + c
a - b % c // a - (b % c)
/*
중위(infix fun)
이름이 붙은 중위 연산자들
*/
a < b or b < c // (a < (b or b)) < c
a == b and b == c // (a == b) and (b == c)
/*
비교
< > <= >=
*/
a < b == b < c // (a < b) == (b < c)
a < b && b < c // (a < b) && (b < c)
/*
동등
== !=
*/
a == b || b != c // (a == b) || (b != c)
/*
논리곱
&&
*/
a || b && c // a || (b && c)
/*
논리합
||
*/
a && b || c // (a && b) || c
/*
대입
= += -= *= /= %=
*/
a = b * c // a = (b * c)
a *= a + b // a *= (a + b)
타입
int, boolean과 같은 primitive type(원시 타입의 값은 메서드의 스택 영역에 저장될 수 있다)과 String과 같은 reference type(참조 타입의 값은 스택 영역에 저장될 수 있다)이 있습니다.
정수
정수를 표현하는 타입은 4가지가 있고 아래와 같이 구성되어있습니다.
이름 | 크기(바이트) | 범위 |
Byte | 1 | -128 .. 127 |
Short | 2 | -32768 .. 32767 |
Int | 4 | -2^31 .. 2^31-1 |
Long | 8 | -2^63 .. 2^63-1 |
/*
숫자 표현 방식
정수를 표현 할 때는 숫자만 구성해도 되고 숫자 사이에 _(underscore)를 사용해서 가독성을 높일 수 있음
*/
val n = 12345
val n2 = 12_345_789
/*
크기에 따른 변수 타입
*/
val one: Byte = 1
val tooBigForShort: Short = 100_000 // The integer literal does not conform to the expected type Short
val million = 1_000_000 // Int 타입 추론
val tooBigForInt: Int = 10_000_000_000 // The integer literal does not conform to the expected type Int
val tenBillions = 10_000_000_000 // Long 타입 추론
val tooBigForLong = 10_000_000_000_000_000_000 // The value is out of range
/*
L이나 l을 접두사로 붙여서 Long타입 강제
*/
val hundredLong = 100L
val hundredInt: Int = 100L // The integer literal does not conform to the expected type Int
/*
접미사로 0b(2진수) 0x(16진수)를 표현
*/
val bin = 0b10101 // 21
val hex = 0xf9 // 249
/*
기타
- 다른 언어는 0으로 시작하면 8진수를 표현하지만 코틀린에서는 지원하지 않음
- 음수를 표현하는 - 표현은 리터럴이 아닌 음수연산자(-)를 사용한 식
*/
val zero = 0
val zeroOne = 01 // Property getter or setter expected, Unsupported [literal prefixes and suffixes]
val neg = -10
val negHex = -0xff
부동소수점
IEEE 754 부동소수점 수를 따르는 Float과 Double 타입이 있습니다.
/*
부동 소수점을 나타낼 때는 숫자 사이에 .을 넣어서 표현
*/
val pi = 3.14
val one = 1.0
/*
0 미만의 수인 경우 0을 생략할 수 있고 .뒤에 숫자가 비어있을 수는 없음
*/
val quarter = .25
val one = 1. // Expecting an element
val two = 2
/*
과학적 표기법(scientific notation) 리터럴을 허용
*/
val pi = 0.314E1 // 3.14, 0.314*10
val pi100 = 0.314E3 // 314.0, 0.314*1000
val piOver100 = 3.14E-2 // 0.0314, 3.14/100
val thousand = 1E3 // 1000.0, 1*1000
/*
부동 소수점은 기본 Double 타입이고 Float 타입으로 사용하고 싶으면 접미사로 f, F를 붙임
*/
val pi = 3.14f
val one = 1f
val two: Double = 2f // The floating-point literal does not conform to the expected type Double
/*
특별한 값을 표현하는 몇 가지 상수
*/
Float.MIN_VALUE // 1.4E-45
Double.MAX_VALUE // 1.7976931348623157E308
Double.POSITIVE_INFINITY // Infinity
1.0/Double.NEGATIVE_INFINITY // -0.0
2 - Double.POSITIVE_INFINITY // -Infinity
3 * Float.NaN // NaN <- NaN은 잘못된 입력으로 인해 계산을 할 수 없음을 나타내는 기호
산술 연산
+ 덧셈
- 뺄셈
* 곱셈
/ 나눈 몫
% 나눈 나머지
floorDiv()몫을 더 작은 정수로 내림한다.
mod()는 a와 a.floorDiv(b) * b의 차이를 반환한다. mod()의 결과값의 부호는 b와 항상 같다.
7.floorDiv(4) // 1
(-7).floorDiv(4) // -2
7.floorDiv(-4) // -2
(-7).floorDiv(-4) // 1
7.mod(4) // 3
(-7).mod(4) // 1
7.mod(-4) // -1
(-7).mod(-4) // -3
단항 +, - 연산의 결과는 인자들의 타입과 같고 Byte와 Short인 경우는 Int를 반환합니다.
val byte: Byte = 1
val int = 1
val long = 1L
val float = 1.5f
val double = 1.5
-byte // -1: Int
-int // -1: Int
-long // -1: Long
-float // -1.5: Float
-double // -1.5: Double
다른 타입끼리 이항 산술 연산을 하면 크기가 더 큰 타입으로 변경되며 Double > Float > Long > Int > Short > Byte 순으로 변경됩니다.
val byte: Byte = 1
val int = 1
val long = 1L
val float = 1.5f
val double = 1.5
byte + byte // Byte
int + byte // Int
int + int // Int
int + long // Long
long + double // Double
float + double // Double
float + int // Float
long + double // Double
비트 연산
정수 타입은 비트 연산을 지원합니다.
연산 | 뜻 | 예제 | 결과 |
shl | 왼쪽 시프트 | 13 shl 2 (-13) shl 2 |
52: 0...0011_0100 -52: 1...1100_1100 |
shr | 오른쪽 시프트 | 13 shr 2 (-13) shr 2 |
3: 0...0000_0011 -4: 1...1111_1100 |
ushr | 부호 없는 오른쪽 시프트 | 13 ushr 2 (-13) ushr 2 |
3: 0...0000_0011 1073741820: 001...1111_1100 |
and | 비트 곱(AND) | 13 and 19 -13 and 19 |
1: 0...0000_0001 19: 0...0001_0011 |
or | 비트 합(OR) | 13 or 19 -13 or 19 |
31: 0...0001_1111 -13: 1...1111_0011 |
xor | 비트 배타합(XOR) | 13 xor 19 -13 xor 19 |
30: 0...0001_1110 -32: 1...1110_0000 |
inv | 비트 반전(inversion) | 13.inv() (-13).inv() |
-14: 1...1111_0010 12: 0...0000_1100 |
문자 타입 Char
유티코드 한 글자를 표현하며 16비트 입니다. `(backquote) 사이에 문자를 넣으면 됩니다.
val z = 'z'
val one = '1'
특수 문자를 위해 이스케이프를 제공합니다.
val tab = '\t'
val backspace = '\b'
val newline = '\n'
val carriageReturn = '\r'
val singleQuote = '\''
val doubleQuote = '\"'
val backslash = '\\'
val dollarSign = '\$'
\u 다음 16진수 4자리를 넣어서 유니코드 문자를 만들 수 있습니다.
val pi = '\u03c0'
Char 타입은 덧셈과 뺄셈을 지원하고 ++, -- 로 1씩 증가와 감소를 지원합니다.
var a = 'a'
var h = 'h'
a + 5 // f
a - 5 // \
h - a // 7
--h // g
++a // b
수 변환
각 수 타입마다 다른 수 타입으로 변환하는 함수가 정의되어 있습니다.
toByte(), toShort(), toInt(), toLong(), toFloat(), toDouble(), toChar()
정수 타입 사이의 변환은 대상 타입이 작은 경우 MSB(2진수로 표현했을 때 상위 비트쪽)를 잘라내고 나머지를 대상 타입의 값으로 변환 합니다.
val n = 945
n.toByte() // -79
n.toShort() // 945
n.toChar() // α
n.toLong() // 945
부동소수점 수 타입과 같은 경우 정밀도를 잃을 수 있다.
Long을 Float로 변환하면 LSB(2진수로 표현했을 때 하위 비트 쪽)을 잃어 버립니다.
2.5.toInt() // 2
(-2.5).toInt() // -2
1_000_000_000_000.toFloat().toLong() // 999999995904
불 타입과 논리 연산
참(true)과 거짓(false)로 표현하는 boolean 타입이 있습니다.
논리연산은 !, or, and, xor, ||, &&가 있습니다.
지연 계산 연산자인 ||, &&는 상황에 따라 연산을 수행하지 않을 수 있습니다
||는 왼쪽 피연산자가 true면 오른쪽 피연산자를 계산하지 않는다.
&&는 왼쪽 피연산자가 false면 오른쪽 피연산자를 계산하지 않는다.
비교와 동등성
==(같다), !=(같지 않다), <(작다), >(크다), <=(작거나 같다), >=(크거나 같다)
val a = 1
val b = 2
a == 1 || b != 1 // true
a >= 1 && b < 3 // true
a < 1 || b < 1 // false
a > b // false
==와 !=는 두 인자가 모두 같은 타입일 때만 허용합니다.
val a = 1
val b = 2L
a == b // Operator '==' cannot be applied to 'Int' and 'Long'
a.toLong() == b // false
<, >, <=, >=는 같은 유형의 타입 끼리 지원 합니다.
1 <= 2L || 3 > 4.5 // true
false == true // false
false < true // true
false > 1 // The integer literal does not conform to the expected type Boolean
'a' < 'b' // true
'a' > 0 // The integer literal does not conform to the expected type Char
NaN 값은 어떤 값과도 같지 않고 크거나 작지도 않다.
NaN은 실제로 특정 값으로 인코딩 되어 있어서 NaN값인지 확인하려면 == 보다 .isNaN() 함수를 사용해야만 합니다.
Double.NaN == Double.NaN // false
Double.NaN != Double.NaN // true
Double.NaN <= Double.NaN // false
Double.NaN < Double.POSITIVE_INFINITY // false
Double.NaN > Double.NEGATIVE_INFINITY // false
Double.NaN.isNaN() // true
public static boolean isNaN(double v) {
return (v != v);
}
NaN은 자기 자신과 같고 가장 큰 값으로 표현됩니다.
val set = sortedSetOf(Double.NaN, Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, 0.0)
println(set) // [-Infinity, 0.0, Infinity, NaN]
문자열
문자열 템플릿
String 타입의 문자열을 만들 때 "를 사용하는데 "와 " 사이에 변수나 식을 넣을 때는 $나 ${}를 사용합니다.
간단한 참조인 경우 $를 사용하고 식을 사용할 땐 ${}를 사용합니다.
fun main() {
val name = "정석준"
val age = 31
println("안녕하세요. 제 이름은 ${name}이고 나이는 ${age}살 입니다.")
// 안녕하세요. 제 이름은 정석준이고 나이는 31살 입니다.
}
"를 3개 사용하면 여러줄을 사용한 문자열을 만들 수 있습니다. trimIndent()를 이용해서 indent를 제거 해줍니다.
fun main() {
val name = "정석준"
val age = 31
val introduction = """
안녕하세요. 제 이름은 ${name}이고 나이는 ${age}살 입니다.
안드로이드 개발 6년차이고 토스를 다니고 있습니다.
""".trimIndent()
println(introduction)
/*
안녕하세요. 제 이름은 정석준이고 나이는 31살 입니다.
안드로이드 개발 6년차이고 토스를 다니고 있습니다.
*/
}
기본 문자열 연산
// length나 lastIndex 처럼 숫자를 반환하는 property가 있음
"Hello!".length.print() // 6
"hello!".lastIndex.print() // 5
// [index]를 사용해서 개별 문자를 가져 올 수 있음
val s = "Hello!"
s[0].print() // H
s[1].print() // e
s[5].print() // !
s[10].print() // Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 10
// + 연산자를 사용해서 문자열을 연결 할 수 있음
val s1 = "Hello!"
val s2 = "Hel" + "lo!"
// == 를 통해서 문자열 비교를 할 수 있음
s1 == s2 // true
// 문자열은 사전식 순서로 정렬되서 > < >= <= 와 같은 비교 연산도 가능
"abc" < "cba" // true
"123" > "34" // false
/*
문자열을 다른 타입으로 변환하는 toByte(), toShort(), toInt(), toLong(), toFloat(), toDouble(), toBoolean() 함수를 제공
그 외에 유용한 함수들도 많이 있음
*/
"".isEmpty() // true
"".isNotEmpty() // false
"Hello".substring(2) // llo
"Hello".substring(1, 3) // el
"Hello".startsWith("Hel") // true
"Hello".endsWith("Hel") // false
"Hello".indexOf("e") // 1
"Hello".indexOf("a") // -1
"Hello".indexOf("l", 2) // 3
배열
코틀린에 내장된 데이터 구조로 크기가 정해져 있고 인덱스로 참조 할 수 있습니다.
배열 정의하기
val a = emptyArray<String>() // Array<String> 원소 0개
val b = arrayOf("Hello", "world") // Array<String> 원소 2개
val c = arrayOf(1, 4, 9) // Array<Int> 원소 3개
val squares = Array(10) { (it + 1) * (it + 1) } // size와 init block을 지정해서 초기화 가능, init block은 0부터 size-1까지 전달
배열 사용하기
배열 타입은 문자열 타입 처럼 [index]로 접근이 가능하고 원소를 변경 할 수도 있습니다.
val squares = arrayOf(1, 4, 9, 16)
squares.size // 4
squares.lastIndex // 3
squares[3] // 16
squares[1] // 4
squares[2] = 100 // 1, 4, 100, 16
squares[3] += 9 // 1, 4, 100, 25
squares[0]-- // 0, 4, 100, 25
val numbers = squares
numbers[0] = 1000
squares[0] // 1000 <- squares와 numbers는 같은 배열을 참조
val numbers2 = squares.copyOf()
numbers2[0] = 1234 // squares는 변화 없음
squares.copyOf(2) // 0, 4
squares.copyOf(5) // 0, 4, 100, 25, 0
var a = arrayOf(1, 2, 3, 4)
a = arrayOf("one", "two") // Array<Int>에 Array<String>으로 변환 할 수 없음
// + 연산자를 통해서 원소를 추가 할 수 있음
intArrayOf(1, 2, 3) + 4 // 1, 2, 3, 4
intArrayOf(1, 2, 3) + intArrayOf(5, 6) // 1, 2, 3, 5, 6
// 배열의 원소 비교는 ==가 아니라 contentEquals로 비교
intArrayOf(1, 2, 3) == intArrayOf(1, 2, 3) // false
intArrayOf(1, 2, 3).contentEquals(intArrayOf(1, 2, 3)) // true
// isEmpty, isNotEmpty, indexOf와 같은 함수도 제공
intArrayOf(1, 2).isEmpty() // false
intArrayOf(1, 2).isNotEmpty() // true
intArrayOf(1, 2).indexOf(2) // 1
intArrayOf(1, 2).indexOf(4) // -1
'개발 > 코틀린' 카테고리의 다른 글
(코틀린) 예외처리 (0) | 2022.09.25 |
---|---|
(코틀린) 조건문, 반복문 (0) | 2022.09.25 |
(코틀린) 함수 (0) | 2022.09.24 |
(코틀린) 코틀린 시작하기 2 - IntelliJ로 코틀린 프로젝트 만들기 (0) | 2022.09.01 |
(코틀린) 코틀린 시작하기 1 - 글을 작성하면서 (0) | 2022.09.01 |