본문 바로가기

IT/코틀린으로 배우는 함수형 프로그래밍

[코틀린으로 배우는 함수형 프로그래밍] 2장 코틀린으로 함수형 프로그래밍 시작하기

안녕하세요 남갯입니다.

 

프로퍼티 선언

 

val value: Int = 10
var variable : Int = 10
var value = 10 // 타입추론
val value = 10 // 타입추론
val value :Int? = null //널처리

 

함수 선언

fun twice(value : Int) : Int{
        return value*2
    }
    fun twice2(value : Int) : Int = value *2
    fun twice3(value : Int) = value *2

함수의 매개변수가 2개인것과 기본 디폴트값을 설정 가능하다.

 

매개변수가 여러개일경우 특정 값에 대한 '변수명 = 5'와 같이 가능하다.

익명함수

실제 구현부를 작성하지 않고 표현하는 방식

fun sum(x: Int, y: Int, calculate: (Int, Int) -> Int): Int {
        return calculate(x, y)
    }

    val sum2 = sum(5, 10) { x, y -> x + y }

확장함수

확장할 타입에 .을 붙인뒤 함수명을 붙인다면 합성의 형태로 확장이 가능하다.

실제 다른 함수명이 있을경우 

fun Int.Product(value : Int): Int{
       return this * value 
    }

연습문제 2-1

fun String.print(str : String) {
        println("hello $str")
    }

코틀린 제어문에는 

if, when문이 존재한다.

 

for 문을 표현하는 방법

 

collection의 경우 withindex()

in, (i in 1..3) , (i until 1..3) , (i in 6 downTo 0 step2)

 

 

인터페이스

인터페이스의 특징

1. 다중상속이 가능하다.

interface foo {}
    interface bar {}
    class Kotlin : foo, bar

 

2. 추상 함수를 가질 수 있다.

    interface foo {
        fun printFoo(){
            
        }
    }
    interface bar {
        fun printBar()
    }
    class Kotlin : foo, bar{
        override fun printBar() {
            TODO("Not yet implemented")
        }
    }

 

3. 함수의 본문을 구현할 수 있다. (자바의 default와 같이)

    interface foo {
        fun printFoo(){
            
        }
    }

 

4. 여러 인터페이스에서 같은 이름의 함수를 가질 수 있다. 

5. 추상 프로퍼티를 가질 수 있다.

interface AbstractProperty{
        val a : Int
    }

 

클래스

class User(var name : String, val age : Int = 18)

var로 선언된 프로퍼티는 getter setter 둘다 가능, val은 게터만 사용가능

 

데이터 클래스

데이터 클래스는 기본적으로 게터,세터, hashCode, equals,toString 함수들을 자동으로 생성

(추가적으로 component와 copy 함수를 제공, copy는 객체의 값을 복사할때 사용, component는 프로퍼티 갯수만큼 호출이 가능한데, 프로퍼티 이름 대신 접근할때 사용)

 

Enum 클래스

자바의 enum 클래스와 동일하다.

 

Sealed클래스

    sealed class Expr {
        data class Const(val number: Double) : Expr()
        data class Sum(val number: Double) : Expr()
        object NotANumber : Expr()
    }

    fun eval(expr: Expr): Double = when (expr) {
        is Expr.Const -> {
            0.0
        }
        is Expr.Sum -> {
            0.0
        }
        is Expr.NotANumber -> {
            0.0
        }
    }

enum과 는 다르게 각 다른 프로퍼티를 가지고 있다.

또한 when절에서 해당 프로퍼티를 설정하지 않으면 컴파일 에러가 나고, else문을 처리할 필요가 없다.

 

 

패턴 매칭

(in 속한다면, ===는 참조 , == 값비교 , is 타입비교)를 통해 비교

 

객체 분해

코틀린에서는 객체를 분해하는 기능을 제공 

객체분해란 어떤 객체를 구성하는 프로퍼티를 분해햐여 편리하게 변수에 할당하는것을 말한다.

 

클래스 객체분해

   data class User(var name: String, val age: Int = 18)
    fun test33(){
        val user : User = User("kotlin", 28)
        val (name,age) = user
    }

리스트 객체분해

    fun listTest(){
        val user1: User = User("kotlin", 28)
        val user2: User = User("kotlin", 28)
        val user3: User = User("kotlin", 28)
        val users = listOf(user1, user2, user3)
        for ((name, order) in users) {
            println("name : $name , order : $order")
        }
    }

맵 객체분해

    val map = mapOf<String, Int>("kotlin" to 1)
    fun mapTest(){
        for((name,order) in map){
            println("name : $name , order : $order")
        }
    }

*****객체분해가 가능한 이유는 위에서 설명했던, data클래스로 선언된 내부에 componentN 함수가 객체분해에 사용되기 때문이다.

 

객체 분해를 활용한 예

    fun lamda() {
        { p1: Int, p2: Int -> "$p1 $p2" }
        { (p1, p2) -> "$p1 $p2" } //??
    }

컬렉션

리스트와 셋, 맵은 

자바와는 다르게 불변과 가변이 존재한다.

기본적으로는 Immutable하며, Mutable 키워드를 붙여 가변적으로 변경한다.

제네릭

제네릭이랑 객체의 사용할 데이터타입을 외부에서 정하는 기법이다. 즉 다양한 타입의 클래스를 유동적으로 사용하게 만들면서 실제 사용부분에서 해당 객체의 타입을 지정하여 해당 타입의 클래스로 사용하도록 하는것.

 

class Box(t: Int){
        var value = t
    }
    class BoxT<T>(t : T){
        var value = t
    }

구체적인 T 타입이 정의되기 전까지는 T를 타입 생성자라고 부른다.

 

** 실제 생성자에 BoxT<String>("kotlin") 과 같이 <>내부에 실제 타입을 직접적으로 명시하지 않아도 컴파일러는 생성자의 타입을 보고 String 으로 타입을 추론한다.

 

 

코틀린의 표준 라이브러리인 5개(let, with, apply, run also)

let, with, apply, run also 함수에 

 

https://namget.tistory.com/entry/let-with-run-also-apply-%EC%A0%95%EB%A6%AC

 

[코틀린] let, with, run, also, apply 정리

안녕하세요 남갯입니다. run과 let 등등 대충의 쓰임새만 알고 있고 따로 물어보면 사용처에 대한 정리가 되어 있지 않아 정리를 못했던거같은데 에서 다시 정리해서 포스팅해보려고 작성했습니�

namget.tistory.com

 

5개의 함수 내부 비교

    fun <T, R> T.let(block: (T) -> R): R
    fun <T, R> with(receiver : T, block: T.() -> R): R
    fun <T,R> T.run(block : T.() -> R) : R
    fun <T> T.apply(block: T.() -> Unit) : T
    fun <T> T.also(block: (T) -> Unit) : T

 

use 함수

use함수는 클로즈 작업을 자동으로 해주는 함수이다. 즉 try-with-resource의 기능과 동일하다.

 

fun useTest(){
        val property = Properties()
        FileInputStream("config.property").use{
            property.load(it)
        }
    }

자동으로 클로즈 작업을 해주는 함수

 

변성

https://namget.tistory.com/entry/kotlin-%EC%A0%9C%EB%84%88%EB%A6%AD%ED%83%80%EC%9E%85-%EC%A0%95%EB%A6%AC

 

[kotlin] 제너릭 변성(variance) 정리

안녕하세요 남갯입니다 오늘은 제너릭 타입에대해 정리해보려고합니다 SubType 이란? subType이란 어떤 class가 다른클래스를 상속받은것을 의미한다. 즉 타입 A가 필요한 곳에 타입 B 값을 넣어도 문

namget.tistory.com

변성을 이해하기 위해

타입 S가 T의 하위타입일때, Box[S]가 Box[T]의 하위타입인가로 질문하는것이 좋다

 

Box[S]가 Box[T]의 상관없음 -> 무공변

Box[S]가 Box[T]의 하위타입 ->공변

Box[T]가 Box[S]의 하위타입 ->반공변

 

https://namget.tistory.com/entry/%EC%BD%94%ED%8B%80%EB%A6%B0-%EC%BD%94%ED%8B%80%EB%A6%B0-%EC%A0%9C%EB%84%88%EB%A6%AD%EC%8A%A4