scala – 改变阶级状态的惯用方法
我有几个类都扩展了相同的特性,并且共享了应该改变其状态的相互功能.但是我想知道是否有更好的方法来实现相同的功能.
例如: trait Breed case object Pincher extends Breed case object Haski extends Breed trait Foox{ def age: Int def addToAge(i: Int): Foox } case class Dog(breed: Breed,age: Int) extends Foox case class Person(name: String,age: Int) extends Foox 我希望addToAge将使用附加的int返回相同的对象, case class Dog(breed: Breed,age: Int) extends Foox{ def addToAge(i: Int) = copy(age = age + i) } case class Person(name: String,age: Int) extends Foox{ def addToAge(i:Int) = copy(age = age + i) } >有没有更好的方法来避免这种情况? 解决方法
一个可能的解决方案,可能涵盖一些用例,是使用无形库中的镜头:
import shapeless._ abstract class Foox[T]( implicit l: MkFieldLens.Aux[T,Witness.`'age`.T,Int] ) { self: T => final private val ageLens = lens[T] >> 'age def age: Int def addToAge(i: Int): T = ageLens.modify(self)(_ + i) } case class Dog(breed: Breed,age: Int) extends Foox[Dog] case class Person(name: String,age: Int) extends Foox[Person] 请注意,要创建镜头,您需要隐式MkFieldLens,因此将Foox定义为抽象类而不是特征更容易.否则你必须在每个孩子中写一些代码以提供隐含的代码. 此外,我认为没有办法避免定义一个年龄:每个孩子的Int.在构造实例时,您必须以某种方式提供年龄,例如狗(Pincher,5),所以你必须在那里有年龄的构造函数参数. 更多解释: 借用Haskell Lens tutorial:
修改部分可用于实现我们想要的年龄. 无形库提供了一种漂亮的无样板语法,用于为案例类字段定义和使用镜头.我相信The code example in the documentation是不言自明的. 以下代码来自该示例: final private val ageLens = lens[???] >> 'age def age: Int def addToAge(i: Int): ??? = ageLens.modify(self)(_ + i) addToAge的返回类型应该是什么?它应该是从中调用此方法的子类的确切类型.这通常是通过F-bounded polymorphism实现的.所以我们有以下内容: trait Foox[T] { self: T => // variation of F-bounded polymorphism final private val ageLens = lens[T] >> 'age def age: Int def addToAge(i: Int): T = ageLens.modify(self)(_ + i) } 在那里使用T作为孩子的确切类型,并且扩展Foox [T]的每个类应该将其自身提供为T(因为自我类型声明self:T =>).例如: case class Dog(/* ... */) extends Foox[Dog] 现在我们需要制作那个镜头[T]>> ‘年龄线工作. 让我们分析>>的签名查看它需要运行的方法: def >>(k: Witness)(implicit mkLens: MkFieldLens[A,k.T]): Lens[S,mkLens.Elem] >我们看到’年龄论证被隐含地转换为无形.见证.见证表示特定值的确切类型,或者换言之,表示类型级别值.两种不同的文字,例如符号的年龄和’foo,有不同的证人,因此可以区分它们的类型. Shapeless提供了一种花哨的反引号语法来获得一些值得见证的东西.对于’年龄符号: Witness.`'age` // Witness object Witness.`'age`.T // Specific type of the 'age symbol >从第1项开始,>>签名,我们需要有一个隐含的MkFieldLens,对于类T(子案例类)和字段’age: MkFieldLens[T,Witness.`'age`.T] age字段也应该具有Int类型.可以用无形的 MkFieldLens.Aux[T,Int] 并且为了更自然地提供这种隐式,作为隐式参数,我们必须使用抽象类而不是特征. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |