How can I pass property getter as a function type

2019-07-19 04:40发布

问题:

How can I pass property getter to a function that accepts function type?

Here is an example of what I want achieve:

class Test {
    val test: String
        get() = "lol"

    fun testFun(func: ()->String) {
        // invoke it here
    }

    fun callTest() {
        testFun(test::get) 
        // error: Type mismatch: inferred type is 
        // KFunction1<@ParameterName Int, Char> but () -> String was expected
    }
}

Is there a way?

回答1:

You can reference the getter by writing ::test (or this::test).

When you write test::get, you are actually referencing the get method on String. That method takes an index and returns the character at that index.

If the property was a var and you want a reference to its setter, you can write ::test::set.

For more info on property references, see here: https://kotlinlang.org/docs/reference/reflection.html#bound-function-and-property-references-since-11



回答2:

As already mentioned, you can use this::test to refer to the getter. Alternatively, if you have kotlin-reflect, you can do this::test.getter.

When you pass the field as a function, it assumes you mean the getter. As a result, if you want the setter, you have two options:

this::test::set

or

this::test.setter

The latter, just like this::test.getter requires kotlin-reflect, or the program will crash (tested locally with Kotlin 1.2.50)

You can, however, get the getter in another way. But I recommend you just stick with this::test because it's shorter.

You can do:

this::something::get

With just something::get it refers to the method inside the String class, which returns a char at an index. For reference, the method declaration:

public override fun get(index: Int): Char


回答3:

If you don't mind, just use { test } (e.g. testFun { test }). This will exactly translate to your () -> String. The next best alternative is probably ::test (or this::test) as was already mentioned.

The second has probably only minor (negligible?) impact on performance. I did not test it myself, nor did I found any source which tells something regarding it. The reason why I say this, is how the byte code underneath looks like. Just due to this question I asked myself about the difference of the two: Is the property reference (::test) equivalent to a function accessing the property ({ test }) when passed as argument e.g. `() -> String`?



回答4:

It seems that you are doing something wrong on logical level.

If you are overriding get method of a variable, then you can access it's value through this get method. Thus, why bother with test::get (which is totally different method, by the way, all you are doing is trying to access char from string), when you can just access variable by it's name?