함수형 프로그래밍은 kotlin의 표준 라이브러리에있는 다양한 함수뿐만 아니라 Kotlin의 구문에 의해 많은지지를 받고 지원됩니다.
● 5가지의 고차함수는 기본적으로 매우 유사한 작업을 수행한다.
▷ 수신자 인수와 코드 블록을 취한 다음 제공된 수신자에서 코드 블록을 실행하는 범위 지정 함수이다.
○ 작동 확인 (with)
inline fun <T, R> with (receiver : T, block : T. ()-> R) : R { return receiver.block () }
이를 사용하면 코드를 더 간결하게 만들 수 있다.
○ with 함수를 사용하지 않은 코드
class User { var id : Long? = null var passwd : String? = null } val user : User = getUser () print (user.id) print (user.passwd)
with 를 사용해서 user 객체의 반복을 제거한다.
이 부분만 빼면 아래와 동일한 코드이다.
val user : User = getUser () with ( user ) { print (id) print (passwd) }
중복이 제거 되어서 좋다. (코드양은 비슷 한 것 같음)
● 그래서 왜 5가지의 함수가 필요한가?
▷ 차이점은 확인하자
○ with 와 also를 비교 (3가지 틀림)
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 }
1. 수진자 인수는 with () 의 경우 명시 적 매개 변수 T 로 제공하는 반면, also () 의 경우 암시 적 수신자 T 로 제공됩니다.
2. 블록 인수는 with () 의 경우 암시 적 수신자 T 를 갖는 함수로 정의되고, also () 의 경우에는 명시적 인수 T 가 있습니다.
3. with () 함수는 블록 인수를 실행하여 반환되는 것을 반환하는 반면 also () 함수는 수신자로 제공된 동일한 객체를 반환합니다.
이 세가지 차이점 때문에 also 함수는 다른 방식으로 사용해야 한다.
val user : User = getUser ().also { print (it.id) print (it.passwd) }
이 코드는 getUser () 함수 를 통해서 user 변수에 할당합니다. 그 전에 also () 함수는 검색된 사용자의 정보를 출력한다.
● 나머지 3개 함수는? (apply, let, run)
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() }
○ apply 의 사용법!
# apply 이용 안함 var user = User() user.name = "whydda" user.passwd = "1234" # apply 이용 val whydda = User().apply { id = "whydda" passwd = "1234" }
블록이 수신자 매개 변수에 전혀 엑세스하지 않건 수신자 매개 변수를 변경하지 않을 경우 also () 를 사용하고 블록이 다른 값을 반환해야 하는 경우는 also를 사용하지 마십시오 예를 들어, also () 는 객체에 대한 부작용을 실행하거나 속성에 할당하기 전에는 데이터 유효성 검사를 할때 매우 유용합니다.
# also () 사용 class Book(user : User) { val author = user.also { requireNotNull(it.passwd) print(it.id) } } # also () 사용 안함 class Book(val user : User) { init { requireNotNull (user.passwd) print (user.id) } }
● let 은 이럴 경우 사용하십시오!
▷ 값이 null이 아닌 경우 코드 실행
▷ nullable 개체를 다른 nullable 개체로 변환
▷ 단일 지역 변수의 범위 제한
○ let의 사용법!
▶ let 사용하지 않음
val person: Person? = getPromotablePerson() if (person != null) { promote(person) } val driver: Person? = getDriver() val driversLicence: Licence? = if (driver == null) null else licenceService.getDriversLicence(it) val person: Person = getPerson() val personDao: PersonDao = getPersonDao() personDao.insert(person)
▶ let 을 사용함
getNullableUser()?.let { // only executed when not-null (not-null 일 경우에만 실행 됨) promote(it) } val driversLicence: Licence? = getNullablePerson()?.let { // convert nullable person to nullable driversLicence licenceService.getDriversLicence(it) } val user: USer = getUser() getPersonDao().let { dao -> // scope of dao variable is limited to this block dao.insert(person) }
● run 은 이런경우 사용한다.
▷ 일부 값음 계산해야하거나 여러 지역 변수의 범위를 제한하려면 run을 사용하십시오.
▷ 명시적 매개 변수를 암시적 수신자로 변환하려는 경우도 런을 사용한다.
○ run 의 사용법
▶ run 사용함
val inserted: Boolean = run { val person: Person = getPerson() val personDao: PersonDao = getPersonDao() personDao.insert(person) } fun printAge(person: Person) = person.run { print(age) }
▶ run을 사용하지 않음
val person: Person = getPerson() val personDao: PersonDao = getPersonDao() val inserted: Boolean = personDao.insert(person) fun printAge(person: Person) = { print(person.age) }
▣ 마지막으로 범위 지정 함수와 VS with, let, also, run
여러 지정 함수에 사용법을 알아보았다. 동일한 코드 블록내에서 여러 범위 지정 함수를 결합하려는 경우가 많았습니다.
범위 지정 함수가 중첩되면 코드가 빠르게 혼란스러워 질 수 있다. 일반 적으로 수신자 인수를 람다 블록의 수신자 (apply, run, with)에
바인딩 하는 범위 지정함수를 중첩하지 마십시오 다른 범위 지정 함수를 중헙할때 람다의 블록의 매개 변수에 대한 명시적인 이름을 제공합니다.
즉, 해당 범위 지정 함수를 중첩 할때 암시 적 매개 변수를 사용하지 마십시오.
중첩 외에도 범위 지정 기능을 콜 체인에서 결합 할 수도 있습니다. 중첩과 달리 이러한 방식으로 범위 지정 함수를 결합 할 때 가독성이 저하되지 않습니다. 오히류 가독성은 향상될 것 입니다.
콜 체인에서 범위 지정 함수를 사용하는 예를 들어보겠다.
private fun insert(user: User) = SqlBuilder().apply { append("INSERT INTO user (email, name, age) VALUES ") append("(?", user.email) append(",?", user.name) append(",?)", user.age) }.also { print("Executing SQL update: $it.") }.run { jdbc.update(this) > 0 }
apply, also, run 을 이용하여 SQL 준비, 로깅, 실행과 같은 문제를 분리했다.
이 것으로 5가지 고차함수에 대해 알아 보았다.
잘 사용하면 가독성이 상당히 좋아 질 것으로 보인다!
▣ 아래의 링크를 필사 하였습니다. 구글 번역을 사용해 번역에 틀린 부분 있으면 알려주세요 :)
https://medium.com/@fatihcoskun/kotlin-scoping-functions-apply-vs-with-let-also-run-816e4efb75f5
'Back-End > kotlin' 카테고리의 다른 글
[kotlin] groupBy (0) | 2022.12.26 |
---|