Kotlin/이해하기
[Kotlin] Kotlin 기본 문법 이해하기 -4 : 함수, 파라미터, 스코프 함수
adjh54
2024. 11. 23. 15:36
반응형
해당 글에서는 Kotlin의 기본 문법 중 함수, 파라미터, 스코프 함수에 대해 알아봅니다.
💡 [참고] Kotlin의 문법들에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
주제 | 링크 |
Kotlin 기본 문법 이해하기 -1 : 주요 특징 및 문법 이해(변수 및 데이터 타입, 캐스팅, Null) | https://adjh54.tistory.com/607 |
Kotlin 기본 문법 이해하기 -2 : Control flow (조건식, RANGE, 반복문) | https://adjh54.tistory.com/608 |
Kotlin 기본 문법 이해하기 -3 : 클래스, 인터페이스, 구현체 | https://adjh54.tistory.com/609 |
Kotlin 기본 문법 이해하기 -4 : 함수, 파라미터, 스코프 함수 | https://adjh54.tistory.com/610 |
1) Kotlin function
💡 Kotlin function
- Kotlin의 함수(function)는 코드의 재사용성과 모듈화를 위한 핵심 요소입니다.
1. 함수 선언(Function declaration)
💡 함수 선언(Function declaration)
- Kotlin에서 일반적인 함수는 ‘fun’ 키워드로 선언합니다. 해당 함수에서는 파라미터를 정의하고 리턴 타입을 정의합니다.
요소 | 설명 |
fun | 함수임을 선언하는 키워드 |
functionName | 함수의 이름 |
parameter1, parameter2, ... | 함수의 매개변수들 (옵션) |
Type1, Type2, ... | 매개변수들의 타입 |
ReturnType | 함수의 반환 타입 (생략 가능, 생략 시 Unit으로 간주) |
return | 함수의 결과를 반환하는 키워드 (ReturnType이 Unit이 아닌 경우 필요) |
fun functionName(parameter1: Type1, parameter2: Type2, ...): ReturnType {
// 함수 본문
return result
}
💡 함수 선언(Function declaration) 예시
- normalFun 함수 이름을 지정하고, parameter1: String, parameter2: Int 파라미터로 지정하였고, 리턴타입을 String으로 지정하였습니다. 그리고 비즈니스 로직 처리는 함수 본문에서 구현합니다.
/**
* 일반 함수 구조 : 파라미터, 리턴타입 정의
*/
fun normalFun(parameter1: String, parameter2: Int): String {
// 함수 본문
val result = parameter1 + parameter2
return result
}
2. 단일 표현식 함수(Single Expression Functions)
💡 단일 표현식 함수(Single Expression Functions)
- 함수 본문이 단일 표현식인 경우, 중괄호와 return 문을 생략할 수 있습니다
/**
* 단일 함수 구조
*/
fun singleFun(x: Int): Int = x * 2
3. 확장 함수(Extension Functions)
💡 확장 함수(Extension Functions)
- 기존 클래스에 새로운 함수를 추가할 수 있습니다.
- 아래의 예와 같이 String 클래스 내에 addExclamation()을 추가합니다.
- 이를 통해서 원본 클래스의 소스 코드를 수정하지 않고 클래스에 새로운 기능을 추가할 수 있습니다.
/**
* 확장 함수 구조
*/
private fun String.addExclamation() = "$this!"
/**
* 확장 함수 호출 : String 클래스를 확장하여 addExclamation를 추가하였습니다. 이에 대해 호출을 하여 기존의 클래스에 함수를 추가합니다.
*/
fun extensionFunCall() {
val str = "Hello"
println(str.addExclamation()) // 출력: Hello!
}
[더 알아보기]
💡 확장 함수의 경우는 확장 범위가 클래스 내인가 아니면 전역인가?
- 확장 함수의 범위는 기본적으로 전역(global)입니다. 다시 말해, 확장 함수는 클래스 내부가 아닌 파일의 최상위 레벨에서 정의됩니다.
- 확장 함수는 해당 함수가 정의된 파일 내에서 어디서든 사용할 수 있습니다. 다른 파일에서도 해당 확장 함수를 import 하여 사용할 수 있습니다.
4. 고차 함수(Higher-Order Functions)
💡 고차 함수(Higher-Order Functions)
- 함수를 인자로 받거나 함수를 반환하는 함수를 정의할 수 있습니다. 이를 통해서 프로그래밍의 유연성과 재사용성을 크게 향상시킵니다.
/**
* 고차함수 구조
*/
fun higherOrderFun(x: Int, y: Int, op: (Int, Int) -> Int): Int = op(x, y)
/**
* 고차함수 호출 : 함수 파라미터
*/
fun higherOrderFunCall() {
// 덧셈 연산
val sum = higherOrderFun(5, 3) { a, b -> a + b }
println(sum) // 출력: 8
// 곱셈 연산
val product = higherOrderFun(5, 3) { a, b -> a * b }
println(product) // 출력: 15
}
5. 인라인 함수(Inline Functions)
💡 인라인 함수(Inline Functions)
- Kotlin의 인라인 함수는 성능 최적화를 위해 사용되는 특별한 종류의 함수입니다.
특징 | 설명 |
선언 방법 | 'inline' 키워드를 사용하여 선언 |
컴파일 시 동작 | 함수 호출 부분에 함수의 본문 코드가 직접 삽입됨 |
주요 사용 목적 | 고차 함수에서 람다 표현식의 오버헤드를 줄이기 위해 사용 |
성능 영향 | 적절히 사용 시 성능 향상, 과도한 사용 시 코드 크기 증가 |
적합한 상황 | 작은 크기의 유틸리티 함수, 반복적으로 호출되는 간단한 연산 |
주의사항 | 복잡하거나 큰 함수에는 부적합, 코드 크기 증가 가능성 |
💡 [참고] inline 함수의 주의사항
주의 사항 | 설명 |
코드 크기 | 모든 함수를 인라인으로 만들면 코드 크기가 불필요하게 커질 수 있습니다. |
성능 영향 | 복잡하거나 큰 함수를 인라인으로 만들면 오히려 성능이 저하될 수 있습니다. |
사용 권장 | 적절한 상황에서만 인라인 함수를 사용하는 것이 좋습니다. |
💡 사용예시
- 기존의 고차함수에 인라인 함수로 변경하였습니다.
1. 성능 최적화: 인라인 함수는 컴파일 시 함수 호출 부분에 함수의 본문 코드가 직접 삽입됩니다. 이로 인해 함수 호출에 따른 오버헤드가 줄어들어 성능이 향상될 수 있습니다.
2. 람다 표현식 오버헤드 감소: 특히 고차 함수에서 람다 표현식을 사용할 때 발생할 수 있는 오버헤드를 줄이는 데 효과적입니다.
3. 코드 최적화: 작은 크기의 유틸리티 함수나 반복적으로 호출되는 간단한 연산에 적합합니다.
@Component
class FunctionComponent {
/**
* 인라인 고차함수 구조
*/
private inline fun inlineHigherOrderFun(x: Int, y: Int, op: (Int, Int) -> Int): Int = op(x, y)
/**
* 인라인 고차함수 호출 : 함수 파라미터
*/
fun inlineHigherOrderFunCall() {
// 덧셈 연산
val sum = higherOrderFun(5, 3) { a, b -> a + b }
println(sum) // 출력: 8
// 곱셈 연산
val product = higherOrderFun(5, 3) { a, b -> a * b }
println(product) // 출력: 15
}
}
6. 연산자 함수(operator fun)
💡 연산자 함수(operator fun)
- Kotlin에서 연산자 오버로딩을 구현하기 위해 사용되는 특별한 함수입니다.
- fun 키워드 앞에 operator 키워드를 사용하여 선언하며 기존 연산자(+, -, *, / 등)의 동작을 사용자 정의 클래스에 맞게 재정의할 수 있습니다.
💡 operator fun 연산자의 오버로딩 함수
주요 연산자 함수 | 설명 |
plus() | + 연산자 |
minus() | - 연산자 |
times() | * 연산자 |
div() | / 연산자 |
get() | [] 인덱스 연산자 |
inc() | ++ 증가 연산자 |
dec() | -- 감소 연산자 |
class Point(var x: Int, var y: Int) {
// + 연산자 오버로딩
operator fun plus(other: Point): Point {
return Point(x + other.x, y + other.y)
}
// - 연산자 오버로딩
operator fun minus(other: Point): Point {
return Point(x - other.x, y - other.y)
}
}
fun main() {
val p1 = Point(10, 20)
val p2 = Point(30, 40)
// 연산자 사용
val sum = p1 + p2 // plus() 함수 호출
val diff = p1 - p2 // minus() 함수 호출
println("sum: (${sum.x}, ${sum.y})") // 출력: sum: (40, 60)
println("diff: (${diff.x}, ${diff.y})") // 출력: diff: (-20, -20)
}
7. suspend fun
💡 suspend fun
- Kotlin의 코루틴에서 사용되는 특별한 함수입니다.
- 비동기 작업을 처리하기 위해 사용되며, 코루틴 내부에서만 호출할 수 있습니다.
💡[참고] 해당 작업은 코루틴 메서드를 사용하기에 아래의 라이브러리를 추가해야 합니다.
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
💡 사용예시
- 해당 예시에서는 코루틴을 활용하여 비동기 처리를 하는 메서드를 구성하였습니다.
1. fetchUserData(): suspend 함수로, User 객체를 반환하기 전에 1초간 대기하는 비동기 작업을 수행합니다.
2. main(): runBlocking을 사용하여 코루틴 스코프 내에서 suspend 함수를 호출하는 예시를 보여줍니다.
package com.blog.kotlinspringbootform.component.functionType
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
/**
* Please explain the class!!
*
* @fileName : FunSuspend
* @author : jonghoon
* @since : 11/23/24
*/
class FunSuspend {
// suspend 함수 예시
private suspend fun fetchUserData(): User {
delay(1000) // 1초 대기
return User("John", 25)
}
// 코루틴 내에서 suspend 함수 사용
fun main() = runBlocking {
val user = fetchUserData() // suspend 함수 호출
println(user)
}
data class User(
val name: String,
val age: Int
)
}
8. 꼬리 재귀함수(tailrec fun)
💡 꼬리 재귀함수(tailrec fun)
- 꼬리 재귀 최적화를 위한 특별 함수를 의미합니다.
- 재귀 호출 함수를 구성하며, 스택 오버플로우를 발생하지 않도록 컴파일러가 최적화를 수행합니다.
package com.blog.kotlinspringbootform.component.functionType
/**
* Tailrec 함수 사용 예시
*
* @fileName : FunTailrec
* @author : jonghoon
* @since : 11/23/24
*/
class FunTailrec {
// 일반적인 재귀 함수
tailrec fun factorial(n: Long, accumulator: Long = 1): Long {
return when (n) {
0L -> accumulator
else -> factorial(n - 1, n * accumulator)
}
}
fun main() {
println(factorial(5)) // 출력: 120
}
}
9. 중위표기 함수(infix fun)
💡 중위표기 함수(infix fun)
- 중위 표기법을 사용할 수 있게 해주는 특별한 함수입니다.
- 두 개의 값 사이에 함수 이름을 위치시켜 더 자연스러운 문법을 제공합니다.
class MyNumber(val value: Int) {
infix fun add(other: MyNumber): MyNumber {
return MyNumber(this.value + other.value)
}
}
fun main() {
val num1 = MyNumber(10)
val num2 = MyNumber(20)
// 일반적인 호출
val result1 = num1.add(num2)
// 중위 표기법 사용
val result2 = num1 add num2
println(result2.value) // 출력: 30
}
[ 더 알아보기 ]
💡 중위 표기법(Infix Notation)
- 일반적인 함수 호출 방식인 obj.function(param) 대신 obj function param 형태로 함수를 호출할 수 있게 해주는 표기법입니다.
- 더 자연스럽고 읽기 쉬운 코드를 작성할 수 있게 해 줍니다.
- 주로 두 객체 간의 연산이나 관계를 표현할 때 사용됩니다.
반응형
2) Kotlin Paramerter
1. 기본 매개변수(Paramerter)
💡 기본 매개변수(Paramerter)
- 함수 내에서 기본적으로 파라미터 타입에 대해서만 지정하며, default 값을 지정한 파라미터를 지정합니다.
/**
* 일반적인 타입을 지정한 파라미터
*/
fun normalParam(name: String): String {
return "hello $name"
}
/**
* default 값을 가지는 파라미터
*/
fun defaultParam(name: String = "lee"): String {
return "hello $name"
}
2. 선택적 매개변수(Optional Parameter)
💡 선택적 매개변수(Optional Parameter)
- 함수 호출 시 생략할 수 있는 매개변수를 의미합니다.
- Kotlin에서는 매개변수에 물음표(?)를 붙여 nullable 타입으로 선언하여 구현합니다.
/**
* optional 파라미터를 사용한 함수
*/
private fun optionalParam(name: String, age: Int?) {
if (age != null) {
println("$name is $age years old")
} else {
println("$name's age is unknown")
}
}
fun optionalParamCall() {
optionalParam("John", 25) // age 값 제공
optionalParam("Jane", null) // age 값을 null로 제공
}
3. 가변 인자 (Vararg Parameter)
💡 가변 인자 (Vararg Parameter)
- 함수 내에 파라미터에 vararg 키워드를 사용하여 가변 개수의 인자를 받는 함수를 정의합니다.
1. 타입: vararg 키워드 뒤에 지정된 타입으로 제한됩니다. 예를 들어, 'vararg numbers: Int'는 정수형 인자만 받을 수 있습니다.
2. 개수: 가변 인자 함수는 0개 이상의 인자를 받을 수 있습니다. 즉, 인자를 전혀 전달하지 않거나, 하나 또는 여러 개의 인자를 전달할 수 있습니다.
/**
* vararg 파라미터를 이용하여 가변 인자 함수
*/
private fun varargSumParam(vararg numbers: Int): Int = numbers.sum()
/**
* vararg 파라미터를 이용하여 가변 인자 함수 호출
*/
fun varargParamCall() {
varargSumParam() // 인자 없이 호출 가능
varargSumParam(1) // 단일 인자
varargSumParam(1, 2, 3) // 여러 인자
varargSumParam(*intArrayOf(1, 2, 3)) // 배열을 전개 연산자(*)와 함께 사용
}
3) Scope Function
💡 Scope Function
- Kotlin에서 객체의 컨텍스트 내에서 코드 블록을 실행할 수 있게 해주는 특별한 함수들입니다
함수 명 | Object reference | Return value | 설명 |
let | it | Lambda result | 객체를 이용해 작업을 수행하고 ‘결과를 반환’합니다. null 체크에 유용합니다. |
run | this | Lambda result | 객체 ‘초기화’와 반환 값의 ‘계산’을 동시에 수행합니다. |
with | this | Lambda result | 객체에 대해 여러 작업을 그룹화합니다. 수신자 객체를 매개변수로 받습니다. |
apply | this | Context object | 객체 구성에 사용되며, 객체 자체를 반환합니다. |
also | it | Context object | 객체에 대한 ‘추가 작업’을 수행하며, ‘객체 자체를 반환’합니다. |
[ 더 알아보기 ]
💡 객체의 컨텍스트
- 특정 객체의 범위 또는 환경을 의미합니다.
- 예를 들어서, ‘let’ 함수를 사용할 때, 객체의 컨텍스트 내에서 ‘it’ 키워드를 통해 해당 객체에 접근할 수 있습니다.
- 이를 객체의 컨텍스트 내에서 작업을 수행하는 것을 의미합니다.
fun main() {
val person = Person("Alice", 30)
// let을 사용한 예시
person.let {
println("Name: ${it.name}, Age: ${it.age}")
it.age += 1
}
}
1. let
💡 let
- 객체를 이용해 ‘작업을 수행하고 결과를 반환’합니다. null 체크에 유용합니다.
- 주로 nullable 객체를 다룰 때 사용되며, 람다 내에서 객체를 'it'으로 참조합니다.
💡 let 함수 기본 구조
1. 'object'는 let 함수를 호출하는 객체입니다.
2. 'it'은 람다 내에서 객체를 참조하는 데 사용되는 기본 이름입니다. 원하는 경우 다른 이름으로 변경할 수 있습니다.
3. 람다 블록 내에서 객체를 사용하여 작업을 수행합니다.
4. 람다의 마지막 표현식이 let 함수의 반환값이 됩니다.
val result = object.let { it ->
// 객체를 사용한 코드 블록
// 'it'은 객체를 참조
// 마지막 표현식이 반환값
}
💡 let 함수를 이용한 예시
- Person이라는 데이터 클래스를 이용하여 작업을 수행하고 결과를 반환합니다.
1. 객체 내에서 let을 이용하여 변수를 처리하는 예시
- 해당 예시에서는 객체 (Person)이라는 값을 접근하여 멤버 변수인 name, age를 접근합니다. 이 접근한 변수를 변환하고 반환하는 처리를 수행합니다.
2. 객체 내에서 let을 이용하여 변수의 null 처리를 하는 예시
- nullablePerson이라는 변수가 null 인지 아닌지에 대한 체크를 수행하고 각각에 맞는 결과값을 반환하는 예시입니다.
3. 리스트 내에서 문자열 길이에 따라 필터링하여 값을 반환받는 예시
- 리스트를 초기화하고, 리스트를 순회하며 길이가 3 초과인 문자열을 반환하는 함수예시입니다.
/**
* let 함수를 이용한 예시
*/
fun letScopeFun() {
val person: Person = Person("홍길동", 30)
// [사용예시-1] 객체 내에서 let을 이용하여 변수를 처리하는 예시
person.let {
println("이름: ${it.name}")
println("나이: ${it.age}")
it.age += 1 // 객체 내 변수의 값을 변환하여 반환합니다.
println("1년 후 나이: ${it.age}")
}
// [사용예시-2] 객체 내에서 let을 이용하여 변수의 null 처리를 하는 예시
val nullablePerson: Person? = null
val result = nullablePerson?.let { "${it.name}은(는) ${it.age}살입니다." } ?: "Person 객체가 null입니다."
println(result) // null 인 경우 => Person 객체가 null입니다. / null이 아닌 경우 => 홍길동은(는) 30살입니다.
// [사용예시-3] 리스트 내에서 let 함수를 이용하여 필터링하여 값을 반환받는 예시 : 문자 길이가 3초과값 반환
val numbers = mutableListOf("one", "two", "three", "four", "five")
val resultList = numbers.map { it.length }.filter { it > 3 }
println(resultList) // "three"(5), "four"(4), "five"(4)의 길이가 선택되어 [4, 5, 5]가 출력
}
2. run
💡 run
- 객체 ‘초기화’와 반환 값의 ‘계산’을 동시에 수행합니다.
- 객체의 멤버 함수나 속성을 여러 번 호출할 때 유용하며, 'this'를 생략할 수 있습니다.
💡 run 함수 기본 구조
1. 확장 함수로서의 run
- 객체의 컨텍스트 내에서 코드를 실행하며, 'this'를 사용하여 객체를 참조할 수 있습니다.'this'는 생략 가능하며, 람다의 마지막 표현식이 run 함수의 반환값이 됩니다.
2. 독립 실행 함수로서의 run
- 특정 객체의 컨텍스트 없이 코드 블록을 실행합니다. 마찬가지로 람다의 마지막 표현식이 run 함수의 반환값이 됩니다.
- 두 경우 모두 run 함수는 코드 블록을 실행하고 그 결과를 반환한다는 공통점이 있습니다.
- 주요 차이점은 첫 번째 형태가 특정 객체의 컨텍스트 내에서 작동하는 반면, 두 번째 형태는 독립적인 코드 블록으로 작동한다는 것입니다.
// 1. 확장 함수로서의 run
object.run {
// 객체의 컨텍스트 내에서 코드 실행
// 'this'로 객체 참조 (생략 가능)
// 마지막 표현식이 반환값
}
// 2. 독립 실행 함수로서의 run
run {
// 코드 블록 실행
// 객체 컨텍스트 없음
// 마지막 표현식이 반환값
}
💡 run 함수를 이용한 예시
1. 객체 초기화와 계산을 동시에 수행하는 예시
- Person 객체를 생성하고 초기화하면서 동시에 문자열을 반환합니다.
2. 객체의 멤버 함수를 여러 번 호출하는 예시
-StringBuilder 객체를 사용하여 여러 작업을 수행하고 결과를 반환합니다.
package com.blog.kotlinspringbootform.component
import org.springframework.stereotype.Component
data class Person(var name: String, var age: Int)
/**
* 범위 함수의 사용예시를 관리하는 컴포넌트
*/
@Component
class ScopeFunctionComponent {
/**
* run 함수를 이용한 예시
*/
fun runScopeFun() {
// 1. 객체 초기화와 계산을 동시에 수행
val result = run {
val person = Person("홍길동", 30) // 객체 초기화
person.age += 1 // 객체 반환값 계산
"${person.name}은(는) ${person.age}살입니다." // run 함수 반환 값
}
println(result) // 출력: 홍길동은(는) 31살입니다.
// 2. 객체의 멤버 함수를 여러 번 호출
val stringBuilder = StringBuilder() // 객체 초기화
val length = stringBuilder.run {
append("Hello") // 객체 반환값 계산
append(" ") // 객체 반환값 계산
append("World") // 객체 반환값 계산
length // run 함수 반환 값
}
println(stringBuilder.toString()) // 출력: Hello World
println("길이: $length") // 출력: 길이: 11
}
}
3. with
💡 with
- 객체에 대해 여러 작업을 그룹화합니다. 수신자 객체를 매개변수로 받습니다.
- 특정 객체에 대해 여러 작업을 수행할 때 사용되며, 람다 내에서 'this'를 생략할 수 있습니다.
💡 with 함수 기본 구조
- 'with' 함수는 수신 객체를 첫 번째 인자로 받고, 두 번째 인자로 람다 함수를 받습니다.
- 람다 함수 내에서 수신 객체의 멤버에 직접 접근할 수 있으며, 'this'를 생략할 수 있습니다.
- 람다의 마지막 표현식이 with 함수의 반환값이 됩니다.
val result = with(object) {
// 객체의 속성이나 함수를 직접 사용
// 'this'는 생략 가능
// 마지막 표현식이 반환값
}
💡 with 함수를 이용한 예시
1. 객체의 여러 속성을 한 번에 설정하는 예시
- Person 객체의 여러 속성을 설정하고 문자열을 반환합니다.
2. 복잡한 계산을 수행하는 예시
- StringBuilder를 사용하여 문자열을 구성하고 그 결과를 반환합니다.
package com.blog.kotlinspringbootform.component
import org.springframework.stereotype.Component
data class Person(var name: String, var age: Int)
/**
* 범위 함수의 사용예시를 관리하는 컴포넌트
*/
@Component
class ScopeFunctionComponent {
fun withScopeFun() {
val person = Person("홍길동", 30)
// 1. 객체의 여러 속성을 한 번에 설정
val result = with(person) {
name = "김철수"
age = 25
"이름: $name, 나이: $age"
}
println(result) // 출력: 이름: 김철수, 나이: 25
// 2. 복잡한 계산을 수행
val numbers = listOf(1, 2, 3, 4, 5)
val sum = with(numbers) {
val doubledNumbers = map { it * 2 }
doubledNumbers.sum()
}
println("합계: $sum") // 출력: 합계: 30
}
}
4. apply
💡 apply
- 객체 구성에 사용되며, 객체 자체를 반환합니다.
- 주로 객체 초기화에 사용되며, 람다의 결과가 아닌 객체 자체를 반환합니다.
💡 apply 함수 기본 구조
- 'apply' 함수는 수신 객체 지정 람다의 한 형태입니다.
- 객체를 구성하고 그 객체를 반환합니다. 람다 내에서 수신 객체의 멤버에 직접 접근할 수 있으며, 'this'를 생략할 수 있습니다.
- 람다의 결과와 관계없이 항상 수신 객체 자체를 반환합니다.
val object = SomeClass().apply {
// 객체의 속성이나 함수를 직접 사용
// 'this'는 생략 가능
// 객체 자체가 반환됨
}
💡 apply 함수를 이용한 예시
1. 객체 초기화 예시
- Person 객체를 생성하고 속성을 설정한 후 그 객체를 반환합니다.
2. 복잡한 객체 구성 예시
- StringBuilder를 사용하여 문자열을 구성하고 그 객체를 반환합니다.
package com.blog.kotlinspringbootform.component
import org.springframework.stereotype.Component
data class Person(var name: String, var age: Int)
/**
* 범위 함수의 사용예시를 관리하는 컴포넌트
*/
@Component
class ScopeFunctionComponent {
/**
* apply 함수를 이용한 예시
*/
fun applyScopeFun() {
// 1. 객체 초기화
val person = Person("홍길동", 30).apply {
name = "김철수"
age = 25
}
println("이름: ${person.name}, 나이: ${person.age}") // 출력: 이름: 김철수, 나이: 25
// 2. 복잡한 객체 구성
val stringBuilder = StringBuilder().apply {
append("Hello")
append(" ")
append("World")
insert(0, "Greeting: ")
}
println(stringBuilder.toString()) // 출력: Greeting: Hello World
}
}
5. also
💡 also
- 객체에 대한 추가 작업을 수행하며, 객체 자체를 반환합니다.
- 객체의 속성을 변경하지 않고 부가적인 작업을 수행할 때 유용합니다.
- 특히나 디버깅이나 로깅 목적으로 자주 사용됩니다.
💡 also 함수 기본 구조
- 'also' 함수는 수신 객체 지정 람다의 한 형태입니다. 객체를 받아 부가적인 작업을 수행하고, 그 객체를 그대로 반환합니다.
- 람다 내에서 수신 객체는 'it'으로 참조됩니다.
- 주로 객체의 상태를 변경하지 않는 부가적인 작업(로깅, 유효성 검사 등)에 사용됩니다.
val object = SomeClass().also {
// 객체에 대한 부가적인 작업 수행
// 'it'을 통해 객체 참조
// 객체 자체가 반환됨
}
💡 also 함수를 이용한 예시
1. 객체 초기화 후 로깅 예시
- Person 객체를 생성하고 초기화한 후, 객체의 상태를 로그로 출력합니다.
2. 컬렉션 처리 예시
리스트를 생성하고 정렬한 후, 정렬된 상태를 출력합니다.
package com.blog.kotlinspringbootform.component
import org.springframework.stereotype.Component
data class Person(var name: String, var age: Int)
/**
* 범위 함수의 사용예시를 관리하는 컴포넌트
*/
@Component
class ScopeFunctionComponent {
/**
* also 함수를 이용한 예시
*/
fun alsoScopeFun() {
// 1. 객체 초기화 후 로깅
val person = Person("홍길동", 30).also {
println("생성된 Person 객체: 이름=${it.name}, 나이=${it.age}")
}
// 2. 컬렉션 처리
val numbers = mutableListOf(3, 1, 4, 1, 5, 9).also {
it.sort()
println("정렬된 리스트: $it")
}
println("Person 객체: $person")
println("Numbers: $numbers")
}
}
4) Kotlin 해당 글 주요 요약
주제 | 설명 | 주요 내용 |
함수 선언 | fun 키워드로 선언 | - fun: 함수 선언 키워드 - functionName: 함수 이름 - parameter: 매개변수 - ReturnType: 반환 타입 |
함수 종류 | 기본 함수 유형 | - 단일 표현식 함수 - 기본 매개변수 - 가변 인자 함수 - 지역 함수 - 확장 함수 |
스코프 함수 | 객체의 컨텍스트 내에서 코드 실행 | - let: null 체크, 지역변수 제한 - run: 객체 구성과 계산 - with: 그룹화된 작업 - apply: 객체 초기화 - also: 부가 작업, 로깅 |
객체 참조 방식 | 스코프 함수에서 객체 참조 | - this 사용: run, with, apply - it 사용: let, also |
반환값 특성 | 스코프 함수의 반환 | - 람다 결과 반환: let, run, with - 객체 자신 반환: apply, also |
사용 목적 | 각 함수의 주요 용도 | - 객체 초기화 - null 안전성 처리 - 임시 범위 지정 - 객체 조작 - 부가 작업 수행 |
// 1. 기본 함수 선언
fun basicFunction(param1: String, param2: Int): String {
return "$param1 $param2"
}
// 2. 단일 표현식 함수
fun singleExpression(x: Int, y: Int) = x + y
// 3. 기본 매개변수
fun defaultParams(name: String = "Default", age: Int = 20) = "Name: $name, Age: $age"
// 4. 가변 인자 함수
fun varargFunction(vararg numbers: Int) = numbers.sum()
// 5. 지역 함수
fun outerFunction() {
fun localFunction() = "Local Function"
println(localFunction())
}
// 6. 확장 함수
fun String.addPrefix() = "Prefix_$this"
// 7. 스코프 함수 예시들
data class Person(var name: String, var age: Int)
// let 예시 - null 체크
val nullablePerson: Person? = Person("홍길동", 30)
nullablePerson?.let {
println("${it.name}의 나이는 ${it.age}입니다.")
}
// run 예시 - 객체 구성과 계산
val personInfo = Person("김철수", 25).run {
age += 1
"이름: $name, 나이: $age"
}
// with 예시 - 객체 속성 접근
val person = Person("박영희", 28)
with(person) {
println("$name is $age years old")
}
// apply 예시 - 객체 초기화
val newPerson = Person("이영수", 35).apply {
name = "새이름"
age = 40
}
// also 예시 - 로깅과 부가 작업
val numbers = mutableListOf(1, 2, 3)
.also { println("초기 리스트: $it") }
.also { it.add(4) }
.also { println("최종 리스트: $it") }
// 실제 활용 예시
class UserProfile {
private val userData = mutableMapOf<String, Any>()
fun updateProfile() = userData.apply {
put("name", "홍길동")
put("age", 30)
put("email", "hong@example.com")
}.also {
println("프로필 업데이트 완료: $it")
}.run {
"프로필 업데이트 성공"
}
}
오늘도 감사합니다. 😀
반응형