27581


<https://kotlinlang.org/docs/reference/reflection.html>

上記リファレンスに載っている`::`オペレータによる関数名を直接指定する方法を試そうとしたのですが、エラーを吐いてしまいました。

[code]

    C:\> C:\opt\kotlin\bin\kotlinc-jvm
    Welcome to Kotlin version 1.0.3 (JRE 1.8.0_91-b15)
    Type :help for help, :quit for quit
    >>> fun isOdd(x: Int) = x % 2 != 0
    >>> val numbers = listOf(1, 2, 3)
    >>> numbers.filter(::isOdd)
    error: left-hand side of a callable reference with a receiver parameter cannot be empty. Please specify the type of the receiver before '::' explicitly
    numbers.filter(::isOdd)
                     ^
    
[/code]

エラーによると「型を明示してください」と出ているようですが、正しくはどう書けばよいのでしょうか？


CC BY-SA 3.0
2016-07-12T17:55:31.237
27580
2017-07-18T15:32:54.580
2391
question
kotlin
::オペレータの呼び出しに失敗する


Please refer to this question if you are able to read english.  
<https://stackoverflow.com/questions/33616464/function-references-and-lambdas>

basically, make a extension or a function without class.

[code]

    fun Int.isOdd()
    
[/code]

* * *

英語で良ければ、以下の質問を参考にしてください。  
<https://stackoverflow.com/questions/33616464/function-references-and-lambdas>

基本的には、extension か クラス抜きの関数を作ればよいです。

[code]

    fun Int.isOdd()
    
[/code]


CC BY-SA 3.0
2016-07-12T18:20:59.893
27581
2017-07-18T15:32:54.580
2017-07-18T15:32:54.580
19110
14435
27580
answer


※Kotlinを使うのは初めてなので不正確な部分があるかと思います

REPLの各行はroot
packageではなく`LineX`のような特殊なclass?に属するようで、`::isOdd`と呼び出すことはできません(でした)。

[code]

    PS C:\Program Files (x86)\JetBrains\IntelliJ IDEA 2016.1.2\plugins\Kotlin\kotlinc\bin> .\kotlinc-jvm
    Welcome to Kotlin version 1.0.1-2 (JRE 1.8.0_92-b14)
    Type :help for help, :quit for quit
    >>> println(this)
    Line1@2aafb23c
    >>> println(this)
    Line2@1cd072a9
    >>> val line = this; fun isOdd(x: Int) = x % 2 != 0
    >>> println(line.isOdd(1))
    true
    
[/code]

上記のREPLの3～4行目はイメージ的には下記のようになってると思われます。  
(あくまでイメージで、実装詳細は確認していません)

[code]

    class Line3 {
        val line = this;
        fun isOdd(x: Int) = x % 2 != 0
    }
    val res3 = Line3() // = Line3@xxxxxxxx
    
    class Line4 {
        init {
            println(res3.line.isOdd(1))
        }
    }
    val res4 = Line4() // = Line4@xxxxxxxx
    
[/code]

そのためREPLではFunction Referencesを使わずに呼び出すのが無難かと思います。

[code]

    >>> fun isOdd(x: Int) = x % 2 != 0
    >>> val numbers = listOf(1, 2, 3)
    >>> numbers.filter{ n -> isOdd(n) }
    [1, 3]
    
[/code]

一応、下記の様によくわからないことをすれば呼び出すことはできました。

1.`fun isOdd() = { x: Int -> x % 2 != 0 }`と定義して、`invoke()`する

[code]

    >>> val line1 = this; fun isOdd() = { x: Int -> x % 2 != 0 }
    >>> (1..10).filter(Line1::isOdd.invoke(line1))
    [1, 3, 5, 7, 9]
    
[/code]

`Line1::isOdd`は`KFunction1<Line1, (Int) → Boolean)`なので、invoke()すると型が合います。

2.`val isOdd = { x: Int -> x % 2 != 0 }`と定義して、`invoke()`する

[code]

    >>> val line1 = this; val isOdd = { x: Int -> x % 2 != 0 }
    >>> (1..10).filter(Line1::isOdd.invoke(line1))
    [1, 3, 5, 7, 9]
    
[/code]

`Line1::isOdd`は`KProperty1<Line1, (Int) → Boolean>`なので、invoke()すると型が合います。


CC BY-SA 3.0
2016-07-13T05:10:10.480
27593
2016-07-13T06:10:22.727
2016-07-13T06:10:22.727
3068
3068
27580
answer


他の方のアドバイスのとおり、REPL内で評価されたコードは`LineX`というクラスに属するため、質問で取り上げた`isOdd`は関数でなくメソッドとして定義される点が問題だったようです。

REPLではなくソースコードのトップレベルに関数を書くか、ローカル関数として定義することで`::`オペレータを利用することができました。

[code]

    // トップレベル関数
    fun isEven(x: Int) = x % 2 == 0
    
    class LocalFun {
        fun testIsOdd() {
            // ローカル関数
            fun isOdd(x: Int) = x % 2 != 0
            println((1..10).filter(::isOdd)) //-> [1, 3, 5, 7, 9]
        }
    }
    
    fun main(args: Array<String>) {
        println((1..10).filter(::isEven))    //-> [2, 4, 6, 8, 10]
        LocalFun().testIsOdd()
    }
    
[/code]


CC BY-SA 3.0
2016-07-13T09:10:06.413
27598
2016-07-13T09:10:06.413
2391
27580
answer