2012-08-09 148 views
2

请考虑下面的例子在scala中传递默认参数?

def foo(a: Int, b: Int = 100) = a + b 
def bar(a: Int, b: Int = 100) = foo(a, b) * 2 

这工作,但要注意我必须提供相同的默认值,这两种功能为b。我的目的其实是下面

def bar(a: Int, b: Int) = foo(a, b) * 2 
def bar(a: Int) = foo(a) * 2 

但是,当你有更多的可选参数,而在链条的附加功能(如巴兹,在相同的方式调用吧)这个就变得很麻烦。有没有更简洁的方式来表达这个scala?

+2

请清楚地说出你的问题:你在这里认为什么麻烦?你到底在找什么?如果你正在寻找一种更简洁的方式来编写默认参数,那么没有,并且怎么会有? – 2012-08-09 03:29:42

回答

3

我不认为有;如果您撰写foo且加倍功能:

val bar = (foo _).curried((_: Int)) andThen ((_: Int) *2) 
// (please, please let there be a simpler way to do this...) 

你失去了默认参数,因为函数对象don't have them

如果它在你的用例中是值得的,你可以创建一个包含你传递的参数的case类,而不是多个单独的参数。

case class Args(a: Int, b: Int = 100, c: Int = 42, d: Int = 69) 
def foo(args: Args) = { import args._; a + b + c + d } 
def bar(args: Args) = foo(args) * 2 
+0

完全真棒技术。每次遇到重载方法时,应由编译器自己完成:将其转换为关联的数据类和函数。对于操作,函数比方法更方便。 – ayvango 2012-08-09 12:17:31

+0

是的,我想案例分类解决方案是最好的。不过感觉这可能是一个有用的特性,可以在scala编译器中轻松实现。我想到的是这样的:def bar(a:Int,b:Int = _)= foo(a,b)* 2,scala可以检查b仅用于定义了默认值的地方所以它可以毫不含糊地解释这一点。 – user881423 2012-08-09 17:12:20

1

我建议使用Option

def bar(a: Int, b: Option[Int] = None) = b match { 
    case Some(x) => foo(a,x) * 2 
    case _ => foo(a) * 2 
} 

这将正是你想要的。另一种方法是使用可变参数。

def baz(a: Int)(b: Int*) = b.headOption match { 
    case Some(x) => foo(a,x) * 2 
    case _ => foo(a) * 2 
} 

我更喜欢第一种方式,因为很明显,参数是可选的。第二个解决方案并不是要处理Option中的包装,但签名并不清楚,只考虑集合的第一个元素。 baz(1)(2) == baz(1)(2,3,4,5)是真的。

编辑

为了使一个与Option看起来像你期望的电话,您可以使用implicits。

implicit def int2Some(i: Int) = Some(i) 

现在,您可以拨打以下功能:

bar(1,2) 
bar(1,Some(2)) 
bar(1) 
bar(1,None) 

implicit被自动调用在以往任何时候它是有用的。但是您的用户可能会感到困惑,为什么可以用Int而不是Option[Int]来调用该函数。

+0

第一个解决方案不允许你调用bar(1)。你必须说bar(1,None)。另外,以前的bar(1,2)现在需要写成bar(1,Some(2))。使用重复的参数更接近所需的语法,但我想如果你有两个或更多的可选参数,它不会工作?是的,它也有你提到的问题。 – user881423 2012-08-09 17:02:56

+0

您可以通过将其缺省设置为无来解决第一个问题。我补充说。 – 2012-08-09 20:15:51

+0

第二个问题可能通过使用隐含来解决。我也加了一个。 – 2012-08-09 20:17:40