我可以让Scala更喜欢隐式转换为Java8Lambda吗?
我正在为kafka streams库编写Scala包装器。基本方法是提供从kafka streams类(如我可以让Scala更喜欢隐式转换为Java8Lambda吗?,scala,java-8,implicit-conversion,Scala,Java 8,Implicit Conversion,我正在为kafka streams库编写Scala包装器。基本方法是提供从kafka streams类(如KStream)到richKStreamOps类的隐式转换 例如,KStream提供以下map签名: <K1, V1> KStream<K1, V1> map(KeyValueMapper<K, V, KeyValue<K1, V1>> mapper) 请注意,map这里需要一个函数返回一个Tuple2,并处理将其转换为特定于kafka流的K
KStream
)到richKStreamOps
类的隐式转换
例如,KStream
提供以下map
签名:
<K1, V1> KStream<K1, V1> map(KeyValueMapper<K, V, KeyValue<K1, V1>> mapper)
请注意,map
这里需要一个函数返回一个Tuple2
,并处理将其转换为特定于kafka流的KeyValue
类型,这样用户就不需要直接与KeyValue
交互
我提供了一个隐式转换:
implicit def ops[K, V](kstream: KStream[K, V]): KStreamOps[K, V] = new KStreamOps[K, V](kstream)
但当我尝试在如下代码中使用新的映射时:
val inputStream: KStream[Int, String] = builder.stream(inputTopic)
stream.map{ (k, v) => (k, v) }
我收到以下编译错误:
[error] KStreamOpsTest.scala:47: type mismatch;
[error] found : (Int, String)
[error] required: org.apache.kafka.streams.KeyValue[Int,String]
[error] stream.map((k, v) => (k, v))
[error] ^
[error] KStreamOpsTest.scala:47: Could not derive subclass of org.apache.kafka.streams.kstream.KeyValueMapper[Int,String,org.apache.kafka.streams.KeyValue[Int,String]]
[error] (with SAM `def method apply(x$1: Int, x$2: String)org.apache.kafka.streams.KeyValue[Int,String]`)
[error] based on: ((k: Int, v: String) => scala.Tuple2(k, v)).
[error] stream.map((k, v) => (k, v))
因此,编译器尝试使用KStream#map
使用期望KeyValue
返回的SAM,而不是期望函数输出为Tuple2
的myKStreamOps#map
如果我将我的方法重命名为KStreamOps#map1
并调用stream.map1
,隐式转换将按预期工作,代码将编译
为什么编译器不能识别出存在一个隐式转换,该转换将得到一个具有正确签名的函数的方法?是否不考虑函数返回类型?山姆会永远赢吗
我正在用Scala 2.11.8测试这一点,启用了-Xexperimental
标志。正如@ukasz所建议的,创建显式包装器似乎是一种方法。我可能会提供一个从包装类型到KStream
的隐式转换:
implicit def unwrap[K, V](wrapped: WrappedKStream[K, V]): KStream[K, V] = wrapped.underlying
这样,我们就可以同时使用KStream
和包装器的方法,但是包装器类方法具有优先权
这里一个明显的缺点是,用户在创建初始对象时需要显式使用包装器类型。正如@ukasz所建议的,创建显式包装器似乎是一种方法。我可能会提供一个从包装类型到KStream
的隐式转换:
implicit def unwrap[K, V](wrapped: WrappedKStream[K, V]): KStream[K, V] = wrapped.underlying
这样,我们就可以同时使用KStream
和包装器的方法,但是包装器类方法具有优先权
这里一个明显的缺点是,用户在创建初始对象时需要显式使用包装器类型。如果原始对象上已经存在map
方法,编译器不会寻找到该方法的隐式转换。这就是算法的工作原理。除了重命名或创建自己的显式而非隐式创建的包装器类之外,我不知道如何解决这个问题。我想更全面地了解是什么决定了方法签名的唯一性。例如,我假设采用两个参数而不是一个参数的map
方法不会与现有的map
方法混淆,并且会触发查找隐式转换。我还假设接受非函数类型的map(x:Int)
是不同的。这是真的吗?这里的特殊问题是类型擦除吗?签名编译为map(f:Function)
,因此无法区分函数参数和返回类型?如果原始对象上已经存在map
方法,编译器不会寻找隐式转换到该方法的对象。这就是算法的工作原理。除了重命名或创建自己的显式而非隐式创建的包装器类之外,我不知道如何解决这个问题。我想更全面地了解是什么决定了方法签名的唯一性。例如,我假设采用两个参数而不是一个参数的map
方法不会与现有的map
方法混淆,并且会触发查找隐式转换。我还假设接受非函数类型的map(x:Int)
是不同的。这是真的吗?这里的特殊问题是类型擦除吗?签名编译为map(f:Function)
,因此无法区分函数参数和返回类型?