Scala多重继承:区分方法参数中的Iterable和PartialFunction [英] Scala Multiple Inheritance: Differentiate between Iterable and PartialFunction in method arguments

查看:95
本文介绍了Scala多重继承:区分方法参数中的Iterable和PartialFunction的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果参数是Iterable[T1]与函数:T1 => T2

但是,许多实现Iterable的类也实现了PartialFunction

However, many classes that implement Iterable also implement PartialFunction

例如:

object FunList {
  def foo(itr: Iterable[Int]) = println("hello")
  def foo(f: (Int => Int)) = println("Goodbye")
}

scala> FunList.foo(List(1))
<console>:9: error: ambiguous reference to overloaded definition,
both method foo in object FunList of type (f: Int => Int)Unit
and  method foo in object FunList of type (itr: Iterable[Int])Unit
match argument types (List[Int])
          FunList.foo(List(1))

当前我的解决方案如下所示,但它与Iterable的子类不匹配,这些子类也不是PartialFunction的子类

currently my solution looks like this, but it does not match subclasses of Iterable which are not also subclasses of PartialFunction

case class SeqOrFun[T1, T2](f: (T1 => T2))
implicit def seqOrFun[T1, T2](f: (T1 => T2)) = SeqOrFun(f)

def unfurl[T1: Numeric, T2: Numeric](x: SeqOrFun[T1, T2], y: SeqOrFun[T1, T2]) = {
  (x.f, y.f) match {
    case (xs: Iterable[T1], ys: Iterable[T2]) => (xs, ys)
    case (xf: (T2 => T1), ys: Iterable[T2]) => (ys.map(xf), ys)
    case (xs: Iterable[T1], yf: (T1 => T2)) => (xs, xs.map(yf))
  }
}

推荐答案

由于List既是Iterable[Int]又是Int => Int,正如您所说的那样,您编写的内容本质上很繁琐.也许我读错了,但是在指定FunList.foo(List(1))打印"hello""Goodbye"的位置上,我看不到任何地方.

Since List is both Iterable[Int] and Int => Int, as you've said, what you're writing is inherently abmiguous. Perhaps I've misread, but I don't see any place at all where you've specified whether you want FunList.foo(List(1)) to print "hello" or "Goodbye".

首先,您可以在呼叫站点使用演员表.我认为您已经知道这一点,但是为了讨论方便而明确:

First, you can use a cast at the call site. I assume you already know this, but just to be explicit for the sake of discussion:

FunList.foo(List(1): Int => Int) // "hello"
FunList.foo(List(1): Iterable[Int]) // "Goodbye"

如果我们的目标是允许调用者简单地编写FunList.foo(List(1)),则可以使用

If our objective here is to allow the caller to simply write FunList.foo(List(1)), you could use the magnet pattern. This means you don't use method overloading at all; instead you write a single method, and the dispatch is done with implicit conversions.

sealed trait FooMagnet
case class HelloMagnet(itr: Iterable[Int]) extends FooMagnet
case class GoodbyeMagnet(f: Int => Int) extends FooMagnet

def foo(x: FooMagnet): Unit = x match {
  case HelloMagnet(itr) => println("hello")
  case GoodbyeMagnet(f) => println("Goodbye")
}

def a(): Unit = {
  implicit def listIsHelloMagnet(x: List[Int]): FooMagnet = HelloMagnet(x)
  FunList.foo(List(1)) // "hello"
}

def b(): Unit = {
  implicit def listIsGoodbyeMagnet(x: List[Int]): FooMagnet = GoodbyeMagnet(x)
  FunList.foo(List(1)) // "Goodbye"
}

您在这里得到的有趣的好处是,调度决策与foo实现是分离的,因为它是由您可以在任意位置定义的隐式确定的.

The fun advantage you get here is that the dispatch decision is decoupled from the foo implementation, since it's determined by those implicits which you can define wherever you like.

您也可以使用它来解决歧义问题!从前面的两个隐式开始:

You can also use this to resolve the ambiguity problem! Start with the two implicits from earlier:

implicit def iterableIsHelloMagnet(x: Iterable[Int]): FooMagnet = HelloMagnet(x)
implicit def functionIsGoodbyeMagnet(x: Int => Int): FooMagnet = GoodbyeMagnet(x)

,然后为List[Int]添加另一个隐式.

And then add another implicit specifically for List[Int].

implicit def listIsHelloMagnet(x: List[Int]): FooMagnet = HelloMagnet(x)

Scala足够聪明,可以看到第三次转换比前两次转换更加具体,因此即使它们都适用,它也将把它用于List[Int].这样我们现在可以写:

Scala is clever enough to see that this third conversion is more specific than the first two, so it will use that one for List[Int] even though they all apply. Thus we can now write:

FunList.foo(Set(1)) // "hello"
FunList.foo((_: Int) + 1) // "Goodbye"
FunList.foo(List(1)) // "hello"

而且您可以将这些隐式的定义移到被调用的库中,因此调用者要做的就是导入它们.

And you can move the definitions of those implicits into the called library, so all the caller has to do is import them.

这篇关于Scala多重继承:区分方法参数中的Iterable和PartialFunction的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆