在Scala中,可选参数的值是否可以依赖于另一个参数?

18

有人知道在Scala中是否可以实现这样的功能吗:

case class Thing(property:String)

def f(thing:Thing, prop:String = thing.property) = println(prop)

上述代码无法编译,会出现错误:error: not found: value thing,位于thing.property处。

以下展示了期望的行为:

f(Thing("abc"), "123") // prints "123"
f(Thing("abc"))        // prints "abc"

我意识到我可以使prop参数成为Option[String]并在函数定义中进行检查,但我想知道在2.8.0版本的新命名/默认参数支持下是否有解决办法。

3个回答

22

是的,在Scala 2.8中是可能的。以下是来自"Scala 2.8中的命名和默认参数"设计文档的引用:

由于参数的作用域延伸到所有后续参数列表(以及方法体),因此默认表达式可以依赖于前面参数列表的参数(但不能依赖于同一参数列表中的其他参数)。请注意,当使用取决于先前参数的默认值时,使用实际参数而不是默认参数。

def f(a: Int = 0)(b: Int = a + 1) = b // OK

另一个例子:

def f[T](a: Int = 1)(b: T = a + 1)(c: T = b)
// generates:
// def f$default$1[T]: Int = 1
// def f$default$2[T](a: Int): Int = a + 1
// def f$default$3[T](a: Int)(b: T): T = b

根据此,你的代码可能如下所示:
scala> case class Thing(property:String)
defined class Thing

scala> def f(thing:Thing)(prop:String = thing.property) = println(prop)
f: (thing: Thing)(prop: String)Unit

scala> f(Thing("abc"))("123")
123

scala> f(Thing("abc"))()
abc

谢谢,这正是我想要的。 - Kristian Domagala
1
将要违反DRY(不要重复自己):这太棒了。 - WestCoastProjects

2

另一个简单的解决方案就是重载该方法:

case class Thing (property: String)

def f(thing: Thing, prop: String) = println(prop)

def f(thing: Thing) = f(thing, thing.property)

如果我没记错的话,这就是C++定义可选/默认参数的方式,对吧? - Randall Schulz
我已经很久没有用C++编程了,但是你当然可以在C++或Java中完成相同的事情。 - Jesper

0

这正是 Option 的用途。您可以在方法调用之前或在方法 f 内部使用 getOrElse 方法。

scala> val abc = Some("abc")
abc: Some[java.lang.String] = Some(abc)

scala> val none: Option[String] = None
none: Option[String] = None

scala> println(abc getOrElse "123")
abc

scala> println(none getOrElse "123")
123

scala> def f(o: Option[String]) = println(o getOrElse "123")
f: (o: Option[String])Unit

scala> f(abc)
abc

scala> f(none)
123

哦,这里有一个可以通过默认参数完成的操作:

scala> case class Thing(property: String = "123")
defined class Thing

scala> def f(t: Thing) = println(t.property)
f: (t: Thing)Unit

scala> f(Thing("abc"))
abc

scala> f(Thing())
123

期望的行为可以通过简单的重载实现。我需要将该方法放在一个对象中,因为看起来REPL不允许直接重载函数声明。
scala> object O {
         def overloaded(t:Thing) = println(t.property)
         def overloaded(t:Thing,s:String) = println(s)
       }
defined module O

scala> O.overloaded(Thing("abc"), "123")
123

scala> O.overloaded(Thing("abc"))
abc

但我认为被迫提供Option而不是普通参数是一种不好的做法。 - Mikaël Mayer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接