Вызовите метод, который принимает два метода в качестве аргумента - PullRequest
0 голосов
/ 30 октября 2018

Когда у меня есть функция, которая принимает в качестве аргумента другую функцию, я могу вызвать ее так:

fun foo(m: String, bar: (m: String) -> Unit) {
    bar(m)
}

foo("a message") { 
    println("message: $it")
}

Есть ли способ назвать его, как описано выше, с одним блоком скобок? Я знаю только так:

fun foo(m: String, bar1: (m: String) -> Unit, bar2: (m: String) -> Unit) {
    bar1(m)
    bar2(m)
}

foo("a message", { println("message 1: $it") }, { println("message 2: $it") } )

Ответы [ 3 ]

0 голосов
/ 30 октября 2018

Я попытался вернуть функцию, которая принимает другую функцию в качестве аргумента, чтобы посмотреть, смогу ли я получить две лямбда-выражения вне ().

fun foo(m:String,bar1:(m:String)->Unit) : (bar2:(m:String)->Unit)->Unit
{
    bar1(m)
    return { bar2: (m: String) -> Unit -> bar2(m) }
}

Оказывается, я не могу. Я заканчиваю тем, что поместил еще одну пару () вокруг или после первой функции, чтобы компилятор знал, что последняя лямбда является аргументом для возвращаемой функции, вместо того, чтобы пытаться передать два лямбда-выражения за пределы списка аргументов в скобках.

(foo("a message"){println("message 1: $it")}){println("message 2: $it")}

или

foo("a message"){println("message 1: $it")}(){println("message 2: $it")}

Очевидно, что это выглядит не лучше. Я думаю

foo("a message", { println("message 1: $it") }, { println("message 2: $it") } )

или

foo("a message", { println("message 1: $it") }){ println("message 2: $it")}

достаточно хороши.

Интересно, что это разрешено в Swift

func foo (m:String,bar1 : ((String) -> Void) ) -> (_:((String) -> Void))->Void
{
    bar1(m)
    return {bar2 in bar2(m)}
}
foo(m: "test"){print("m1: \($0)")}{print("m2: \($0)")}
0 голосов
/ 30 октября 2018

Просто для удовольствия ... вот некоторые попытки получить что-то похожее на то, что вы просили. Обратите внимание, что я не могу рекомендовать какой-либо другой подход, кроме "стандартного" ;-) (это был отказ от ответственности)

  1. стандарт как есть:

    fun method1(s: String,
                m1: (String) -> String,
                m2: (String) -> String) {
        println(m1(s))
        println(m2(s))
    }
    method1("test", { "m1: $it" }) {
        "m2: $it"
    }
    // if you like with or without mentioning the parameter names:
    method1("test",
        m1 = { "m1: $it" },
        m2 = { "m2: $it" }
    )
    
    // 1b. using own methods and supplying method references
    fun m1(s : String) = "m1: $s"
    fun m2(s : String) = "m2: $s"
    method1("test1b", ::m1 /*, ::m2 */) {
        "m2: $it"
    }
    
  2. используя invoke ...

    class Method2(val s: String,
                  val m1: (String) -> String) {
        operator fun invoke(m2: (String) -> String) {
            println(m1(s))
            println(m2(s))
        }
    }
    
    fun method2(s: String,
                m1: (String) -> String) = Method2(s, m1)
    method2("test2") {
        "m1: $it"
    }() {
        "m2: $it"
    }
    
  3. с использованием поставщика пар с собственной уродливой функцией расширения

    fun method3(s: String,
                m1AndM2: () -> Pair<(String) -> String, (String) -> String>) {
        m1AndM2().let { (m1, m2) ->
            println(m1(s))
            println(m2(s))
        }
    }
    
    infix fun <T : (String) -> String> T.and(m2: (String) -> String) = Pair(this, m2)
    method3("test3") {
        { s: String -> "m1: $s" } and // note: the "s: String" is mandatory as the compiler can not infer the type
            { "m2: $it" }
    }
    
    // 3b. using a div operator as delimiter (still a hack):
    operator fun <T : (String) -> String> T.div(m2: (String) -> String) = Pair(this, m2)
    method3("test3b") {
        { s: String -> "m1: $s" } / {
            "m2: $it"
        }
    }
    

Примечание: вы даже можете поиграть с одним или другим решением, а может даже придумать что-нибудь получше ... Тем не менее, это просто игра. Я бы все-таки придерживался первого варианта ... может быть, ссылка на метод более полезна в вашем случае. Я даже считаю вариант с именованными параметрами лучше, чем пытаться выполнить что-то вроде цепочки блоков. И не забывайте: другие (более важно, вероятно, ваше будущее я) должны иметь возможность читать код; -)

0 голосов
/ 30 октября 2018

Вы можете использовать ссылки на методы. В приведенном ниже примере используются «статические» функции, классная вещь в том, что вы также можете ссылаться на «функции экземпляра» (замыкания):

object Xxx {
    @JvmStatic
    fun main(args: Array<String>) {
        service("initial", ::toUpperCase, ::withSuffix)
    }

    fun toUpperCase(s: String) = s.toUpperCase()
    fun withSuffix(s: String) = "$s.mySuffix"

    fun service(argument: String, vararg enhancers: (String) -> String) {
        println(enhancers.fold(argument) { s, e -> e(s) })
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...