是否在Scala API中的选项和命名默认参数,如油和水?

我正在开发一个Scala API(对于Twilio,顺便说一句),其中操作有相当大量的参数,其中许多都有合理的默认值。为了减少打字和增加可用性,我决定使用具有命名和默认参数的case类。例如对于TwiML Gather动词:

case class Gather(finishOnKey: Char = '#', 
                  numDigits: Int = Integer.MAX_VALUE, // Infinite
                  callbackUrl: Option[String] = None, 
                  timeout: Int = 5
                  ) extends Verb

这里感兴趣的参数是callbackUrl。它是唯一的参数,在某种意义上是真正可选的,如果没有提供值,则不应用任何值(这是完全合法的)。

我已经声明它作为一个选项,以便在API的实现方面执行monadic映射例程,但这会给API用户带来一些额外的负担:

Gather(numDigits = 4, callbackUrl = Some("http://xxx"))
// Should have been
Gather(numDigits = 4, callbackUrl = "http://xxx")

// Without the optional url, both cases are similar
Gather(numDigits = 4)

就我可以做出来,有两个选项(没有双关语)来解决这个问题。或者使API客户端将隐式转换导入范围:

implicit def string2Option(s: String) : Option[String] = Some(s)

或者,我可以重新声明case类与null默认值,并将其转换为实现方面的一个选项:

case class Gather(finishOnKey: Char = '#', 
                  numDigits: Int = Integer.MAX_VALUE, 
                  callbackUrl: String = null, 
                  timeout: Int = 5
                  ) extends Verb

我的问题如下:

>有没有更优雅的方式来解决我的特殊情况?
>更一般地:命名参数是一个新的语言特性(2.8)。可以证明,选项和命名默认参数是像油和水? 🙂
>在这种情况下可能使用null默认值是最好的选择吗?

这里有另一个解决方案,部分灵感来自Chris’ answer.它也涉及一个包装器,但包装器是透明的,你只需要定义一次,并且API的用户不需要导入任何转换:

class Opt[T] private (val option: Option[T])
object Opt {
   implicit def any2opt[T](t: T): Opt[T] = new Opt(Option(t)) // NOT Some(t)
   implicit def option2opt[T](o: Option[T]): Opt[T] = new Opt(o)
   implicit def opt2option[T](o: Opt[T]): Option[T] = o.option
}

case class Gather(finishOnKey: Char = '#', 
                  numDigits: Opt[Int] = None, // Infinite
                  callbackUrl: Opt[String] = None, 
                  timeout: Int = 5
                 ) extends Verb

// this works with no import
Gather(numDigits = 4, callbackUrl = "http://xxx")
// this works too
Gather(numDigits = 4, callbackUrl = Some("http://xxx"))
// you can even safely pass the return value of an unsafe Java method
Gather(callbackUrl = maybeNullString())

为了解决更大的设计问题,我不认为选项和命名默认参数之间的相互作用是一样多的油和水,因为它可能看起来乍一看。可选字段和默认值之间有明确的区别。可选字段(即类型Option [T]之一)可能永远不具有值。另一方面,具有默认值的字段不需要将其值作为参数提供给构造函数。这两个概念因此是正交的,并且不奇怪,字段可以是可选的并且具有默认值。

也就是说,我认为一个合理的理由可以使用Opt而不是选项的这样的字段,不只是保存客户端一些打字。这样做使得API更灵活,在某种意义上,您可以用Opt [T]参数(或反之亦然)替换T参数,而不会破坏构造函数[1]的调用者。

至于使用一个空的默认值为公共字段,我认为这是一个坏主意。 “你”可能知道你期望一个null,但访问该字段的客户端可能不。即使该字段是私有的,使用null是要求麻烦的路,当其他开发人员必须维护您的代码。所有关于空值的常见参数在这里发挥作用 – 我不认为这个用例是任何特殊的异常。

[1]只要删除option2opt转换,只要需要选择[T],呼叫者就必须通过T.

http://stackoverflow.com/questions/4199393/are-options-and-named-default-arguments-like-oil-and-water-in-a-scala-api

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:是否在Scala API中的选项和命名默认参数,如油和水?