scala объединяет несколько параметров вызова функции в Кортеж — это может быть отключено?

Это - неприятное нарушение безопасности типов в моем проекте, таким образом, я ищу способ отключить его. Кажется этим, если функция берет AnyRef (или java.lang. Объект), можно вызвать функцию с любой комбинацией параметров, и Scala объединит параметры в Кортеж, возражают и вызывают функцию.

В моем случае функция не ожидает Кортеж и перестала работать во времени выполнения. Я ожидал бы, что эта ситуация будет поймана во время компиляции.

object WhyTuple {
 def main(args: Array[String]): Unit = {
  fooIt("foo", "bar")
 }
 def fooIt(o: AnyRef) {
  println(o.toString)
 }
}

Вывод:

(foo,bar)
7
задан retronym 17 May 2010 в 19:38
поделиться

6 ответов

Компилятор способен интерпретировать методы без круглых скобок. Поэтому он воспринимает круглые скобки в fooIt как Tuple. Ваш вызов будет таким же, как:

fooIt( ("foo","bar") )

Тем не менее, вы можете заставить метод исключить вызов, и получить значение, если вы используете какую-нибудь обертку, например Some(AnyRef) или Tuple1(AnyRef).

1
ответ дан 6 December 2019 в 12:46
поделиться

Я думаю, что определение (x, y) в Predef является ответственным. Флаг компилятора "-Yno-Prefs" может быть полезен, если вы готовы выполнить работу по ручному импорту любых неявных выражений, которые могут вам понадобиться. Под этим я подразумеваю, что вам придется добавлять import scala.Predef._ повсюду.

0
ответ дан 6 December 2019 в 12:46
поделиться

Никаких имплицитов или Predef здесь нет - просто старая добрая магия компилятора. Вы можете найти его в средстве проверки типов . Я не могу найти его в спецификации прямо сейчас.

Если вы достаточно мотивированы, вы можете добавить к компилятору параметр -X, чтобы предотвратить это.

В качестве альтернативы, вы можете избежать написания методов arity-1, которые принимают супертип TupleN .

7
ответ дан 6 December 2019 в 12:46
поделиться

Редактировать : По мнению людей, более информированных, чем я, следующий ответ на самом деле неверен: см. этот ответ . Спасибо Аарону Новструпу за указание на это.

Это на самом деле причуда парсера , а не системы типов или компилятора. Scala позволяет вызывать функции с нулевым или одним аргументом без скобок, но не с более чем одним аргументом. Итак, как Фред Хаслам говорит , то, что вы написали , не является вызовом с двумя аргументами, это вызов с одним аргументом, имеющим значение кортежа. Однако, если метод действительно принимает два аргумента, вызов будет вызовом с двумя аргументами.Похоже, что смысл кода влияет на то, как он разбирается (что немного отстойно).

Что касается того, что вы можете с этим поделать, это непросто. Если метод действительно требует двух аргументов, эта проблема исчезнет (т.е. если кто-то по ошибке попытается вызвать его с одним аргументом или с тремя, он получит ошибку компиляции, как вы ожидаете). Не думаете ли вы, что есть какой-то дополнительный параметр, который вы откладываете добавить к этому методу? :)

4
ответ дан 6 December 2019 в 12:46
поделиться

Как насчет чего-то вроде этого:

object Qx2 {
    @deprecated def callingWithATupleProducesAWarning(a: Product) = 2
    def callingWithATupleProducesAWarning(a: Any) = 3
}

Кортежи имеют признак Product, поэтому любой вызов callWithATupleProducesAWarning, передающий кортеж, будет выдавать предупреждение об устаревании.

4
ответ дан 6 December 2019 в 12:46
поделиться

Не могли бы вы также добавить двухпараметрическое переопределение, которое помешало бы компилятору применять синтаксический сахар? Если сделать типы, принимающие подходящим образом затемненными, вы вряд ли получите ложные срабатывания. Например:

object WhyTuple {

  ...

  class DummyType

  def fooIt(a: DummyType, b: DummyType) {
    throw new UnsupportedOperationException("Dummy function - should not be called")
  }
}
0
ответ дан 6 December 2019 в 12:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: