코틀린 심화문법
이전 글에 이어서, 심화 문법을 작성한다!
이전 글에서 헷갈릴만한 점을 질문받았었는데,
val tmp : String
fun method : Int
class Dog : Animal() {
constructor() : this() { }
}
: 가 붙으면, 공통적으로 '타입, 자료형' 이라고 생각하면 편하다.
변수의 타입, 함수의 타입, 클래스의 타입(부모), 생성자의 타입(부모)
이해하기에 따라 어느정도의 부조화가 있을 수도 있지만, 크게 상관없을 것이다.
1. 람다
함수형 프로그래밍의 대표적 예. value 처럼 다룰 수 있는 익명함수.
1) 변수에 넣을 수 있다
2) 메소드의 파라미터로 넘겨줄 수 있음.
3) return 값으로 사용할 수 있다.
// 람다명 : 인자타입-> 리턴타입 = { 입력값 -> 리턴값 }
val square : (Int) -> (Int) = { number -> number * number }
// 람다명 = {입력 -> 출력}
val nameAge = {name : String, age : Int -> "my name is ${name}, I'm ${age}"}
// 어쨌든 타입추론이 가능하게 지정해주어야 한다.
// 사용할 때엔 square(), nameAge() 이렇게 사용한다
fun main() {
println(square(12)) // 144
println(nameAge("hevton", 25)) // my name is hevton, I'm 25
}
람다는 처음 접하면 어려울 수 있으나, 너무 편한 방식으로 자리잡게 될 것이므로
지금 당장 모든 걸 이해하려고 할 필욘 없다
람다를 인자로 받아보기 예시
// 람다를 인자로 받아본다.
// Double을 받아서 Boolean을 뱉는 람다식을 받아서, 그 Boolean값을 리턴한다.
fun invokeLambda(lambda : (Double) -> Boolean) : Boolean {
return lambda(5.2343)
}
fun main() {
// Double형 number를 받는데, 그 number가 5.2343이냐에 따라서 true/false 리턴하는 람다
val lambda = {number : Double -> number == 5.2343}
println(invokeLambda(lambda)) // true
println(invokeLambda({it > 3.22})) // true
println(invokeLambda { it > 3.22 }) // true
}
2. 확장함수
코드로 보는게 이해가 더 빠를 것 같다.
// sleepy 확장함수. String객체에 ()꼴을 취하여 호출한 뒤, 리턴은 String이다.
val sleepy : String.() -> String = {
this + " is sleepy!"
}
fun extendString(name : String, age : Int) : String {
// String 확장함수인데, Int를 인자로 받는다. this는 확장함수를 호출한 String객체, 그리고 it은 인자를 나타내는 예약어
val introduceMyself : String.(Int) -> String = {
"I am ${this} and ${it} years old"
}
return name.introduceMyself(age)
}
// 참고로, 입력은 여러개지만 출력은 하나니까, 입력은 항상 괄호를 쳐주는 것이다.
val calculateGrade : (Int) -> String = {
when(it) {
in 0..40 -> "fail"
in 41..70 -> "pass"
in 71..100 -> "perfect"
else -> "Error"
}
}
fun main() {
val hev = "hevton"
println(hev.sleepy()) // hevton is sleepy
println(extendString("hevton", 25)) // I am hevton and 25 years old
println(calculateGrade(100)) // perfect
}
3. Data class
자바와 다르게,, 아래 함수들을 자동으로 생성해준다.
- hashCode()
- copy()
- equals()
- toString()
- componentsN()
data class Ticket(val companyName : String, val name : String, var date : String, var seatNumber : Int)
// toString(), hashCode(), equals(), copy() 를 자동으로 만들어준다.
fun main() {
val ticketA = Ticket("KoreanAir", "Hevton", "2023-01-01", 13)
// 객체 내 필드 정보들이 출력되는 장점 : data class의 장점 중 하나
println(ticketA) // Ticket(companyName=KoreanAir, name=Hevton, date=2023-01-01, seatNumber=13)
}
data 클래스는 다음과 같은 특징이 있다.
- 기본 생성자에 1개 이상의 파라미터가 있어야 함
- 기본 생성자의 파라미터가 val 또는 var 로 선언해야 함
- 다른 클래스를 상속받을 수 없음 (슈퍼 클래스를 가질 수 없음)
Data class에 대한 내용은 여기
4. Companion object
자바의 static과 같다.
class Book private constructor(val id : Int, val name : String) {
// private property나 object를 읽어올 수 있게 해준다.
// 자바의 static 역할을 한다
companion object {
fun create() = Book(0, "animal farm")
}
}
private constructor는 접근제한을 두기 위한 키워드를 넣은 거고,
이렇게 넣은 상태에서 companion object를 통해선 객체를 생성할 수 있음을 보여준다.
이렇게 하면, 해당 클래스의 컴패니언 오브젝트 안의 메서드는
인스턴스의 생성 없이 이용할 수 있다. Log.d() 이런 함수들의 d() 함수가 컴패니언 오브젝트로 감싸져 있는 것이다.
5. Object
Singleton Pattern 을 간단하게 구현할 수 있다.
싱글톤 패턴은, 객체를 단 하나만 갖는 클래스 설계 패턴이다.
object CarFactory { // object는 싱글톤 패턴이다.
var cars = mutableListOf<Car>()
fun makeCar(horsePower: Int) : Car {
val car = Car(horsePower)
cars.add(car)
return car
}
}
data class Car(val horsePower : Int) {
}
fun main() {
val car = CarFactory.makeCar(10)
val car2 = CarFactory.makeCar(200)
println(car) // Car(horsePower=10)
println(car2) // Car(horsePower=200)
println(CarFactory.cars.size.toString()) // 2
}
사용할 때엔 CarFactory 이런식으로 클래스 이름을 그대로 사용한다. 객체는 단 하나만 생성된다.
자바의 정적 클래스와 비슷해 보일 수 있지만, 객체가 생성된다는 점에서 차이가 있다.
이후에는 코틀린 + 안드로이드 강의글을 작성한다.