在非case类上使用Lens,通过Scala中的构造函数扩展某些内容

在非case类上使用Lens,通过Scala中的构造函数扩展某些内容,scala,scalaz,lenses,Scala,Scalaz,Lenses,我可能想得不对,但在Scala中,我很难在用构造函数扩展的类上使用镜头 class A(c: Config) extends B(c) { val x: String = doSomeProcessing(c, y) // y comes from B } 我正在尝试创建一个镜头来改变这个类,但在这样做时遇到了困难。以下是我希望能够做到的: val l = Lens( get = (_: A).x, set = (c: A, xx: String) => c.co

我可能想得不对,但在Scala中,我很难在用构造函数扩展的类上使用镜头

class A(c: Config) extends B(c) {
    val x: String = doSomeProcessing(c, y) // y comes from B
}
我正在尝试创建一个镜头来改变这个类,但在这样做时遇到了困难。以下是我希望能够做到的:

val l = Lens(
    get = (_: A).x,
    set = (c: A, xx: String) => c.copy(x = xx) // doesn't work because not a case class
)
我认为这一切归结为找到一个好的方法来改变这个类

我有什么选择来实现这样的目标?我从两个方面考虑这个问题:

将初始化逻辑移到伴随对象a中,并将其移到def applyc:Config中,然后将a类更改为从伴随对象创建的case类。不幸的是,我不能在我的对象中从Bc扩展,因为我只能在其apply方法中访问c。 将x设为变量,然后在Lens.set just a.clone中设置x值,然后返回克隆实例。这可能会起作用,但看起来相当难看,更不用说将其更改为var可能会让人大吃一惊。 使用一些反射魔法进行复制。如果我可以避免的话,我不太喜欢这种方法。
你觉得怎么样?我的想法是不是真的错了,或者这个问题有一个简单的解决办法吗?

这取决于你希望你的镜头做什么。镜头法则指定setter应该替换getter将获得的值,同时保持其他所有内容不变。现在还不清楚这里的其他一切意味着什么

设置时是否希望调用B的构造函数?您知道doSomeProcessing方法调用了哪个吗

如果所有的方法都是纯函数的,那么您可以考虑类A有两个字段,即:C:COFIG和X:String,因此您不妨将它替换为带有这些字段的CASE类。但是,在尝试实现仅使用c作为参数的构造函数时,这将导致问题

我要做的是做如下:

class A(val c: Config) extends B(c) {
  val x = doSomeProcessing(c, y)
  def copy(newX: String) = new A(c) { override val x = newX }
}
除了copy方法中的命名参数外,您编写的镜头现在完全有效

如果在中有依赖于x的其他属性,请小心,这可能会为这些属性创建具有意外值的实例

如果您不希望c成为类a的属性,那么您将无法克隆它,或者在不向构建器提供配置的情况下重建实例,而构建器不能提供配置,因此您的目标似乎无法实现