Scala

时间:2018-01-01 17:07:21

标签: scala functional-programming side-effects

Martin Odersky的书&#Sc; Programming in Scala'谈到避免有副作用的方法。 例如,以下方法具有写入标准输出流的副作用。

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

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

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

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

2 个答案:

答案 0 :(得分:5)

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

副作用会破坏许多所需的属性,例如可组合性,可测试性,可维护性,可重用性,局部推理,参照透明度,纯度,等式推理等等。所以,你希望将它们包含在尽可能小的代码中。

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

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

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

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

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

答案 1 :(得分:0)

在函数式编程中,我们努力使用函数效应而不是副作用。有关Scala中功能效果的说明,请参见以下内容(下载以获得完美质量):

enter image description here

enter image description here

https://www.slideshare.net/pjschwarz/functional-effects-part-1 https://www.slideshare.net/pjschwarz/functional-effects-part-2