函数式编程中的设置器函数

3
如何在函数式编程中实现setter?我希望尊重不可变性和其他函数式编程原则。
private int age;

public void setAge(int age){

this.age=age;

}

这是否可能?如果不行,那么在函数式编程语言中如何表示程序的状态(及其变化)?


5
你需要创建一个新对象,除了它的年龄被设置为新年龄之外,其他方面都与原对象相同。 - Lee
请阅读这篇文章:http://dustinmartin.net/getters-and-setters-in-scala/。 - Artsiom Miklushou
2
为什么会有踩票?“对于可变类,我使用setter,在不可变类中应该使用什么?”- 我想这对FP新手来说是个好问题。 - senia
1
@senia:同意,我也不太确定Artsiom提供的文章与问题有什么关系(并不是说这篇文章不好——只是它与不可变类无关)。 - Travis Brown
2个回答

10

一般来说,您应该创建一个新状态而不是修改旧状态。

复制

您可以像这样使用copy方法:

case class Person(name: String, age: Int)

val youngBob = Person("Bob", 15)
val bob = youngBob.copy(age = youngBob.age + 1)
// Person(Bob,16)

scalaz镜头

您也可以使用Lens

import scalaz._, Scalaz._

val ageLens = Lens.lensu[Person, Int]( (p, a) => p.copy(age = a), _.age )

val bob = ageLens.mod(_ + 1, youngBob)
// Person(Bob,16)

请参见Learning scalaz/Lens。还有其他的Lens实现。

shapeless Lens

例如,您可以使用shapeless Lens,该Lens使用宏实现,因此您不必手动创建Lens

import shapeless._

val ageLens = Lens[Person] >> 1

val bob = ageLens.modify(youngBob)(_ + 1)
// Person(Bob,16)

参见github上的示例

另请参阅

有很多Lens的实现。请查看Scala无样版功能镜头Macrocosm


1

虽然谈论FP变异器几乎是自相矛盾的,但Scala作为一种混合面向对象和函数式语言确实有一种用于创建变异器和类似变异器方法的语法:

scala> class C1 { def x: Int = xx; def x_=(i: Int): Unit = xx = i; private var xx: Int = 0 }
defined class C1

scala> val c1 = new C1
c1: C1 = C1@1e818d28

scala> c1.x = 23
c1.x: Int = 23

scala> c1.x
res18: Int = 23

自然地,如所示,这没有任何意义,但是无论支持命名的访问器和变异器的内容是否为简单字段,变异器都可以对值施加范围约束或在值被变异时进行一些日志记录,因此它是一个相当通用的构造。

请注意,您不能仅使用变异器。它必须有一个相应的访问器。

补充说明

带有变异器但没有情况类的不可变性

scala> class C2(xInit: Int) { def this = this(0)
                              def x: Int = xx
                              def x_=(i: Int): C2 = new C2(i)
                              private var xx: Int = xInit
                            }

scala> val c2a = new C2()
c2a: C2 = C2@2f85040b

scala> val c2b = c2a.x = 23
c2b: C2 = C2@74f1bfa9

scala> c2a.x
res19: Int = 0

scala> c2b.x
res20: Int = 23

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接