【问题标题】:Infer common super-type推断常见的超类型
【发布时间】:2017-03-23 16:33:27
【问题描述】:

这就是我想要做的事情

  def merge[A, B, C](eithers: Either[A,B]*)(implicit ev1: A <:< C, ev2: B <:< C): Seq[C] =
     eithers.flatMap(_.fold(Option[C](_), Option[C](_)))

基本上,我想将Either[A,B] 的列表“展平”为Seq[C],其中C 是A 和B 的常见超类型(显然Any 除外)。

例如:

  trait Foo
  class Bar extends Foo
  class Baz extends Foo

  merge(Left[Bar, Baz](new Bar), Right[Bar, Baz](new Baz)) 

这不起作用:( 它说Cannot prove that Baz &lt;:&lt; C

但是,这确实有效:

  merge[Bar, Baz, Foo](Left[Bar, Baz](new Bar), Right[Bar, Baz](new Baz))
  res7: Seq[Foo] = ArrayBuffer(Bar@613f7eb7, Baz@565aa4ac)

所以,问题是有人可以用某种技巧让它推断出常见的超类型,这样我就不必像这样拼出来了吗? 或者,至少,一种仅使用一个类型参数的方法(我不介意指定结果的类型,因为我必须拼出传入数据的类型)。

我知道做后者的一种方法是将它分配给一个变量:

val merged: Seq[Foo] = merge(Left[Bar, Baz](new Bar), Right[Bar, Baz](new Baz)) 

这行得通,但对我来说不太合适,因为我讨厌声明只使用一次的变量。理想情况下,我想做这样的事情:

merge(input)
  .filter(doILikeIt)
  .map(doSomethingInteresting)
// etc. 

有什么想法吗?

【问题讨论】:

  • 为什么不使用Either[A, B] extends Either[C, C]这个事实,因为差异?

标签: scala generics type-inference


【解决方案1】:

有一个简单的解决方案,使用方差:

def merge[C](eithers: Either[C, C]*): Seq[C] = eithers.map(_.fold(x => x, x => x))

【讨论】:

    【解决方案2】:

    使用类型边界而不是隐式参数对我有用:

    def merge[A <: C, B <: C, C](eithers: Either[A,B]*): Seq[C] =
      eithers.flatMap(_.fold(Option[C](_), Option[C](_)))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多