2013-02-08 3 views
6

Я хотел бы передать закрытие метода в качестве опции, и я делаю то, что показано ниже. Я получаю ошибку компиляции, как показано ниже. Можно ли передать необязательный параметр закрытия функции?Как передать необязательный параметр закрытия функции?

def sampleMethod(a: String, b: String, optionalMethod: Option[(String, Int) => Unit]) { 
    // do some processing with a and b 
    optionalMethod match { 
     case Some(optionalMethod) => { 
     optionalMethod("a",3) 
     } 
     case _ 
     log("no optional method passed") 
    } 
} 

// definition of optMethod in some other place 
val optMethod = (c: String, d: Int) => { 
    // some processing with c, d and external values 
} 

// invoke 
sampleMethod("hi", "bye", optMethod) => FAILS TO COMPILE 

ERROR = type mismatch. expecting Option[(String, Int) => Unit] found (String, Int) => Unit 
+0

sampleMethod ("hi", "bye", Some (optMethod)) – twillouer

+0

optionalMethod.map (f => f ("a", 3)), чтобы быть более ясным – twillouer

+1

Просто потому, что другие языки и их сообщества пользователей неаккуратные termino logy, давайте не будем делать то же самое здесь. «Закрытие» относится к использованию свободных переменных в литерале функции (имена без привязок в теле этой функции) и их ссылки «закрываются» в лексическую среду. Не все функции включают закрытие лексической среды. Не все функции являются функциональными литералами. Например, они часто создаются (автоматически или прозрачно с помощью компилятора или явно) посредством «частичного приложения» другой функции или метода. –

ответ

3

Как насчет

sampleMethod("hi", "bye", Some(optMethod)) 
6

Как указывалось ранее, ваш метод ожидает Option значение, содержащее optionalMethod. Вы должны, следовательно, передать Option значение к нему:

// invoke with method 
sampleMethod("hi", "bye", Some(optMethod)) 
// invoke without method 
sampleMethod("hi", "bye", None) 

Если вы хотите избежать значения Option, вы можете попробовать следующее (особ избежать None.):

def sampleMethod(a: String, b: String, optionalMethod: (String, Int) => Unit = (_, _) => log("no optional method passed")) { 
    optionalMethod("a", 3) 
} 

// invoke with method 
sampleMethod("hi", "bye", optMethod) 
// invoke without method 
sampleMethod("hi", "bye") 
0

Более ясно:

scala> def sampleMethod(a: String, b: String, optionalMethod: Option[(String, Int) => Unit]) { 
    | optionalMethod.map(f => f("a", 3)) 
    | } 
sampleMethod: (a: String, b: String, optionalMethod: Option[(String, Int) => Unit])Unit 


scala> sampleMethod("A", "A", Some((c:String, d:Int) => println(s"Hello wolrd $c...$d"))) 
Hello wolrd a...3 

Вы должны просто добавить "Некоторые из них()" вокруг функции

необязательный
7

Сообщение об ошибке довольно явное: sampleMethod ожидает Option, но вы передаете прямое значение функции (не завернутое в Some).

Самый простой способ исправить это, чтобы обернуть optMethod в Some:

sampleMethod("hi", "bye", Some(optMethod)) 

Но если вы хотите, чтобы иметь возможность просто сделать sampleMethod("hi", "bye", optMethod), вы можете добавить перегружен определения sampleMethod:

object Test { 
    def sampleMethod(a: String, b: String, optionalMethod: Option[(String, Int) => Unit]) { 
    // do some processing with a and b 
    optionalMethod match { 
     case Some(optionalMethod) => { 
     optionalMethod("a",3) 
     } 
     case _ => log("no optional method passed") 
    } 
    } 
    def sampleMethod(a: String, b: String) { sampleMethod(a, b, None) } 
    def sampleMethod(a: String, b: String, optionalMethod: (String, Int) => Unit) { 
    sampleMethod(a, b, Some(optionalMethod)) 
    } 
} 

val optMethod = (c: String, d: Int) => { 
    // some processing with c, d and external values 
} 

// invoke 
Test.sampleMethod("hi", "bye", optMethod) // Now Compiles fine 
Test.sampleMethod("hi", "bye") // This too 
+0

Я думаю, что перегрузка - это гораздо лучший подход, чем использование опции «Option» для аргумента функции. –

+0

Вы имеете в виду использование только 2 перегрузок (один с аргументом и один без), а не 3 перегрузки, как в моем ответе? Если это так, то дело в том, что в общем случае может быть достаточно общее поведение между обоими случаями, которые вы хотите разложить на одну единицу (как в моей первой перегрузке, которая выполняет всю работу), и достаточно различий, которые просто имеют значение по умолчанию для 'optionalMethod' (как в ответе @ fynn) может оказаться недостаточным. Это очень зависит от реальных потребностей. –

+2

Затем создайте частный метод, который выполняет эту работу, и берет 'Option [Function]', который затем вызывается общедоступными методами, перегруженными с помощью функции и без нее. –

Смежные вопросы