【问题标题】:Is it possible for an optional argument value to depend on another argument in Scala可选参数值是否可能依赖于 Scala 中的另一个参数
【发布时间】:2011-03-06 16:00:48
【问题描述】:

有谁知道这样的事情在 Scala 中是否可行:

case class Thing(property:String)

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

以上代码无法编译;在thing.property 给出错误error: not found: value thing

以下显示了预期的行为:

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

我意识到我可以将 prop 参数设为 Option[String] 并检查函数定义,但我想知道是否有办法通过 2.8.0 中的新命名/默认参数支持来解决它。

【问题讨论】:

    标签: scala scala-2.8 default-value named-parameters


    【解决方案1】:

    这正是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
    

    可以通过简单的重载来实现预期的行为。我需要将该方法放在object 中,因为看起来 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 而不是普通参数是不好的做法。
    【解决方案2】:

    是的,在 Scala 2.8 中是可能的。这是"Named and Default Arguments in 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
    

    【讨论】:

    • 谢谢,这正是我所追求的。
    • 要违反 DRY(不要重复自己):这太棒了。
    【解决方案3】:

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

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

    【讨论】:

    • 如果我没记错的话,这就是 C++ 定义可选/默认参数的方式,对吧?
    • 我用 C++ 编程已经很久了,但你当然可以用 C++ 或 Java 做同样的事情。
    猜你喜欢
    • 2021-07-05
    • 2016-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    相关资源
    最近更新 更多