여기까지 정리 2

  1. 고차함수란?
    • 다른 함수를 파라미터로 받거나 함수를 반환하는 함수
  2. 코틀린의 람다, 자바의 람다와의 차이?
    • 람다가 함수 인자면 트레일링 클로저처럼 뺼 수 있다.
    • 람다 인자가 하나면 이름 지정 없이 it로 뺄 수 있다.
  3. 코틀린의 함수 타입, 자바의 함수형 인터페이스와 차이?
    • 함수 타입은 함수처럼 쓰일 수 있는 값들을 표시하는 타입이다.
    • 함수 타입은 SAM 인터페이스로 암시적으로 변환할 수 없다.
    • 자바의 SAM은 람다나 메소드 참조로 인스턴스화할 수 있다.

SAM(Single Abstract Method)

  1. 수신 객체가 있는 함수 타입, 없는 함수 타입
    • 수신 객체 X: (Int) -> Int
    • 수신 객체 O: Int.(Int) -> Int
  2. 익명 함수와 람다의 차이
    • 익명 함수는 fun(parameter)의 형태로 작성하는 이름이 없는 함수
  3. 인라인 함수와 제약
    • inine함수는 컴파일 타임에 해당 선언을 인라인으로 넣어준다. 이러면 오버헤드가 줄어들게 된다.
  4. 호출 가능 참조
    • 람다나 익명함수로 함수 값을 만들었을 때 이미 선언되어 있고 이를 함수로 넘기려면
    • ::functionName으로 넘길 수 있다.
  5. 람다와 익명 함수 안에서의 return
    • 비지역적 반환(non-local return)이 일어난다.
    • 비지역적 반환은 특정 블록이나 람다 표현식의 스코프를 벗어나 바깥쪽 함수나 스코프로 반환하는 것을 의미한다.
      • 이러면
        1. 흐름 제어에서 예기치 않은 반환이 일어난다.
        2. 유지보수가 어려워진다.
        3. 테스트도 어려워진다.
        4. 가독성도 떨어진다.
        5. 안정성이 떨어진다.
    • 이 말은 즉, 람다나 익명함수가 컴파일되면 inline이 된다.
  6. inline, noinline, crossinline
    • inline: 컴파일 타임에 코드를 아예 해당 부분에 바로 넣는다.(원래 거기 있는 것처럼)
    • noinline: inline을 막는다.
    • crossinline: 주로 비지역적 제어흐름을 막기 위해서 사용한다.
  7. 확장함수란?
    • 어떤 클래스의 멤버인 것처럼 호출할 수 있는, 그러나 멤버는 아닌 함수를 의미한다.
  8. 동반객체확장
    • 클래스에 내포된 객체 중에서 바깥 클래스의 이름으로 객체 멤버에 접근할 수 있는 companion 레벨에서 확장하는 것을 의미한다.
    • Companion 을 명시한다.
  9. 확장 프로퍼티와 제약
    • 다른 일반 멤버와 마찬가지로 확장프로퍼티에 접근할 수 있다.
    • 그러나 안정적으로 상태를 추가할 방법이 없어서 뒷받침 필드를 사용할 수 없고
    • lateinit 등도 불가하다.
    • lazy도 (delegate) 쓸 수는 있는데 의미가 없다.
    • 명시적 get/set이 필요하다.
  10. 클래스 내부에서 확장 함수 선언의 주의점?
    • 캡슐화는 꺨 수 없지만 시그니쳐가 겹치면 멤버를 먼저 콜해서 원하는 대로 동작하지 않을 수 있다.
  11. 영역 함수란?
    • apply, with, let, also, run 등이 있다.

         inline fun <T, R> with(receiver: T, block: T.() -> R): R {
              return receiver.block()
          }
            
            
          inline fun <T> T.also(block: (T) -> Unit): T {
          block(this)
          return this
          }
            
            
          inline fun <T> T.apply(block: T.() -> Unit): T {
          block()
          return this
          }
            
            
          inline fun <T, R> T.let(block: (T) -> R): R {
          return block(this)
          }
            
            
          inline fun <T, R> T.run(block: T.() -> R): R {
          return block()
          }
       
      /**
       *   with, also, apply, let, run은 3가지 차이점 중 한 가지가 서로 다르다.
       * 1. 범위 지정 함수 호출 시 수신 객체가 매개 변수로 명시적으로 전달되거나 수신 객체의 확장 함수 형태로 암시적 수신 객체로 전달  
       * 2. 범위 지정 함수의 수신 객체 지정 람다에 전달되는 수신 객체가 명시적으로 매개 변수로 전달되거나 수신 객체의 확장 함수로 암시적인 수신 객체로 코드 블록 내부로 전달
       * 3. 범위 지정 함수의 결과로 수신 객체를 그래로 반환하거나 수신 객체 지정 람다의 실행 결과 반환
      **/
      
      • apply 사용 예시: 수신 객체 람다 내부에서 수신 객체의 함수를 사용하지 않고 수신 객체를 다시 반환하려는 경우
      • also 사용 예시: 수신 객체의 프로퍼티나 함수 대신에 객체 자기 자신에 대한 참조가 필요한 경우
      • let 사용 예시: null safety 체크에서 많이 사용
      • with 사용 예시: NonNull 수신객체이고 결과가 필요하지 않은 경우
      • run 사용 예시: 값을 계산할 필요가 있거나 여러 개의 지역 변수 범위를 제한하려고 할 떄