斯卡拉;您可以将多个参数定义为一个

时间:2012-07-15 20:19:29

标签: scala functional-programming

您可以定义一组变量供以后使用吗?

以下是一些突出我意图的伪代码:

def coordinates = x1, y1, x2, y2

log("Drawing from (%4.1f, %4.1f) to (%4.1f, %4.1f)".format(coordinates))
canvas.drawLine(coordinates, linePaint)

这是一个包含重复代码的工作示例。

log("Drawing from (%4.1f, %4.1f) to (%4.1f, %4.1f)".format(x1, y1, x2, y2))
canvas.drawLine(x1, y1, x2, y2, linePaint)

3 个答案:

答案 0 :(得分:6)

是的,你可以,虽然语法可以说是可怕的笨重,并且有一些限制,起初可能看起来有点武断。诀窍是将方法转换为函数(称为“eta扩展”),然后使用该函数的tupled方法来获取可应用于元组的内容。

假设你有一个这样的类:

class Foo {
  def f(a: String, b: String) = "%s, %s".format(b, a)
  def g(x: Int, y: Int, z: Int) = x + y * z
}

一个例子:

val foo = new Foo

您想要使用Foo方法的一些数据:

val names = ("John", "Doe")
val nums = (42, 3, 37)

你不能只写foo.f(names)foo.g(nums),因为类型不符合参数列表,而元组在Scala中是不同的东西。但您可以写下以下内容:

scala> (foo.f _).tupled(names)
res0: String = Doe, John

scala> (foo.g _).tupled(nums)
res1: Int = 153

在方法将其转换为函数之后粘贴下划线(这在我看来是Scala语法中最令人困惑的小怪癖),tupled将它从具有两个(或三个)参数的函数转换为a具有单个元组参数的函数。

您可以通过定义以下辅助函数来稍微清理代码,例如:

scala> val myF = (foo.f _).tupled
myF: ((String, String)) => String = <function1>

scala> val myG = (foo.g _).tupled
myG: ((Int, Int, Int)) => Int = <function1>

scala> myF(names)
res2: String = Doe, John

scala> myG(nums)
res3: Int = 153
但是,我不确定那会好得多。

最后,您不能(方便地)在varargs方法上使用此方法 - 您不能编写以下内容:

val coordsTupleToString = ("(%4.1f, %4.1f) to (%4.1f, %4.1f)".format _).tupled

甚至只是:

val coordsToString = "(%4.1f, %4.1f) to (%4.1f, %4.1f)".format _

这是避免Scala中的varargs的另一个原因。

答案 1 :(得分:2)

看起来你需要一个元组:

val coordinates = (x1, y1, x2, y2)

或者可能是一个成熟的物体?

答案 2 :(得分:0)

现在,这可能是显而易见的,但如果只在少数情况下让你烦恼,你可以随时加强:

implicit def enhancedCanvas(canvas: Canvas) = new {
  // using bad and slow syntax. please change this in Scala 2.10.
  def drawLineC(coordinates: (Float, Float, Float, Float), paint: Paint) = {
    val (x1, y1, x2, y2) = coordinates
    canvas.drawLine(x1, y1, x2, y2, paint)
  }
}

另一种可能性,如果你疯了。 (可能是这样的增强已经在Scalaz或Shapeless中了。)

implicit def enhTuple4[A,B,C,D](t: Tuple4[A,B,C,D]) = new {
  def |<[E] (f: (A, B, C, D) => E) = f(t._1, t._2, t._3, t._4)
}

// to be used as
val coordinates = (x1, y1, x2, y2)
coordinates |< (canvas.drawLine(_, _, _, _, linePaint))