Groovy неявный вызов не работает для замыканий членов при использовании аннотации @CompileStatic
Этот код работает как положено (вывод j.doe
):
class Sample {
Closure formatFirstName
Closure formatLastName
void doStuff (String fname, String lname, Closure callback) {
formatFirstName(fname) { String fnameError, String formattedFname ->
formatLastName(lname) { String lnameError, String formattedLname ->
String errors = "${fnameError ? "${fnameError}, " : ''}${lnameError ?: ''}"
callback(errors, formattedFname, formattedLname)
}
}
}
}
Closure ffn = { String fname, Closure callback ->
String firstInitial = fname?.substring(0,1)
if (!firstInitial)
callback('invalid first name', null)
else
callback(null, firstInitial.toLowerCase())
}
Closure fln = { String lname, Closure callback ->
String lastPrefix = lname?.size() > 2 ? lname.substring(0,3) : null
if (!lastPrefix)
callback('invalid last name', null)
else
callback(null, lastPrefix.toLowerCase())
}
Sample sample = new Sample(formatFirstName: ffn, formatLastName: fln)
sample.doStuff('John', 'Doe') { String errors, String formattedFname, String formattedLname ->
if (errors)
println errors
else
println "${formattedFname}.${formattedLname}"
}
Добавление @CompileStatic
аннотация вызывает исключение:
groovy.lang.MissingMethodException: No signature of method: Sample$_doStuff_closure1.doCall() is applicable for argument types: (java.lang.String, Sample$_doStuff_closure1_closure2) values: [Doe, Sample$_doStuff_closure1_closure2@bb70963]
Possible solutions: doCall(java.lang.String, java.lang.String), findAll(), findAll()
at Sample$_doStuff_closure1.doCall(ConsoleScript226:11)
at ConsoleScript226$_run_closure1.doCall(ConsoleScript226:26)
at Sample.doStuff(ConsoleScript226:10)
at Sample$doStuff.call(Unknown Source)
at ConsoleScript226.run(ConsoleScript226:40)
(Код с @CompileStatic
аннотация)
import groovy.transform.CompileStatic
@CompileStatic
class Sample {
Closure formatFirstName
Closure formatLastName
void doStuff (String fname, String lname, Closure callback) {
formatFirstName(fname) { String fnameError, String formattedFname ->
formatLastName(lname) { String lnameError, String formattedLname ->
String errors = "${fnameError ? "${fnameError}, " : ''}${lnameError ?: ''}"
callback(errors, formattedFname, formattedLname)
}
}
}
}
Closure ffn = { String fname, Closure callback ->
String firstInitial = fname?.substring(0,1)
if (!firstInitial)
callback('invalid first name', null)
else
callback(null, firstInitial.toLowerCase())
}
Closure fln = { String lname, Closure callback ->
String lastPrefix = lname?.size() > 2 ? lname.substring(0,3) : null
if (!lastPrefix)
callback('invalid last name', null)
else
callback(null, lastPrefix.toLowerCase())
}
Sample sample = new Sample(formatFirstName: ffn, formatLastName: fln)
sample.doStuff('John', 'Doe') { String errors, String formattedFname, String formattedLname ->
if (errors)
println errors
else
println "${formattedFname}.${formattedLname}"
}
Использование явного вызова (т.е. closure.call
) теперь это снова работает:
import groovy.transform.CompileStatic
@CompileStatic
class Sample {
Closure formatFirstName
Closure formatLastName
void doStuff (String fname, String lname, Closure callback) {
formatFirstName.call(fname) { String fnameError, String formattedFname ->
formatLastName.call(lname) { String lnameError, String formattedLname ->
String errors = "${fnameError ? "${fnameError}, " : ''}${lnameError ?: ''}"
callback(errors, formattedFname, formattedLname)
}
}
}
}
Closure ffn = { String fname, Closure callback ->
String firstInitial = fname?.substring(0,1)
if (!firstInitial)
callback('invalid first name', null)
else
callback(null, firstInitial.toLowerCase())
}
Closure fln = { String lname, Closure callback ->
String lastPrefix = lname?.size() > 2 ? lname.substring(0,3) : null
if (!lastPrefix)
callback('invalid last name', null)
else
callback(null, lastPrefix.toLowerCase())
}
Sample sample = new Sample(formatFirstName: ffn, formatLastName: fln)
sample.doStuff('John', 'Doe') { String errors, String formattedFname, String formattedLname ->
if (errors)
println errors
else
println "${formattedFname}.${formattedLname}"
}
Итак, мой вопрос: почему я должен использовать явный вызов замыкания для замыканий членов при использовании статической компиляции? Это просто потому, что у Java нет неявного вызова? Если бы это было так, мы бы не стали явно ссылаться на callback
закрытие передается в doStuff
метод, а?