4

尝试使用 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>

有什么比强制编译更优雅的解决方案?

4

2 回答 2

5

--修改后的答案,基于 Exception 和 Blaisorblade 的评论--

您遇到了 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
  • 第一次调用有效,因为andf的常见超类型是,所以这是推断的类型。java.lang.Doublejava.lang.Numberjava.lang.NumberT

  • 第二次调用f有效,因为我们已经明确告诉编译器T==java.lang.Number. 当编译器发现第二个参数 ,0 : Int与预期类型不匹配时java.lang.Number,它会搜索从Intto的隐式转换Number。编译器找到Predef.int2Integer并应用它。一切都很好。

  • 第三次调用f不起作用,因为第一个参数约束T == Number,而第二个参数说T >: Int(即是T的超类型Int)。Intand的常见超类型NumberAny,但这不起作用,因为Foo[T]它不是协变的T(换句话说,我们不能将 a 强制Foo[Number]转换为 a Foo[Any])。这就是编译器错误信息的要点。请注意,编译器不知道如何应用隐式转换,因为它不知道T要转换为的特定类型。

关于您发布的 JavaFX 代码的一件奇怪的事情是KeyValue该类不是通用的,而是具有通用构造函数。有趣的是,这在 Scala 中是不可能的,所以没有办法(据我所知)T从 Scala 代码中显式地限制参数。如果整个KeyValue类都是通用的,你也可以写

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

这相当于 Exception 发布的代码,因为编译器会推断double2Double转换。

于 2011-08-05T21:06:09.083 回答
4

几天前我遇到了同样的问题。在尝试了不同的事情之后,我最终做到了。

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

(请参阅 Blaisorblade 评论以获取解释)

于 2011-08-06T21:50:28.327 回答