코틀린 & Java/코틀린인액션

Kotlin Plus 산술연산자 오버로딩

코딩하는후운 2023. 5. 9. 13:21
반응형

연산자 오버로딩 & 기타 관례

  • 코틀린이 지원하는 여러 관례(컨벤션)와 관례의 사용법
  • 코틀린은 자바클래스를 사용하고 있음. 따라서 자바가 특정 인터페이스를 구현하게 할수는 없음
  • 따라서 확장함수를 통해 기존클래스에 새로운 메서드를 추가한다.
  • 이를 통해 기존 자바코드를 바꾸지 않고도 새로운 기능을 부여할수 있다.
StringsJVM.kt (kotlin-stdlib)


/**
 * Returns `true` if this string is equal to[other], optionally ignoring character case.
 *
 * Two strings are considered to be equal if they have the same length and the same character at the same index.
 * If[ignoreCase] is true, the result of `Char.uppercaseChar().lowercaseChar()` on each character is compared.
 *
 *@paramignoreCase`true` to ignore character case when comparing strings. By default `false`.
 */
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
public actual fun String?.equals(other: String?, ignoreCase: Boolean = false): Boolean {
    if (this === null)
        return other === null
    return if (!ignoreCase)
        (this as java.lang.String).equals(other)
    else
        (this as java.lang.String).equalsIgnoreCase(other)
}

특별히 코틀린에서는 연산자에 대응하는 특별한 메소드들을 정의할수 있게 되어있다.

산술연산자 오버로딩

Plus

  • 자바에서는 원시타입에 대해 산술연산자를 사용할수 있음
  • 특별히 String 에 대해서는 + 를 사용할수 있도록 정의해두었음
  • 이외에도 이러한 산술연산자를 정의해서 쓰면 좋은 경우가 있는데,
  • 코틀린에서는 이것을 각자 상황에 맞게 정의해서 쓰는것이 가능하다.

이항 산술연산 오버로딩

  • operator 키워드를 붙여야한다는 점을 기억한다.
  • 관례 Convention : 이러한 방식으로 연산자를 정의하는 것을 의미
operator fun Int.plus(b: Int) = this + b

fun test() {
    operator fun Int.plus(b: Any): String {
        return "$this $b"
    }
    println(10 + "ABC")
}
data class Position(val a: Int, val b: Int) {

    operator fun plus(item: Position): Position {
        return Position(a + item.a, b + item.b)
    }
}

class ExampleUnitTest {

    @Test
    fun test() {
        val positionOne = Position(1, 2)
        val positionTwo = Position(3, 4)
        println(positionOne + positionTwo)
    }
}
Function code
plus a + b
minus a - b
div a / b
rem a % b
times a * b
not !a
unaryPlus +a
unaryMinus -a
inc ++a, a++
dec –a, a–
class ExampleUnitTest {

    @Test
    fun test() {
        var position = Position(1, 2)
        println(position++)
        println(++position)
    }
}

data class Position(var a: Int, var b: Int) {

    operator fun inc(): Position {
        return Position(a.inc(), b.inc())
    }
}

Android CoroutineScope

private val job = SupervisorJob()
private val uiScope = CoroutineScope(Dispatchers.Main + job)


CoroutineScope.kt
public operator fun CoroutineScope.plus(context: CoroutineContext)
: CoroutineScope =
    ContextScope(coroutineContext + context)


CoroutineContext.kt
public operator fun plus(context: CoroutineContext): CoroutineContext =
    if (context === EmptyCoroutineContext) this else // fast path -- avoid lambda creation
        context.fold(this){acc, element->
val removed = acc.minusKey(element.key)
            if (removed === EmptyCoroutineContext) element else {
                // make sure interceptor is always last in the context (and thus is fast to get when present)
                val interceptor = removed[ContinuationInterceptor]
                if (interceptor == null) CombinedContext(removed, element) else {
                    val left = removed.minusKey(ContinuationInterceptor)
                    if (left === EmptyCoroutineContext) CombinedContext(element, interceptor) else
                        CombinedContext(CombinedContext(left, element), interceptor)
                }
            }
}

Invoke Operator

이름 없이 호출될 수 있음

class Test{
    operator fun invoke(str: String){
        print(str)
    }
}

fun main(){
    val test = Test()
    test("wow")
}
// UseCase
class GetAccountLocalUseCase @Inject constructor(
    private val localRepository: LocalRepository
) : BaseUseCase() {

    operator fun invoke(): Flow<TaskResult<AccountLocal>> =
			flow{emit(localRepository.getUserInfo())}.toTaskResult()
		}
}

// ViewModel
class MyAddressViewModel @Inject constructor(
    val getAccountLocalUseCase: GetAccountLocalUseCase
) : BaseViewModel() {


init {
        getAccountLocalUseCase()
					  .onSuccess { account ->
               ...
            }
            .onFailure { it.printStackTrace() }
            .call(viewModelScope)

 

반응형