Ну, method1()
не может быть объявлением def method =
, так как невозможно вызвать метод без списка параметров, передающего список параметров.
scala> def method1 = 0
method1: Int
scala> method1()
<console>:9: error: Int does not take parameters
method1()
^
Обратите внимание, что ошибка происходит из Scalaпытаясь вызвать apply()
для результата method1
, который является Int
.
И наоборот, нельзя вызывать метод vararg со списком параметров.
scala> def vararg(x: Int*) = x.size
vararg: (x: Int*)Int
scala> vararg
<console>:9: error: missing arguments for method vararg;
follow this method with `_' if you want to treat it as a partially applied function
vararg
^
Поэтомув первом случае нет другого возможного поведения, кроме того, что было показано.
Во втором примере первый и последний случаи не являются неоднозначными.Нельзя вызывать vararg без списка параметров (как показано), и нельзя вызывать метод без параметров, передающих параметр.Один может вызвать метод с пустым списком параметров без параметров, что было сделано главным образом для того, чтобы сделать API-интерфейсы Java более «красивыми» - например, .toString
.
Второй случай -- вызов метода с пустым списком параметров - вносит некоторую двусмысленность.Затем Scala пытается определить, является ли один более конкретным , чем другой.
Давайте сделаем небольшой обход.Зачем искать более конкретные методы?Предположим, у вас есть это:
object T {
def f(x: AnyRef) = x.hashCode
def f(x: String) = x.length
}
Подобные вещи относительно распространены в Java API.Если кто-то вызвал f("abc")
, естественно, ожидается, что компилятор вызовет второй метод, а не первый, , но оба они действительны .Итак, как их устранить?Возможно, поскольку String
идеально подходит для того, что передается, можно использовать это, верно?Итак, рассмотрим, вот что:
object T {
def f(x: AnyRef) = x.hashCode
def f(x: java.util.Collection[_]) = x.size
}
И я называю это f(new ArrayList[String])
Итак, что теперь?Ну, AnyRef
- это класс, а Collection
- это интерфейс, так что мы могли бы отдать приоритет интерфейсам над классами?А что, если бы у меня был другой метод, ожидающий List
- это тоже интерфейс.
Итак, чтобы решить эту неоднозначность, Scala использует наиболее специфическую концепцию .На самом деле это довольно простая концепция.
Во-первых, Scala проверяет, является ли один таким же конкретным, как другого.Существует четыре простых правила, определенных в терминах типов и выражений, но суть в том, что метод a столь же специфичен, как и метод b, если b можно вызывать с параметрами a.
В этом случае method2()
специфичен method2(args: Any*)
, потому что method2(args: Any*)
можно вызвать с пустым списком параметров.С другой стороны, method2(args: Any*)
не так специфичен, как method2()
, потому что method2()
нельзя вызывать с аргументами типа Any
.
Далее, Scala проверяет, является ли класс классом, который определяет один изМетоды являются подклассом класса, который определяет другой.Это правило не применяется в этом случае.
Наконец, Scala добавляет 1 к каждому методу для каждого из двух критериев, которые ему подходят.Таким образом, method2()
имеет вес 1, а method2(args: Any*)
имеет вес 0. Если вес одного больше другого, этот метод считается наиболее специфичным .
.мы видели, method2()
является наиболее конкретным, поэтому он выбран.