簡単な解決策は、デフォルトの場合のために、独自のSelector
インスタンスを提供することです:
class DefaultSelector[R <: HList, K] extends Selector[R, K] {
type Out = Option[Nothing]
def apply(l: R): Out = None
}
def get[K, V](k: K)(
implicit sel: Selector[R, K] = new DefaultSelector[R, K]
): sel.Out = sel(r)
しかし、そのコードでScalaのコンパイラーは、デフォルトの場合の結果のためにTypeTag
Sを提供する難しさを有することができます。だから、何Selector
が見つからない場合にも、None: Option[Nothing]
にデフォルト設定されます新しい型クラスDefaultSelector
を、書くことができることを修正するための
:
import shapeless._
import shapeless.ops.record._
trait DefaultSelector[R <: HList, K] {
type Out
def apply(r: R): Out
}
sealed trait LowPriorityDefaultSelector {
type Aux[R <: HList, K, V] = DefaultSelector[R, K] { type Out = V }
case class Impl[R <: HList, K, V](get: R => V) extends DefaultSelector[R, K] {
type Out = V
def apply(r: R): Out = get(r)
}
implicit def default[R <: HList, K, V](
implicit ev: Option[Nothing] =:= V // tricking Scala's implicit resolution
): Aux[R, K, V] =
Impl[R, K, V](Function.const(None))
}
object DefaultSelector extends LowPriorityDefaultSelector {
implicit def existing[R <: HList, K, V](
implicit sel: Selector.Aux[R, K, V]
): Aux[R, K, V] =
Impl[R, K, V](sel.apply)
}
その後get
関数は次のようになります。
def get[K, V](k: K)(implicit sel: DefaultSelector[R, K]): sel.Out = sel(r)
結果(両方のソリューション)次のとおりです:
scala> get(Ti)
res0: Option[Int] = Some(4)
scala> get(Ta)
res1: Option[String] = Some(plif)
scala> get(To)
res2: Option[Nothing] = None
クラス「X」はどのように見えますか?ところで、すべての必要なインポートステートメントを提供するときにコードを試す方が簡単です。 – devkat
私は質問を簡略化して、重要な部分に焦点を当てています。うまくいけば、それは簡単に答えるはずです。 – arnfred
それはあなたの問題を解決しませんが、あなたの元の質問については: 'X'では' K'だけ 'k 'をタイプするので、' V'と 'M'は知られていないので、暗黙のうちに。しかし、合併はすぐに 'V 'を使用しようとするので、うまくいきません。私はそれを次のようにコンパイルすることに成功しました: 'クラスX [K <:T、OV、V、M <:HList>(val k:K)(暗黙のs1:Selector.Aux [AR、K、オプション:[M]、[K]、[V]、オプション:[V] )はA [K、V] 'を拡張する。 's1'は' R'から 'V'を計算し、' ev'は 'Option'を展開して、'合併 'と 's'に行きます。 – Kolmar