Ошибка компиляции Scala с параметризованным конструктором Java и параметризованным интерфейсом - PullRequest
4 голосов
/ 05 августа 2011

При попытке скомпилировать следующий код с Scala 2.8.1 / JavaFx 2.0 beta

new KeyValue(circle.translateYProperty, random() * height)

я получаю следующую ошибку:

[error]  found   : javafx.beans.property.DoubleProperty
[error]  required: javafx.beans.value.WritableValue[Any]
[error]             new KeyValue(circle.translateYProperty, random() * height)
[error]                                 ^
[error] one error found

В то время как эта строка компилируется очень хорошо:

new KeyValue(circle.translateXProperty.asInstanceOf[WritableValue[Any]], random() * width)

Я проверил конструктор KeyValue и он имеет следующую подпись:

public <T> KeyValue(javafx.beans.value.WritableValue<T> tWritableValue, T t) { /* compiled code */ }

circle.translateXProperty возвращает DoubleProperty , который реализует следующий интерфейс:

public interface WritableNumberValue extends javafx.beans.value.WritableValue<java.lang.Number>

Что может быть более элегантным решением, чем приведение к компиляции?

Ответы [ 2 ]

5 голосов
/ 06 августа 2011

- Пересмотренный ответ, основанный на комментариях Исключения и Блейзорблейда -

Вы столкнулись с ограничением применения имплицитов в Scala, а не (просто) проблемой взаимодействия Scala-Java. Вот упрощенный пример,

class Foo[T]
def f[T](x: Foo[T], y: T): T = y

f(new Foo[Number], new java.lang.Double(0)) // OK; infers T==Number
f[Number](new Foo[Number], 0)               // OK; uses implicit int2Integer(0)
// f(new Foo[Number], 0)                    // error
  • Первый вызов f работает, потому что общий супертип java.lang.Double и java.lang.Number равен java.lang.Number, то есть тип, выведенный для T.

  • Второй вызов f работает, потому что мы явно сказали компилятору, что T==java.lang.Number. Когда компилятор находит второй аргумент 0 : Int, не соответствующий ожидаемому типу java.lang.Number, он ищет неявное преобразование из Int в Number. Компилятор находит Predef.int2Integer и применяет его. Все хорошо.

  • Третий вызов f не работает, поскольку первый параметр ограничивает T == Number, а второй аргумент говорит T >: Int (то есть T - это супертип Int) , Общий супертип Int и Number равен Any, но это не сработает, потому что Foo[T] не является ковариантным в T (другими словами, мы не можем привести Foo[Number] к Foo[Any]). Это суть сообщения об ошибке компилятора. Обратите внимание, что компилятор не знает, как применить неявное преобразование, потому что он не знает определенного типа T для преобразования в.

Одна странная вещь в опубликованном вами коде JavaFX заключается в том, что класс KeyValue не является универсальным, но имеет универсальный конструктор. Интересно, что это не возможно в Scala, поэтому нет способа (насколько я могу судить) явно ограничить параметр T из кода Scala. Если бы весь класс KeyValue был универсальным, вы также могли бы написать

new KeyValue[Number](circle.translateYProperty, random() * height)

, который будет эквивалентен коду, опубликованному Exception, поскольку компилятор выведет преобразование double2Double.

4 голосов
/ 07 августа 2011

У меня была такая же проблема несколько дней назад.Попробовав разные вещи, я закончил с этим.

new KeyValue(circle.translateYProperty, double2Double(random() * height))

(см. Комментарии Blaisorblade для объяснения)

...