建模可选参数的最佳方法

路易斯·米格尔·梅加·苏亚雷斯

正如标题所述,在Scala中为可选参数建模的最佳方法是什么

对于可选参数,我的意思是执行函数主体不需要的值。

因为该参数存在默认值,或者根本不需要参数本身(例如,配置或调试标志)请注意,在Java上,我可能会传递null给这些参数。


这是Scala社区的常见问题解答,特别是由新手制作的。

例如:

路易斯·米格尔·梅加·苏亚雷斯

简单且社区接受的答案

总体上,社区对此达成共识,即以下列出的所有提议或替代方案都不值得其权衡取舍。
因此,建议的解决方案是仅使用Option数据类型,然后手动/显式将值包装在Some

def test(required: Int, optional: Option[String] = None): String =
  optional.map(_ * required).getOrElse("")

test(required = 100) // ""
test(required = 3, optional = Some("Foo")) // "FooFooFoo"

但是,这种方法的明显缺点是需要随时待命的样板。但是,可以说这使代码更易于阅读和理解,从而易于维护。

不过,有时您可以使用其他技术(例如默认参数或重载提供更好的API,如下所述

替代方案和建议

隐式转换

由于先前解决方案的样板,一遍又一遍地提到了使用隐式转换的常见替代方法例如:

implicit def a2opt[A](a: A): Option[A] = Some(a)

这样以前的函数可以这样调用:

test(required = 3, optional = "Foo")

不利的一面是隐式转换隐藏了一个事实,它optional是一个可选参数(当然,如果它被命名为别的),并且这种转换可以应用于代码的许多其他(非预期)部分。这就是通常不鼓励隐式转换的原因

另一个替代方案是使用扩展方法,而不是像那样隐式转换optional = "foo".opt但是,扩展方法甚至需要添加更多代码,并且现场调用仍然具有一些样板,这一事实使它像一个平庸的中间点。
(免责声明,如果你使用的猫,你已经有了这样的扩展方法的范围.some,所以你可能需要使用)

默认参数

该语言提供了为函数的参数提供默认值的支持,这样,如果未传递默认值,则编译器将插入默认值。

可能有人认为这应该是对可选参数建模的最佳方法。但是,他们有三个问题。

  1. 您不一定总是具有默认值,有时您只想知道该值是否已传递。例如,一个标志。

  2. 如果它在自己的参数组上,则仍然需要添加看起来很丑陋的空括号(这当然是主观意见)

def transact[A](config: Config = Config.default)(f: Transaction => A): A

transact()(tx => ???)
  1. 默认参数只能有一个重载。
object Functions {
  def run[A](query: Query[A], config: Config = Config.default): A = ???
  def run[A](query: String, config: Config = Config.default): A = ???
}

错误:在对象函数中,方法运行的多个重载替代方法定义了默认参数。

超载

另一个常见的解决方法是提供该方法的重载版本。例如:

def test(required: Int, optional: String): String =
  optional * required

def test(required: Int): String =
  test(required, optional = "")

这一优点是,它封装了样板的按定义站点而不是按请求站点;还使代码更易于阅读,并得到工具的良好支持。
然而,最大的缺点是,如果您有多个可选参数,则无法很好地扩展。例如,对于三个参数,您需要七个7重载。

但是,如果您有许多可选参数,则最好只请求一个Config/Context参数并使用Builder可能会更好

生成器模式。

def foo(data: Dar, config: Config = Config.default)

// It probably would be better not to use a case class for binary compatibility.
// And rather define your own private copy method or something.
// But that is outside of the scope of this question / answer.
final case class Config(
    flag1: Option[Int] = None,
    flag2: Option[Int] = None,
    flag3: Option[Int] = None
) {
  def withFlag1(flag: Int): Config =
    this.copy(flag1 = Some(flag))

  def withFlag2(flag: Int): Config =
    this.copy(flag2 = Some(flag))

  def withFlag3(flag: Int): Config =
    this.copy(flag3 = Some(flag))
}

object Config {
  def default: Config = new Config()
}

请求本地支持

关于贡献者的论述,已建议为此用例添加语言级别或stdlib级别的支持。但是,由于上述相同的原因,所有这些都已被丢弃。

此类建议的示例:

结语

与往常一样,根据您的具体情况和要提供的API选择要使用的技术。


斯卡拉3

也许引入并集类型可以为编码可选参数提供更简单的方法?

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在C ++中处理可选参数/默认值的最佳方法

来自分类Dev

建模gRPC消息的最佳方法

来自分类Dev

Guava可选作为可选参数的方法参数

来自分类Dev

Guava可选作为可选参数的方法参数

来自分类Dev

循环(可选)方法参数

来自分类Dev

设置可选的方法参数?

来自分类Dev

使用可选参数进行 POST 的最佳实践

来自分类Dev

可以使用可选参数为JSNI函数建模吗?

来自分类Dev

建模无向图的最佳方法

来自分类Dev

在Firebase中建模数据的最佳方法

来自分类Dev

为带有可选参数的最终私有字段设置默认实例的最佳方法是什么?

来自分类Dev

使用Java中的可选参数获取第一个非null值的最佳方法

来自分类Dev

Java方法参数是否可选?

来自分类Dev

可选参数和方法重载

来自分类Dev

使用可选参数的方法重载

来自分类Dev

具有可选参数的方法

来自分类Dev

编写条件可选构造函数的最佳方法

来自分类Dev

为订阅邮件服务的配额系统建模的最佳方法

来自分类Dev

在python中为JSON数据建模的最佳方法

来自分类Dev

在Django网站上存储/建模游戏数据的最佳方法?

来自分类Dev

为订阅邮件服务的配额系统建模的最佳方法

来自分类Dev

Swift和最佳用例中可选和非可选函数参数之间的语义

来自分类Dev

抽象方法中的可选参数?是否可以?

来自分类常见问题

Java方法链接(可选)基于参数

来自分类Dev

带可选参数的VBA包装方法

来自分类Dev

检查可选的多参数委托方法

来自分类Dev

使用Moq模拟使用可选参数的方法

来自分类Dev

Specman是否支持方法的可选参数?

来自分类Dev

将可选参数传递给方法