实现接受多种类型的函数的最佳方法

时间:2018-03-20 22:09:04

标签: scala implicit-conversion

鉴于scala中没有Union,

我有三个函数接受不同的参数,但在其他方面完全相同。如何不像我现在那样重复自己,最好地实现这一点?

  import scala.sys.process._

  def function1(command:String):String = {
    ...
    command.!! // scala sys process execution
  }

  def function2(command:Seq[String]):String = {
    ...
    command.!! // scala sys process execution
  }

  def function3(command:ProcessBuilder):String = {
    ...
    command.!! // scala sys process execution
  }

2 个答案:

答案 0 :(得分:3)

import scala.sys.process._加载的隐式转换会从StringSeq[String]转换为ProcessBuilder,这样就可以执行!在这两种类型中,您可以使用相同的隐式转换来调用任何这些类型的函数

import scala.sys.process._
function3(Seq(""))
function3("")
def function3(command:ProcessBuilder):String = {
    ...
    command.!!
  }

此代码应该编译,您不需要function1function2。如果import scala.sys.process._不在function2 CALL的范围内,这将无效。

您可以在scala.sys.process中的包对象中找到隐式定义,如果您查看它,您会看到正在扩展ProcessImplicits,这是定义隐式转换

答案 1 :(得分:1)

我不知道你为什么在!!上定义了String,所以我无法帮助你。但是,让我们说你所做的就是使用toString。然后你的方法适用于任何支持toString的类型,在Scala中它实际上就是一切。所以只需要Any

def function(command: Any): String = {
  // Do something with command.toString
}

如果您确实需要针对不同类型的不同情况,可以使用case classes并根据不同类型进行调度。

sealed trait Foo
case class FooString(value: String)
case class FooSeq(value: Seq[String])
case class FooPB(value: ProcessBuilder)

def function(arg: Foo): String = {
  arg match {
    case FooString(str) => "It's a string!"
    case FooSeq(str) => "It's a sequence!"
    case FooPB(str) => "It's a process builder!"
  }
}

由于您的特征是sealed,如果您忘记了模式匹配中的任何情况,您将收到编译器警告。因此,您可以安全地处理每个案例,并确信您已经这样做了。

总之,如果您想支持多种类型,请查看您所需的功能是否以常用超类型提供(在上面的示例中为Any)。这可能是特质或父类。常见的候选人是SeqIterable。如果您需要基于少数几种类型的不同行为,请定义一个密封的特征和一些继承它的案例类,这样您就可以对所有不同的可能性进行模式匹配。