중위 표기법(중위 함수)-Infix

#Kotlin #Kotlin_Infix

1. Infix?

함수(메서드)는 메서드인데 일반적이지 않은 형태로 사용할 수 있는 함수이다. 확장함수의 일종으로 가독성이 훨씬 좋아질 수 있다. is, until, and, or, ... 모두 코틀린에서 만들어 둔 중위함수, infix 이다. (참고: until source code)

fun standardInfixTest() {  
    val str = "hello"  
    val num = 10  
    val arr = arrayOf(1, 2, 3, 4)  
  
    if((str is String) and (num is Int)) {  //infix: is, and
		for((idx, arrNum) in arr.withIndex()) { //infix: in
            println("hello arr[$idx]: ${(arrNum+num)}")  
        }  
    }  
}

2. Infix 함수 만들기

infix 함수의 정의 형태는 infix fun R.functionName(t: T): V 이다. 이 함수를 정의하기 위해서는,

2-1. vararg가 안된다는 것이지, 컬렉션이 안된다는 것은 아니다.

infix fun Int.plusToEachOf(arr: IntArray): IntArray {  
    return arr.map { it + this }.toIntArray()  
}

fun test() {
	val result: IntArray = 10 plusToEachOf intArrayOf(0, 1, 2, 3, 4, 5)
	println("result: ${result.contentToString()}")
}

2-2. 클래스 내에 선언하면 리시버 함수가 없어도 된다.

infix notation, kotlinlang.org

class InfixJoinWithDashClass {  
    infix fun joinWithDash(str: String): String {  
        return "$this-$str"  
    }  
  
    infix fun String.joinWithDashWithR(str: String): String {  
        return "$this-$str"  
    }  
  
    fun build() {  
        println(joinWithDash("is this object"))  // infix.InfixJoinWithDashClass@4a574795-is this object
        println("this is" joinWithDashWithR "joinWithDashWithR()") //joinWithDashForOuter-use this
    }  
}

위 처럼 클래스 안에 두가지 infix 함수가 선언되었다.
하나는 리시버가 없고(없는 것 같이 보이고) 하나는 리시버가 있다.
둘 다 쓸 수 있을까? 둘 다 클래스 내에서든, 클래스를 인스턴스화 해서든 쓸 수 있을까?

둘 다 클래스 내에서는 사용가능하다. But 리시버가 있는 함수는 클래스 밖에서 사용할 수 없다.

왜그럴까?
생각해보면 중위함수는 확장함수의 형태이고 동작도 확장함수처럼 동작한다.

fun test() {
	val infixJoinWithDashClass = InfixJoinWithDashClass()

	val strWithJoinWithDashMethod = infixJoinWithDashClass joinWithDash "is object of InfixJoinWithDashClass."
	val strWithJoinWithDashWithRMethod = "This is made by" joinWithDashWithR "joinWithDashWithR method." //Error! lint에서부터 잡는 에러.
}