본문 바로가기
언어/Kotlin

[Kotlin 문법 종합] - 여러 인스턴스 리턴, 자신의 객체 전달 @@수정하기

by 젼젼39 2024. 3. 6.

1. 여러 인스턴스 리턴

    : 두 개 이상의 데이터를 포함하는 데이터클래스를 만들고 인스턴스 리턴하기

    //메소드는 기본적으로 하나의 데이터를 리턴함

1) Pair     =  2개의 인스턴스 리턴

    var chicken = Chicken()
    var eggs = chicken.getEggs()
    var listEggs = eggs.toList()
    
    // 리스트로 관리
    var firstEgg = listEggs[0] 		// = eggs.first 
    var secondEgg = listEggs[1] 	// = eggs.second

    println("달걀의 종류는 ${eggs} 입니다.") 		//(달걀, 맥반석) // Pair
    println("리스트 달걀의 종류는 ${listEggs} 입니다.") 	//[달걀, 맥반석] // toList
    println("첫번째 달걀의 종류는 ${firstEgg} 입니다.")
    println("두번째 달걀의 종류는 ${secondEgg} 입니다.")
}

class Chicken {
    fun getEggs(): Pair<String, String> {
        var eggs = Pair("달걀", "맥반석")
        return eggs
    }
}

 

2) Triple    = 3개의 인스턴스 리턴

fun main() {
    var chicken = Chicken()
    var eggs = chicken.getThreeEggs()
    var listEggs = eggs.toList()
    
    // 리스트로 관리
    var firstEgg = listEggs[0] 		// = eggs.first
    var secondEgg = listEggs[1] 	// = eggs.second
    var eggTime = listEggs[2] 		// = eggs.third

    println("달걀의 정보는 ${eggs} 입니다.") 		//(달걀, 맥반석, 20230101)
    println("리스트 달걀의 정보는 ${listEggs} 입니다.") 	//[달걀, 맥반석, 20230101]
    println("첫번째 달걀의 종류는 ${firstEgg} 입니다.")
    println("두번째 달걀의 종류는 ${secondEgg} 입니다.")
    println("달걀은 ${eggTime}에 나왔습니다.")
}

class Chicken {
    fun getTwoEggs(): Pair<String, String> {
        var eggs = Pair("달걀", "맥반석")
        return eggs
    }

    fun getThreeEggs(): Triple<String, String, Int> {
        var eggs = Triple("달걀", "맥반석", 20230101)
        return eggs
    }
}

 

 

2. 자신의 객체 전달

    : Scope Functions들을 제공, 객체를 사용할 때 임시로 Scope를 만들어 편리한 코드 작성을 도움

vv 다시 이해하기... @@@@

(1) 명시적으로 수신객체 자체를 람다의 수신객체로 전달하는 방법

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

(2) 수신객체를 람다의 파라미터로 전달하는 방법

public inline fun <T> T.also(block: (T) -> Unit): T
public inline fun <T, R> T.let(block: (T) -> R): R

    // T = 수신객체.   it으로 사용 가능 but 문제점 있음
    // block: 내부는 람다함수의 소스코드

    // 모든 수신객체를 it으로 활용할 경우의 문제점 = 제대로 참조하지 못할 수 있음
            --> it을 다른 이름으로 변경해 사용하기도 함

// Scope Function을 중첩으로 사용할 경우 누가 누구의 범위인지 알수 없다!
// Implicit parameter 'it' of enclosing lambda is shadowed 경고 발생!

data class Person(
	var name: String = "",
	var age: Int? = null,
	var child: Person? = null
)

// 잘못된 예시
Person().also {
	it.name = "한석봉"
	it.age = 40
  val child = Person().also { 		//it 안에서 또 also를 한 것
	  it.name = "홍길동" // 누구의 it인지 모른다! 
    it.age = 10 // 누구의 it인지 모른다!
  }
  it.child = child
}

// 수정한 예시
Person().also {
	it.name = "한석봉"
	it.age = 40
  val child = Person().also { c -> 		//it 이 아니라 c로 넘겨줌!
	  c.name = "홍길동"
    c.age = 10
  }
  it.child = child
}

 

  • let, with, also, apply, run
  it this
{ } 블록 수행 결과를 리턴 let run, with
객체 자신을 반환 also apply

 

1) let function

    : { } 안에 it으로 자신의 객체를 전달, 수행 결과를 반환

    var strNum = "10"

    var result = strNum?.let { 		//strNum이 null이 아닐 때 
        Integer.parseInt(it) 		//{ } 안에서 strNum을 it으로 대체해 사용 가능
    } 								//parseInt에 strNum을 넘겼을 때 문자열을 숫자로 바꿔 result에 저장

    println(result!!+1) 		//result가 0이 아님을 보장하고 1을 더해 11이 나옴

2) with function

    : { } 안에 this로 자신의 객체를 전달, 코드 수행
    //this는 생략 가능.
    //null이 확실히 아닐 때만 사용하는 것을 권장. this는 언제든 사용 가능하니까

    var alphabets = "abcd" 		//뭔가 들어있으니 null이 아닌 게 확실함

    with(alphabets) { 		//이 뒤부터 { } 안에서 alphabets는 this로 불린다
//      var result = this.subSequence(0,2)    //this 생략가능
        var result = subSequence(0,2)
        println(result)
    }

 

3) also function

    : { } 안에 it으로 자신의 객체를 전달, 객체 반환

    //apply와 자주 사용

fun main() {
    var student = Student("참새", 10)

    var result = student?.also { 		//student 객체가 null이 아닐때만 실행
        it.age = 50 				//student.age 와 동일, age가 바뀐 student 객체가 result에 대입됨.
    }
    result?.displayInfo() 		//동일한 결과 나옴
    student.displayInfo() 		//동일한 결과 나옴
}

class Student(name: String, age: Int) {
    var name: String
    var age: Int

    init {
        this.name = name
        this.age = age
    }

    fun displayInfo() {
        println("이름은 ${name} 입니다")
        println("나이는 ${age} 입니다")
    }
}

4) apply function

    : { } 안에 this로 자신의 객체 전달, 객체를 반환

    - 객체의 상태 변화시킨 뒤 바로 저장하고 싶을 때 사용

fun main() {
    var student = Student("참새", 10)

    var result = student?.apply { 		//여기!!
        student.age = 50 		//it이 아니라 this로 들어옴, 객체의 상태를 변환하고 바로 반환, result에 대입
    }
    result?.displayInfo()
    student.displayInfo()
}

class Student(name: String, age: Int) {
    var name: String
    var age: Int
    
    init {
        this.name = name
        this.age = age
    }
    
    fun displayInfo() {
        println("이름은 ${name} 입니다")
        println("나이는 ${age} 입니다")
    }
}

5) run function

    (1) 객체에서 호출하지 않는 경우

    var totalPrice = run { 			//여기! 임시영역 사용st
        var computer = 10000
        var mouse = 5000

        computer+mouse 			//totalPrice에 대입됨
    }
    println("총 가격은 ${totalPrice}입니다")

    (2) 객체에서 호출하는 경우    // null이 보장되어야 하는 with와 달리 null 체크 가능, 안전

fun main() {
    var student = Student("참새", 10)
    student?.run { 				//여기!! student가 null이 아닐 때만 run 할 수 있음
        displayInfo() 			// = student.displayInfo( )  //  = with에서도 this 생략하고 메소드 바로 썼음
    }
}

class Student(name: String, age: Int) {
    var name: String
    var age: Int
    
    init {
        this.name = name
        this.age = age
    }
    
    fun displayInfo() {
        println("이름은 ${name} 입니다")
        println("나이는 ${age} 입니다")
    }
}