简体   繁体   English

Scala,无法实现通用的Java方法

[英]Scala, can't implement generic java method

I'd like to implement a java method that uses generics in scala (2.9.2). 我想实现一个在scala(2.9.2)中使用泛型的java方法。 But I'm failing... 但是我失败了

Java interface method: Java接口方法:

public <T extends Number> void setAttribute(Key<T> key, Number value);

Scala code that want to implement that method: 要实现该方法的Scala代码:

def setAttribute[T <: Number](key: Key[T], value: Number) = {
  setAttributeLocal(key, value)  }

private def setAttributeLocal[T](key: Key[T], value: T) = {
  val stringValue = ConvertUtils.convert(value, classOf[String]).asInstanceOf[String]
  session = session + (key.getValue() -> stringValue)
}

Key looks like: 密钥如下所示:

public class Key<T>

But this doesn't compile. 但这无法编译。

[error]  found   : mypackage.Key[T]
[error]  required: mypackage.Key[java.lang.Number]
[error] Note: T <: java.lang.Number, but Java-defined class Key is invariant in type T.
[error] You may wish to investigate a wildcard type such as `_ <: java.lang.Number`. (SLS 3.2.10)
[error]     setAttributeLocal(key, value)

I can't figure out what's the problem. 我不知道是什么问题。 Any suggestions/idea? 有什么建议/想法吗?

greez GarfieldKlon 格里兹·加菲尔德·科隆

It appears the compiler is unhappy with your call to setAttributeLocal . 看来编译器对您对setAttributeLocal的调用不满意。 setAttributeLocal requires a Key[Number] , but you are providing a Key[_ <: T] . setAttributeLocal需要一个Key[Number] ,但是您要提供一个Key[_ <: T] In Java-Land this means you're trying to pass a Key<? extends Number> 在Java-Land中,这意味着您尝试传递Key<? extends Number> Key<? extends Number> off as a Key<Number> . Key<? extends Number>Key<Number>

The suggestion is to have setAttributeLocal accept Key<? extends Number> 建议是让setAttributeLocal接受Key<? extends Number> Key<? extends Number> or Key[_ <: Number] , depending on whether it is Java- or Scala-defined. Key<? extends Number>Key[_ <: Number] ,具体取决于它是Java定义还是Scala定义的。

Something looks a bit off here. 这里看起来有些不对劲。

Have you tried: 你有没有尝试过:

def setAttribute[T <: Number](key: Key[T], value: T) =
  setAttributeLocal(key, value)

It seems strange/bad to preserve the type T for the key, but not use it on the value. 保留键的类型T,但不对值使用它,这似乎很奇怪/不好。 My guess is that's where you're getting an invariant error. 我的猜测是,您会收到一个不变的错误。 You're trying to assing the value of type Number to a key of type T and the compiler isn't sure if it can't pass Number for T (while it knows it can pass T for Number ). 您试图将Number类型的值赋给T类型的键,并且编译器不确定它是否不能为T传递Number (虽然它知道可以为Number传递T )。

Can we see more code? 我们可以看到更多代码吗?

As @jsuereth already pointed out, there is a discrepancy between the signatures of setAttribute and setAttributeLocal , namely, that the former accepts a Key[T <: Number] but fixes the value that goes with the key to exactly be a Number , whereas the latter is more flexible and allows key and value to be T <: Number . 正如@jsuereth已经指出的那样, setAttributesetAttributeLocal的签名之间存在差异,即前者接受Key[T <: Number]但将与该键一起的值固定为完全为Number ,而后者更灵活,并允许键和值是T <: Number This looks rather odd and you might want to reconsider that decision. 这看起来很奇怪,您可能需要重新考虑这个决定。 It also leads to the problem explained by @Ben Schulz. 这也导致了@Ben Schulz解释的问题。

In any case, the compiler (2.9.1) is happy with the following setup: 无论如何,编译器(2.9.1)对以下设置感到满意:

MyI.java : MyI.java

public interface MyI {
  public <T extends Number> void setAttribute(Key<T> key, Number value);
}

Key.java : Key.java

public interface Key<T> {
}

Test.scala : Test.scala

object Test extends App {
  def setAttribute[T <: Number](key: Key[T], value: Number) = {
    setAttributeLocal(key, value)  }

  private def setAttributeLocal[T](key: Key[T], value: Number) = {
    /* Notice that value is now also of type Number. */
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM