#scala #overloading #overload-resolution
#scala #перегрузка #перегрузка-разрешение
Вопрос:
Почему в Scala разрешена такая перегрузка?
class log {
def LogInfo(m: String, properties: Map[String, String]): Unit = {
println(m)
}
def LogInfo(m: String, properties: Map[String, String], c: UUID = null): Unit = {
println(m c.toString())
}
}
Во втором определении функции LogInfo я установил для дополнительного параметра значение по умолчанию null. Когда я выполняю следующий вызов, он вызовет первую перегрузку.
val l: log = new log()
val props: Map[String, String] = Map("a" -> "1")
l.LogInfo("message", props)
Почему бы ему не выдать исключение? При значении по умолчанию я бы подумал, что оба определения могут выглядеть одинаково.
Комментарии:
1. » При значении по умолчанию я бы подумал, что оба определения могут выглядеть одинаково». У вас есть какие-либо доказательства в поддержку этой идеи, или это просто предположение?
2. Почему это должно вызывать исключение?
3. Я должен был сказать ошибка компиляции, а не исключение.
Ответ №1:
Исключение здесь не будет выдаваться, потому что компилятор выбирает первую перегрузку в качестве применимой. Это связано с тем, как разрешение перегрузки работает с аргументами по умолчанию. Согласно спецификации, сильным намеком на то, что такие методы отбрасываются, будет следующая строка:
В противном случае пусть CC будет набором применимых альтернатив, которые не используют какой-либо аргумент по умолчанию в приложении to
e1,…,em
.
Это связано с тем, как компилятор Scala выдает байтовый код JVM для этих двух методов. Если мы скомпилируем их и заглянем за кулисы, мы увидим (опуская фактический байт-код для краткости):
public class testing.ReadingFile$log$1 {
public void LogInfo(java.lang.String,
scala.collection.immutable.Map<java.lang.String, java.lang.String>);
Code:
public void LogInfo(java.lang.String,
scala.collection.immutable.Map<java.lang.String, java.lang.String>,
java.util.UUID);
Code:
public java.util.UUID LogInfo$default$3();
Code:
0: aconst_null
1: areturn
}
Вы видите, что сгенерированный код фактически выдал два метода, один из которых принимает два аргумента, а другой — три. Кроме того, компилятор добавил дополнительный метод called LogInfo$default$3
(имя на самом деле имеет значение, где $3
означает «параметр по умолчанию для третьего аргумента»), который возвращает значение по умолчанию для c
переменной второй перегрузки. Если должен был быть вызван метод с аргументом по умолчанию, LogInfo$default$3
он будет использоваться для введения новой переменной с заданным значением.
Ответ №2:
Оба метода применимы, но разрешение перегрузки, в частности, выбрасывает приложение, которое требует аргументов по умолчанию:
применимые альтернативы, которые не используют какой-либо аргумент по умолчанию
http://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#overloading-resolution
Что касается «почему», представьте, что перегрузка имеет много параметров по умолчанию, так что большинство ее приложений не похожи на вызовы первого метода.