업데이트:

카테고리:

/

태그: ,

확장함수

어떤 클래스의 멤버 메서드인 것처럼 호출, 클래스 밖에 선언된 함수

기존의 클래스는 건들이지 않고 추가로 함수를 제작함 ⇒ 캡슐화는 깨지지 않음

fun string.lastChar(): Char = this.get(this.length - 1)
  • string : 타입
  • this : 수신받는 객체
open class Shape
class Rectangle: Shape() 

fun Shape.getName() = "shape"
fun Rectangle.getName() = "rectangle"

fun printClassName(s: Shape) {
	println(s.getName())
}

printClassName(Rectangle()) // shape

확장 함수는 정적 바인딩되기 때문에 컴파일 이후, 값이 변하지 않는다.

범위지정함수

제공된 람다식을 써서 객체에서 이런 함수를 호출하면 임시 범위가 형성된다. 이 범위에선 이름없이 객체에 접근할 수 있다.

작성하는 이유는 범위함수를 사용해서 코드를 작성한 경우가 가독성이 더 좋기 때문에

receiver : 수신객체

block : 람다식

  1. with → Non-Null한 수신 객체, 결과가 필요하지 않은 경우

     <T.R>.with(receiver: T, block: T.() -> R): R {
     	return receiver.block()
     }
        
     val person = Person("Jone", 30)
     val result = with(person) {
     	// 별도의 참조없이도 객체 내부의 변수와 함수를 사용할 수 있음
     	// 람다식의 결과를 반환함
     	val Introduction = "내 이름은 $name이고 나이는 $age입니다."
     	Introduction.length // 리턴값
     }
    
  2. also → 객체를 사용하지 않음, 객체 속성을 변경하지 않고 사용 / 사이드 이펙트, 데이터 유효성 검사

     <T>T.also(block: (T) -> Unit): T {
     	block(this)
     	return this
     }
        
     val list = listOf<String>("one", "two").also { it ->
     	// 반환값은 로직을 돈 결과가 아니라 원본 데이터라는 점
     	println("반환 목록 $it")
     }
    
  3. apply → 람다 내부에서 객체 함수를 사용하지 않을 때, 객체 자신은 반환시 사용 / 객체 초기화에 주로 사용

     <T>T.apply (block: T.() -> Unit) : T {
     	block()
     	return this
     }
        
     val person = Person().apply {
     	// Person 객체 내부에 있는 변수를 초기화하거나 변경
     	name = "John"
     	age = 30
     	say("Hello")
     }
    
  4. let → 저장된 값이 null이 아닌 경우에 코드를 실행해야 될 때 사용

     <T.R>T.let(block:(T) -> R) R {
     	return block(this)
     }
    
  5. run → 어떤 값 계산 / 여러 개의 지역 변수 범위 제한

     <T.R>T.run(block: T.() -> R): R {
     	return block()
     }
        
     // also와 다르게 로직을 실행한 결과가 반환된다.
     val message = "Hello World"
     val result = message.run {
     	val uppercased = toUpperCase() // == this.toUpperCase()
     	"$uppercased length: ${length}" // 람다 결과
     }