如何从Scala调用通配符Java函数

3

我有一个Java库,其中包含一些通用的容器:

public interface IColumnTable<T extends IColumn<?, ?>>
{
}
public interface IColumn<D extends IColumnValues<?>, M extends IMetaData> 
{
}
public interface IColumnValues<E> 
{
}
public interface IMetaData 
{
}

并提供获取它们具体实例的工厂方法

public interface StorageFactory
{
IColumnTable<? extends IColumn<? extends IColumnValues<?>, ? extends IMetaData>> read(String tableName) throws IOException;
}

我还有一个实用方法,可以通过类型转换和值转换来输入通配符表格。

public class TableConverterUtil 
{
public static <T, V> IColumnTable<IColumn<IColumnValues<T>, IMetaData>> getPureTypedTable(
        IColumnTable<? extends IColumn<? extends IColumnValues<V>, ? extends IMetaData>> tableRaw,
        Class<T> type,
        Optional<Function<V, Optional<T>>> converter
    ) 
}

请注意IColumnValues参数使用V而不是?的用法。

在Java中,我可以调用以下代码以获取具有Double值的表格:

try {
            IColumnTable<IColumn<IColumnValuesExact<Double>, IMetaData>> myDoubleTable = TableConverterUtil.getPureTypedTable(
                StorageManagerUtil.getDefault().get("default").read("myTableName"),
                Double.class,
                Optional.empty()
            );
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (StorageManagerInstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

然而在Scala中,我似乎无法让相同的调用起作用:
TableConverterUtil.getPureTypedTable(
  StorageManagerUtil.getDefault.get("default").read("myTableName"),
  classOf[Double],
  Optional.empty()
)

结果为:

[file and line number]: no type parameters for method emp
ty: ()java.util.Optional[T] exist so that it can be applied to arguments ()
[error]  --- because ---
[error] undetermined type
[error]       Optional.empty()
[error]                ^
[error] [file and line number]: type mismatch;
[error]  found   : java.util.Optional[T]
[error]  required: java.util.Optional[java.util.function.Function[?,java.util.Op
tional[?]]]
[error]       Optional.empty()
[error] 

                ^

我还尝试过使用null代替Optional.empty(),结果如下:
[error] [file & line no]: no type parameters for method get
PureTypedTable: (x$1: com.wwa.data.interfaces.IColumnTable[_ <: com.wwa.data.int
erfaces.IColumn[_ <: com.wwa.data.interfaces.IColumnValues[V], _ <: com.wwa.data
.interfaces.IMetaData]], x$2: Class[T], x$3: java.util.Optional[java.util.functi
on.Function[V,java.util.Optional[T]]])com.wwa.data.interfaces.IColumnTable[com.w
wa.data.interfaces.IColumn[com.wwa.data.interfaces.IColumnValuesExact[T],com.wwa
.data.interfaces.IMetaData]] exist so that it can be applied to arguments (com.w
wa.data.interfaces.IColumnTable[?0], Class[Double], Null)
[error]  --- because ---
[error] argument expression's type is not compatible with formal parameter type;

[error]  found   : com.wwa.data.interfaces.IColumnTable[?0(in method doWork)] wh
ere type ?0(in method doWork) <: com.wwa.data.interfaces.IColumn[_ <: com.wwa.da
ta.interfaces.IColumnValues[_], _ <: com.wwa.data.interfaces.IMetaData]
[error]  required: com.wwa.data.interfaces.IColumnTable[_ <: com.wwa.data.interf
aces.IColumn[_ <: com.wwa.data.interfaces.IColumnValues[?V], _ <: com.wwa.data.i
nterfaces.IMetaData]]
[error]     TableConverterUtil.getPureTypedTable(
[error]                        ^
[error] [file & line No.]: type mismatch;
[error]  found   : com.wwa.data.interfaces.IColumnTable[?0(in method doWork)] wh
ere type ?0(in method doWork) <: com.wwa.data.interfaces.IColumn[_ <: com.wwa.da
ta.interfaces.IColumnValues[_], _ <: com.wwa.data.interfaces.IMetaData]
[error]  required: com.wwa.data.interfaces.IColumnTable[_ <: com.wwa.data.interf
aces.IColumn[_ <: com.wwa.data.interfaces.IColumnValues[V], _ <: com.wwa.data.in
terfaces.IMetaData]]
[error]       StorageManagerUtil.getDefault.get("default").read("myTableName"),
[error]    

                                                ^

我还尝试了一种辅助方法,以捕获传递给IColumnValues的通配符,以便我可以实际上传递一个函数。但是没有成功,似乎每当我尝试将内部_之一绑定到命名类型参数时,编译器就会出问题。

我可以勉强改变Java库,但认为我可能错过了什么,因为Scala和Java应该是完全互操作的。

是否有一种方法可以在不更改Java的情况下从Scala调用getPureTypedTable?(使用转换函数而不是空或空可选项)

PS:抱歉发帖太长,今天晚上很晚了,我已经盯着这个问题看了一段时间了


3
如果您明确Optional的类型,比如使用Optional.empty[java.util.function.Function[_, _]](),那么它可以通过编译吗? - Sean Vieira
Scala类型推断有时会感到困惑;我怀疑在这种情况下,类型参数V可能会混淆,因为它在调用中实际上没有被使用。作为第一步,请尝试传递显式类型参数,例如getPureTypedTable[Double, Double](...) - lmm
不,它不能使用通配符编译。 - James k
它在使用显式类型进行编译时是可行的,问题出现在参数为通配符表时。 - James k
1个回答

0

我觉得我在这个 Scala 群组的帖子中找到了答案 https://groups.google.com/forum/#!topic/scala-user/JlCsy48poIU

它涉及到模式匹配来命名类型,但同时也给出了一个有关未检查类型的编译器警告,我认为可以安全地忽略它...

def callWildcardTableFunction(table: IColumnTable[_ <: IColumn[_ <: IColumnValues[_], _ <: IMetaData]])
    : IColumnTable[IColumn[IColumnValues[Double], IMetaData]] = table match
  { 
    case boundTable: IColumnTable[IColumn[IColumnValues[valueType], m]] @unchecked =>  
      TableConverterUtil.getPureTypedTable[Double, valueType](boundTable, classOf[Double], null)
  }

如果有更好的方式/这其实不安全,请说出来!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接