23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
이전에 범위함수 기본에 대해서 알아보았다.
(참고 https://devocean.sk.com/blog/techBoardDetail.do?ID=165527)
이번에는 각각 범위함수를 상세히 알아볼 것이다.
let 범위 함수는 다음 특성을 가진다.
참조 컨텍스트: context object 참조, it를 통해서 참조한다.
결과 값: 람다 결과를 반환한다.
let은 호출 체인 결과에 대해 하나 이상의 함수를 호출하는데 사용할 수 있다.
01.let_sample.kt 파일을 만들고 다음과 같이 작성하자.
fun main(args: Array<String>) {
val numbers = mutableListOf("one", "two", "three", "four", "five")
println("------ 01. 일반 예제 ------")
// 2가지 이상의 오퍼레이션이 존재하는 일반 예제
val resultList = numbers.map { it.length }.filter { it > 3 }
println(resultList)
println("------- 02. let 이용 ------")
// let을 이용하여 오퍼레이션 묶어주기 (it로 참조함을 확인하자)
numbers.map { it.length }.filter { it > 3 }.let {
println(it)
}
println("------- 03. let + 함수 레퍼런스 이용 ------")
// 다음과 같이 함수 참조를 이용할수도 있다. (::를 이용하여 함수 참조흘 한다.)
numbers.map { it.length }.filter { it > 3 }.let( ::println )
}일반적인 예제는 map, filter 를 이용하여 결과 리스트를 생성한 후 내용을 출력한다.
let 범위 함수를 이용하면, 처리 결과를 let 함수로 묶어서 처리할 수 있다. 즉, 출력 이외에 여러 처리를 let에서 수행할 수 있다.
let 범위 함수에서는 함수 레퍼런스를 이용하여 처리 결과를 출력할 수 있다.
결과는 다음과 같다.
------ 01. 일반 예제 ------
[5, 4, 4]
------- 02. let 이용 ------
[5, 4, 4]
------- 03. let + 함수 레퍼런스 이용 ------
[5, 4, 4]let은 람다 실행 결과를 반환한다.
그리고 it 대신에 아규먼트 함수를 직접 지정해서 프로세스 처리를 수행할 수도 있다.
02.let_sample.kt 파일을 만들고 다음과 같이 수행할 수 있다.
fun main(args: Array<String>) {
val numbers = listOf("one", "two", "three", "four", "five")
val modifiedFirstItem = numbers.first().let {
firstItem ->
println("The first item of the list is '$firstItem'")
if (firstItem.length >= 5) firstItem else "!" + firstItem + "!"
}.uppercase()
println("First item after modifications: '$modifiedFirstItem'")
}위와 같이 리스트의 첫번째 아이템을 획득한 후, let 범위함수를 사용하여, 길이가 5 이상인 경우와 그렇지 않은 경우를 확인하여 내용을 변경한다.
최종적으로 대문자로 변경한 결과를 modifiedFirstItem 에 담고 출력한다.
그리고 내부적으로 it 대신에 firstItem이라고 아규먼트 참조 이름을 변경하였다.
처리결과는 다음과 같다.
The first item of the list is 'one'
First item after modifications: '!ONE!'let 사용방법에 대해서 알아 보았다.
let은 리시버 참조를 it를 통해 수행한다.
그리고 결과 반환은 람다 처리 결과를 반환함을 확인할 수 있었다.
run 범위함수는 다음과 같은 특성을 가진다.
컨텍스트 객체 참조를 위해서 this를 사용한다.
결과 값으로 lambda 결과를 반환한다.
run은 with와 동일하지만 차이점은 확장함수로 구혀되어 있다는 것이다.
let과 같이 dot노테이션을 이용하여 컨텍스트 객체를 호출할 수 있고 효과는 run과 같다.
run 은 값을 초기화 하고 결과를 계산하여 반환할때 유용하게 사용된다.
01_run_sample.kt 파일을 생성하고 다음과 같이 코드를 작성하자.
class MultiportService(var url: String, var port: Int) {
fun prepareRequest(): String = "Default request"
fun query(request: String): String = "Result for query '$request'"
}
fun main() {
val service = MultiportService("https://example.kotlinlang.org", 80)
// run을 이용하여 람다 처리 결과를 반환한다.
// service에 직접 run을 쓸수 있으므로 확장함수이다.
val result = service.run {
port = 8080
query(prepareRequest() + " to port $port")
}
// let 함수를 이용하여 동일한 결과를 출력한다.
val letResult = service.let {
it.port = 8080
it.query(it.prepareRequest() + " to port ${it.port}")
}
println(result)
println(letResult)
}위와 같이 service 라는 변수에 객체를 담고, 이를 확장한 run 범위함수를 수행했다.
let을 이용할때에는 it. 을 통해서 컨텍스트 객체에 참조하고 있음을 확인할 수 있다.
결과는 다음과 같다.
Result for query 'Default request to port 8080'
Result for query 'Default request to port 8080'run을 확장함수가 아닌 방식으로 사용할수도 있다.
다만 이때에는 컨택스트 객체를 참조할 수 없다. 그러나 여전히 lambda 결과를 반환할수는 있다.
02.run_sample.kt 파일을 생성하고 다음과 같이 작성하자.
fun main() {
// run을 객체 확장으로 사용하지 않은 케이스
// 람다 결과를 반환하여 hexNumberRegex 변수에 담는다.
val hexNumberRegex = run {
val digits = "0-9"
val hexDigits = "A-Fa-f"
val sign = "+-"
Regex("[$sign]?[$digits$hexDigits]+")
}
for (match in hexNumberRegex.findAll("+123 -FFFF !%*& 88 XYZ")) {
println(match.value)
}
}위 예제는 객체 확장이 아닌 방식으로 run을 사용한 예제이고, lambda 실행 결과를 반환한다.
입력된 문자열에서 regex에 매치되는 대상을 찾아서 출력한다.
실행결과
+123
-FFFF
88run 범위 함수를 이용한 샘플을 확인해 보았다.
run은 확장함수로 사용하거나, 확장없이 사용할수도 있다.
또한 컨텍스트 객체 참조를 this로 수행할 수 있으며, 람다 결과를 반환하는 것도 알아 보았다.
with 범위 함수는 다음과 같은 특성을 가진다.
context 객체 참조를 this를 통해 수행한다.
결과는 lambda 결과를 반환한다.
with 는 확장 함수가 아니다. 컨텍스트 객체를 아규먼트로 전달하며, 내부에는 lambda를 수행하게 된다. 리시버는 this를 통해서 참조가 가능하다.
01.with_sample.kt 파일을 만들고 다음과 같이 작성한다.
fun main(args: Array<String>) {
val numbers = mutableListOf("one", "two", "three")
println("------ 01.with는 this를 이용하여 컨텍스트 객체를 참조한다. . -----")
with(numbers) {
println("'with' 는 아규먼트를 this를 통해 참조할 수 있다. $this")
println("다음과 같이 $size 엘리먼트 개수를 가진다.")
}
println("------ 02.with 값 계산을 위해 참조 객체의 속성과 함수를 그대로 사용할수도 있다. -----")
val firstAndLast = with(numbers) {
"The first element is ${first()}"
" the last element is ${last()}"
}
println(firstAndLast)
}우선 with는 this를 이용하여 컨텍스트 객체를 참조한다.
하여 $this는 numbers 객체 자체를 참조한다.
그리고 내부적으로는 함수, 속성을 바로 사용할수도 있다.
처리결과는 다음과 같다.
------ 01.with는 this를 이용하여 컨텍스트 객체를 참조한다. . -----
'with' 는 아규먼트를 this를 통해 참조할 수 있다. [one, two, three]
다음과 같이 3 엘리먼트 개수를 가진다.
------ 02.with 값 계산을 위해 참조 객체의 속성과 함수를 그대로 사용할수도 있다. -----
the last element is three위 결과와 같이 with는 컨텍스트 객체를 this를 이용하여 참조할 수 있다.
또한 처리 결과 반환은 lambda 처리 결과를 반환함을 알 수 있다.
apply 범위함수 특징은 다음과 같다.
context 객체 참조는 this로 수행한다.
객체 자체를 결과로 반환한다.
apply는 객체 자체를 반환한다.
일반적인 케이스로 객체 초기화를 수행해야하는 경우에 주로 이용된다.
01.apply_sample.kt 파일을 생성하고 다음 코드를 작성하자.
data class Person(var name: String, var age: Int = 0, var city: String = "")
fun main() {
val adam = Person("Adam").apply {
age = 32
city = "London"
}
println(adam)
val james = Person("James").apply {
age = 40
city = "Paris"
}.apply {
println(this)
}
}위와 같이 Person 데이터 객체를 생성했고, 이름값만 초기화 하고 나머지는 기본값을 이용했다.
apply 범위 함수를 이용하여 초기화 값을 사용하였고, 처리 결과 adam 변수에 반환된 참조 객체 그대로 할당했다.
결과를 출력하는 코드를 작성했다.
처리 결과는 다음과 같다.
Person(name=Adam, age=32, city=London)
Person(name=James, age=40, city=Paris)즉 변경된 Person 객체를 확인할 수 있다.
apply는 참조객체 자체를 반환하므로 콜 체인을 걸 수 있다. 두번째 james 의 경우 콜 체인을 통해서 값을 초기화 하고, 결과를 출력했다.
apply를 통해서 참조 객체를 초기화 하고 콜체인을 수행해서 결과를 출력해 보았다.
apply는 this를 통해서 컨텍스트 객체를 참조할 수 있고, 객체 자체를 반환하는 것을 확인했다.
also 범위함수 특징은 다음과 같다.
context 객체는 it를 통해서 참조할 수 있다.
객체 자체를 반환한다.
also는 컨텍스트 개체를 인수로 사용하는 일부 작업을 수행하는데 유용하다.
속성 및 기능이 아닌 객체에 대한 참조가 필요한 작업이나 외부 범위에서 이 참조를 숨기고 싶지 않은 경우에 사용하자.
코드에서도 보면 "그리고 객체로 다음도 수행한다" 라고 읽을 수 있다.
01.also_sample.kt 파일을 생성하고 다음과 같이 작성하자.
fun main() {
val numbers = mutableListOf("one", "two", "three")
numbers
.also { println("The list elements before adding new one: $it") }
.add("four")
println(numbers)
}위와 같이 numbers 변수를 생성하고 다음에 내용을 출력하고, 새로운 값을 추가했다.
처리 결과는 다음과 같다.
The list elements before adding new one: [one, two, three]
[one, two, three, four]also는 특정 작업을 수행하고, 또한 다음 처리를 수행한다라고 해석되는 작업을 수행할때 유용하다.
객체 참조는 it를 통해 수행하고, 반환값을 객체 자체로 수행할 수 있음을 알 수 있다.
takeIf
특정 조건을 만족하는 경우 객체를 반환한다.
긍정로직을 수행하는 경우이다.
takeUnless
특정 조건을 만족하지 않은 경우 객체를 반환하며, 만족하는 경우 null을 반환한다.
부정로직을 수행하는 경우이다.
객체 참조를 위해서 it를 사용한다.
01.takeIf_sample.kt 파일을 생성하고 다음과 같이 작성하자.
import kotlin.random.*
fun main() {
val number = Random.nextInt(100)
val evenOrNull = number.takeIf { it % 2 == 0 }
val oddOrNull = number.takeUnless { it % 2 == 0 }
println("even: $evenOrNull, odd: $oddOrNull")
}위와 같이 eventOrNull은 짝수인경우 값을 받아 들인다.
oddOrNull은 홀수인경우 값을 받아 들이게 된다. 아닌 경우 널값이 할당된다.
몇번 출력을 해보면 다으므 결과를 얻을 수 있다.
even: null, odd: 49
even: 48, odd: null
even: null, odd: 1참고할 것은 takeIf와 takeUnless는 조건에 만족하지 않은경우 null을 반환한다. 그러므로 ?. 를 이용하여 널에 안전하도록 코드를 작성하자.
02.takeIf_sample.kt 를 만들고 다음과 같이 작성하자.
fun main() {
val str = "Hello"
val caps = str.takeIf { it.isNotEmpty() }?.uppercase()
//val caps = str.takeIf { it.isNotEmpty() }.uppercase() //compilation error
println(caps)
}위 코드는 널에 대해서 안전하다.
결과는 다음과 같다.
HELLOtakeIf, takeUnless 를 이용하여 특정 조건에 맞는 결과만 추출할 수 있다.
아닌경우 널이 반환되므로 널 안전하게 ?. 를 이용해야 한다는 것도 이해할 수 있었다.
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.