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

Best way to implement a function that accepts multiple types

考虑到 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
  }

我不知道你为什么要在 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)。这可能是一个特征或 parent class。常见的候选者是 SeqIterable。如果您需要基于 select 几种类型的不同行为,请定义一个密封特征和一些从它继承的 classes,这样您就可以对所有不同的可能性进行模式匹配。

有一个从 import scala.sys.process._ 加载的隐式转换,它将从 StringSeq[String] 转换为 ProcessBuilder,这使得执行 ! 在这两种类型中,您可以使用相同的隐式转换来调用带有任何这些类型的 function3

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

此代码应该可以编译,您不需要 function1function2。如果 import scala.sys.process._ 不在 function2 调用的范围内,这将不起作用。

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