2017-01-26 8 views
1

私はkafka-streamsライブラリ用のScalaラッパーを作成しています。基本的なアプローチは、KStreamのようなkafka-streamsクラスから暗黙の変換を提供して、豊富なKStreamOpsクラスにすることです。ScalaはJava 8 Lambdaへの暗黙的な変換を優先させることができますか?

たとえば、KStreamは以下map署名を提供する:KeyValueMapperは(Scalaの観点から)署名付きSAM (K, V) => KeyValue[K1, V1]ある

<K1, V1> KStream<K1, V1> map(KeyValueMapper<K, V, KeyValue<K1, V1>> mapper) 

。ここmapは、ユーザーが「doesnのようにkafka-streams固有KeyValue型にそれを変換Tuple2とハンドルを返す関数を期待していること

class KStreamOps[K, V](underlying: KStream[K, V]) { 
    def map[K1, V1](f: (K, V) => (K1, V1)): KStream[K1, V1] = 
    underlying.map { (k, v) => 
     val tuple = f(k, v) 
     KeyValue.pair(tuple._1, tuple._2) 
    } 
} 

は注意:ここで

map方法を提供するKStreamOpsの最小限の実装です直接KeyValueと対話する必要があります。

私は暗黙の型変換を提供:

implicit def ops[K, V](kstream: KStream[K, V]): KStreamOps[K, V] = new KStreamOps[K, V](kstream) 

をしかし、私は次のようなコードで私の新しいmapを使用しようとすると:

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)) 

したがって、コンパイラはを使用しようとしています関数の出力がTuple2であると予想する私のKStreamOps#mapの代わりに、KeyValueが返されると予想されるSAMを使用して、を返します。

私のメソッドの名前をKStreamOps#map1に変更し、stream.map1を呼び出すと、暗黙の変換が期待通りに機能し、コードがコンパイルされます。

コンパイラは、正しいシグネチャの機能を持つメソッドを取得する暗黙の変換が存在することをコンパイラが認識できないのはなぜですか?関数の戻り値の型は考慮されていませんか? SAMはいつも勝つだろうか?

私はこれをScala 2.11.8で、-Xexperimentalフラグをオンにしてテストしています。

+1

コンパイラは、元のオブジェクトにそのようなメソッドが既に存在する場合、 'map'メソッドを持つものへの暗黙的な変換を探しません。これは単にアルゴリズムがどのように機能するかです。暗黙のうちに明示的に作成された独自のラッパークラスの名前変更や作成を除いて、これを回避する方法は不明です。 –

+0

メソッドシグネチャの一意性を決定する要素をより完全に理解したいと思います。私は 'map'メソッドが、1つではなく2つの引数をとると仮定します。たとえば、既存の' map'メソッドと混同しないで暗黙の変換を探します。私はまた、非関数型を取る 'map(x:Int)'が別個であると仮定します。本当?ここでの特定の問題は、型が消去されているか、シグネチャが 'map(f:Function)'にコンパイルされているため、関数のパラメータと戻り値の型を区別できないのでしょうか? –

答えて

0

@Łukaszが示唆しているように、明示的なラッパーを作成することは、ここに行く方法のようです。そして、私はおそらく私のラッパーからの暗黙的な変換を提供しますバックKStreamに入力します。

implicit def unwrap[K, V](wrapped: WrappedKStream[K, V]): KStream[K, V] = wrapped.underlying 

をこの方法で、我々はKStreamの、利用可能なラッパーの両方の方法があるでしょうが、ラッパークラスのメソッドが優先され得ます。

ここで明らかな欠点は、初期オブジェクトの作成時にユーザーがラッパータイプを明示的に使用する必要があることです。

関連する問題