출처 : 코틀린 학습을 위한 링크(이전 글 1.2 참고), 강의 교안
1. Functions (함수)
1.1 Functions
- fun 키워드
- 반환 타입 선언 가능
- 함수의 매개변수에는 var, val 키워드 사용 불가 (자동으로 val이 적용)
fun hello() {
return println("Hello, world!")
}
fun sum(x:Int, y:Int): Int {
return x + y
}
1.2 Named Arguments
- 매개변수명 지정 호출 가능 (Named Argument)
fun printMessageWithPrefix(message: String, prefix: String) {
println("[$prefix] $message")
}
fun main() {
// Uses named arguments with swapped parameter order
printMessageWithPrefix(prefix = "Log", message = "Hello")
// [Log] Hello
}
1.3 Default Parameter Values
- 함수의 매개변수에 기본값 선언 가능
fun printMessageWithPrefix(message:String, prefix: String="Info") {
println("[$prefix] $message")
}
funmain() {
// Function called with both parameters
printMessageWithPrefix("Hello", "Log")
// [Log] Hello
// Function called only with message parameter
printMessageWithPrefix("Hello")
// [Info] Hello
printMessageWithPrefix(prefix ="Log", message ="Hello")
// [Log] Hello
}
1.4 Single-Expression Functions
- 코드를 간결하게 만들기 위해 단일 수식 함수의 형식으로 단축 가능
fun sum(x:Int, y:Int): Int {
return x + y
}
fun sum(x:Int, y:Int) = x + y
- 중괄호 { } 를 제거
- = 연산자를 사용하여 함수를 선언
- 반환 타입 생략 가능
1.5 Lambda Expressions
- 람다식을 이용한 함수 표현
- { } 안에 람다식 작성
- 람다식 형식 : { 매개변수 -> 함수 본문 }
- 매개변수가 없다면 생략 가능
fun main() {
val upperCaseString = { text:String -> text.uppercase() }
}
- 매개변수가 1개인 람다 함수
- 중괄호 안에서 매개변수를 생략하고 it 키워드로 매개변수 이용 가능
val test = {x:Int -> println(x)}
val test: (Int) -> Unit = {println(it)}
- 람다 함수의 반환값 : 마지막 문장의 실행 결과
- 다른 함수(고차함수)에 매개변수로 람다식 전달
- 함수에서 람다식 반환
- 람다식에서 바로 호출
- Lambda Expression ; 다른 함수에 매개변수로 전달
- 매개변수로 람다식 한 개만 있으면 ( ) 생략 가능
- .으로 연결해서 처리 가능
val numbers = listOf(1, -2, 3, -4, 5, -6)
val positives = numbers.filter({ x ->x >0})
val isNegative ={ x: Int-> x <0}
val negatives = numbers.filter(isNegative)
println(positives)
// [1, 3, 5]
println(negatives)
// [-2, -4, -6]
1.6 Function Types
1) 기본
- 함수 타입 선언 : 함수를 선언할 때 매개변수와 타입 호환
- 형식 : (매개변수타입) -> return 타입
2) 타입 별칭
- typealias
- typealias MyFunType = (Int, Int) -> Int
- var test:MyFunType = = {a:Int, b:Int -> a + b}
- 매개변수의 타입을 유추할 수 있다면 변수를 선언할 때 타입 선언 생략 가능
- var test: MyFunType = { a, b -> a + b}
- return from a function
fun toSeconds(time:String):(Int) -> Int=when(time) {
"hour"->{ value -> value *60*60}
"minute"->{ value -> value *60}
"second"->{ value -> value }
else -> { value -> value }
}
fun main() {
val timesInMinutes =listOf(2, 10, 15, 1)
val min2sec =toSeconds("minute")
val totalTimeInSeconds =timesInMinutes.map(min2sec).sum()
println("Total time is $totalTimeInSeconds secs")
// Total time is 1680 secs
}
- invoke separately
- 람다식 뒤에 () 로 즉시 호출 가능
- println({text:String -> text.uppercase()}("hello"))
3) Trailing Lambdas
- 람다식이 유일한 매개변수인 경우 ( ) 생략 가능
val doubled = numbers.map {x -> x * 2}
- 람다식이 함수의 마지막 매개변수로 전달되는 경우 ( ) 밖에 작성 가능
2. 클래스 (Classes)
2.1 클래스
- 클래스 : class Customer
- 속성을 가진 클래스 선언
- 필드 변수의 정의
class Contact(val id: Int, var email: String)
class Contact(val id: Int, var email: String) {
val category: String = ""
}
- 인스턴스 생성 ; new 키워드 사용하지 않음.
fun main() {
val contact = Contact(1, "mary@gmail.com")
}
2.2 클래스 생성자
- 생성자 : constructor 키워드로 선언하는 함수
- 주 생성자
- constructor 키워드로 클래스 선언부에 선언, 키워드 생략 가능
- 한 클래스에 하나만 가능
class Person contructor(firstName: String) {/* ... */}
class Person(firstName: String) {/* ... */}
- 생성자의 매개변수는 기본적으로 생성자에서만 사용 가능 (지역변수)
- 생성자의 매개변수를 var 또는 val 키워드로 선언하면 클래스의 멤버 변수로 선언
class Person(val firstName: String, val lastName: String, var age: Int)
- init 영역
: 주 생성자의 본문
- init 키워드를 이용, 주 생성자의 본문 구현
class InitOrderDemo(name:String) {
val firstProperty ="First property: $name".also(::println)
init{
println("First initializer block that prints $name")
}
val secondProperty ="Second property: ${name.length}".also(::println)
init {
println("Second initializer block that prints ${name.length}")
}
}
- Secondary constructor
- 클래스의 본문에 constructor 키워드로 선언하는 함수, 여러 개 추가 가능
- 주 생성자와 보조 생성자를 모두 선언한다면 생성자끼리 연결 필요
class Person(val pets:MutableList<Pet> = mutableListOf())
class Pet{
constructor(owner:Person) {
owner.pets.add(this) // adds this pet to the list of its owner's pets
}
}
class Person(val name:String) {
val children: MutableList<Person> = mutableListOf()
constructor(name:String, parent:Person) :this(name) {
parent.children.add(this)
}
}
2.3 코틀린의 클래스 종류
1) 데이터 클래스
- data 키워드로 선언
- .equals() or == : 두 객체의 데이터를 비교 (주 생성자의 멤버 변수가 같은지만 판단)
- .toString() 함수 : 객체의 데이터를 반환 (객체가 포함하는 멤버 변수의 데이터 출력)
- .copy() : 객체 복사해서 새로운 클래스 인스턴스 생성
data class User(val name: String, val id: Int)
2) 컴패니언 클래스
- 멤버 변수나 함수를 클래스 이름으로 접근하고자 할 때 사용
- companion object 키워드 사용
class Test {
companion object {
var data = 100
fun func() {
println("hello!")
}
}
}
fun main() {
Test.func()
println(Test.data)
}
3) 오브젝트 클래스
- 익명 클래스를 만들 목적으로 사용
- 클래스를 선언하면서 동시에 객체 생성
- object 키워드 사용 ; object: 타입() {}
open class Test {
open var data = 100
open fun func() {
println("hello!")
}
}
var o = object: Test() {
override var data = 100
override fun func() {
println("hello")
}
}
fun main() {
o.data = 10
o.func()
}
2.4 상속
1) 상속 방법
- 하위 클래스 : 상위 클래스
2) 코틀린에서의 상속
- 코틀린의 클래스는 기본적으로 상속 불가
- 상속을 위해서는 상위 클래스 선언 시 open 키워드 필요
- 하위 클래스의 생성자에서 상위 클래스의 생성자 호출 : super()
3) 재정의 (overriding)
- 상위 클래스에 선언된 변수나 함수를 하위 클래스에서 다시 정의하는 것
- 상위 클래스에서 오버라이딩을 허용할 변수나 함수 선언 앞에 open 키워드 추가
- 하위 클래스에서 재정의할 때 override 키워드 추가
3. 널 안전성 (Null Safety)
3.1 null
- 널 (null) : 객체가 선언되었지만 초기화되지 않은 상태
- 널 포인트 예외 : 널인 상태의 객체를 사용할 수 없다는 오류
- 널 안전성 : 널 포인트 예외가 발생하지 않도록 코들르 작성하는 것
fun main() {
var neverNull: String = "This cant't be null"
neverNull = null // Throws a compiler error
var nullable: String? = "You can keep a null here"
nullable = null // ok
fun strlength(notNull: String): Int {
return notNull.length
}
println(strlength(neverNull))
println(strlength(nullable)) // Throws a compiler error
}
3.2 널 안전성 연산자
- 널 허용 연산자 ?
var test: String? = "Mobile"
test = null
- 널 안전성 호출 연산자 ?.
- 널 허용으로 선언한 변수의 멤버에 접근할 때는 반드시 ?. 키워드 사용
- 변수가 null이 아니면 멤버에 접근, null이면 멤버에 접근하지 않고 null 반환
fun lengthString(myabeString: String?): Int? = maybString?.length
fun main() {
val nullString : String? = null
prinln(lengthString(nullString)) // null
}
- Elvis 연산자 ?:
- 변수가 null일 때 대입해야 할 값을 지정
fun main() {
val nullString: String? = null
println(nullStirng?.length ? : 0) // 0
}
- 예외 발생 연산자 !!
- 객체가 널일 때 예외를 일으키는 연산자
- 널 허용인 객체라도 강제 예외를 발생
4. 지연 초기화
; 클래스의 코드에 Nullable 처리가 남용되는 것을 방지
4.1 lateinit
- 선언 초기값을 할당할 것임을 명시적으로 선언
- var 키워드로 한 변수만 사용 가능 (기초 타입 객체에는 사용 불가)
fun main() {
lateinit var name: String
// Nullable로 선언 시 -> var name: String? = null
init {
name = "kotlin"
}
fun process() {
name.plus("Hi")
// Nullable로 선언 시 -> name?.plus("Hi")
}
}
4.2 by lazy { }
- 소스에서 변수가 최초로 이용되는 순간 { } 부분이 자동으로 실행, 결과값이 변수의 초기값으로 할당
- 읽기 전용 변수인 val을 사용하는 지연 초기화
class Company {
val person: Person by lazy {Person()}
fun process() {
println("person의 이름은 ${person.name}") // 최초 호출 시 초기화
}
}
5. 스코프 함수
; 코드를 축약해서 표현할 수 있도록 도와주는 함수, 영역 함수
5.1 run
- 함수 안에서 호출한 대상을 this로 사용 가능
- 클래스 내부의 함수를 사용하는 것과 동일한 효과이기 때문에 this는 생략하고 메서드나 프로퍼티를 바로 사용 가능
- 스코프의 마지막 코드를 반환
var list = mutableListOf("Scope", "Function")
val lastItem = list.run {
it.add("Run")
get(size-1)
}
println("반환값 run = $lastItem")
5.2 let
- 함수 안에서 호출한 대상을 it으로 사용 가능
- it을 생략할 수는 없지만 target 등 다른 이름으로 바꿀 수 있음.
- 스코프의 마지막 코드를 반환
var list = mutableListOf("Scope", "Function")
list.let { target -> // it 대신 다른 이름 사용 가능
val listSize = target.size
println("리스트의 길이 let = $listSize")
}
val lastCount = list.let {
it.add("let")
it.count()
}
println("반환값 let = $lastCount")
5.3 apply
- this로 사용되는 스코프 함수
- 호출 대상인 this 자체를 반환하는 스코프 함수
- 스코프 함수 안에서 코드가 모두 완료된 후에 자기 자신을 되돌려줌.
var list = mutableListOf("Scope", "Function")
list.apply {
val listSize = size
println("리스트의 길이 apply = $listSize")
}
val afterApply = list.apply {
add("Apply~")
count()
}
println("반환값 apply = "$afterApply")
5.4 also
- it으로 사용되는 스코프 함수
- 호출 대상인 this 자체를 반환하는 스코프 함수
var list = mutableListOf("Scope", "Function")
list.also {
val listSize = it.size
println("리스트의 길이 also = $listSize")
}
5.5 with
- this로 사용되는 스코프 함수
var list = mutableListOf("Scope", "Function")
with (list) {
val listSize = size
println("리스트의 길이 with = $listSize")
}
'전공과목 정리 > 모바일소프트웨어' 카테고리의 다른 글
[모바일소프트웨어📱] 코틀린(Kotlin) 문법 (1) (0) | 2024.09.16 |
---|