Scala中方法副作用的含义

问题描述 投票:0回答:1

Martin Odersky的书“Scala编程”讲述了避免有副作用的方法。例如,以下方法具有写入标准输出流的副作用。

def printArgs(args: Array[String]): Unit = {
  args.foreach(println)
}

然后它说,更好的方法是定义一个格式化传递的args进行打印的方法,但只返回格式化的字符串,如:

def formatArgs(args: Array[String]) = args.mkString("\n")

我不明白这两种方法在概念上是如何不同的。总之,我们的目标是打印一个字符串。如果我们不在目标方法中这样做,那么客户端代码会这样做,这意味着我们只是转移代码导致从一个地方到另一个地方的“副作用”。

scala functional-programming side-effects
1个回答
5
投票

它们是不同的,因为副作用明显包含在系统最边缘的少数方法中。

副作用破坏了许多理想的特性,例如可组合性,可测试性,可维护性,可重用性,局部推理,参考透明度,纯度,等式推理等等。因此,您希望将它们包含在尽可能小的代码中。

给出一个关于可组合性的例子。如果除了将参数打印到控制台之外,还想将它们写入日志文件,该怎么办?请注意,这两者实际上完全相同,只是写入IO流,其中一个恰好连接到文件,其中一个恰好连接到终端的标准输出。

然而,你不能重复使用逻辑,你必须复制它,因为生成字符串的逻辑与打印它的逻辑混合在一起。而在第二个解决方案中,如果您有一个方法,比如将字符串记录到数据库,那么您可以简单地使用您的方法组合该方法,从参数生成字符串,以便有一个方法将您的参数记录到数据库。

关于可测试性的另一个例子:打印到终端的测试方法是一个真正的痛苦。你必须以某种方式捕获终端的输出。

测试返回字符串的方法很简单,只需将返回值与期望值进行比较即可。而且你实际上不必测试到终端的打印,因为这是Scala标准库提供的方法,该方法已经过广泛测试(如果它被破坏了,你还有更大的问题)。

请注意,在第一个解决方案中,您被迫执行测试println是否有效的重复工作,没有办法绕过它。

© www.soinside.com 2019 - 2024. All rights reserved.