加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 为“免费”获取案例类的部分构造函数

发布时间:2020-12-16 08:53:45 所属栏目:安全 来源:网络整理
导读:考虑定义两个属性的抽象类 abstract class A { def a: Int def b: Int // real A has additional members} 这是各种案例类的基类,如 case class Foo(a: Int,b: Int) extends Acase class Bar(a: Int,b: Int) extends A// and many more 目标:我最终希望能够
考虑定义两个属性的抽象类

abstract class A {
  def a: Int
  def b: Int
  // real A has additional members
}

这是各种案例类的基类,如

case class Foo(a: Int,b: Int) extends A
case class Bar(a: Int,b: Int) extends A
// and many more

目标:我最终希望能够以两种方式创建上述案例类的实例,即

val b1 = Bar(1,2)
val b2 = Bar(1) has 2
assert(b1 == b2) // must hold

方法:因此定义一个定义has的辅助类似乎是合理的,这允许我部分构造As

case class PartialA(f: Int => A) {
  def has(b: Int) = f(b)
}

问题:当前机器不允许调用Bar(1),因为这实际上是对Bar.apply(1)的调用,也就是说,由编译器生成的对象Bar定义的方法apply.

如果我可以强制编译器生成Bar对象,那将是很好的,因为对象Bar扩展了PartialAConstructor,其中

abstract class PartialAConstructor{
  def apply(a: Int,b: Int): A // abstract,created when the compiler creates
                               // object Bar
  def apply(a: Int) = PartialA((b: Int) => apply(a,b))
}

但是,似乎不可能影响案例类的伴随对象的生成.

期望的属性:

>案例类:Foo,Bar等应该保留案例类,因为我想使用编译器生成的好东西,例如结构相等,复制和自动生成的提取器.
>“完全”结构相等:将案例类定义为

case class Bar(a: Int)(val b: Int)

不是一个选项,因为编译器生成的equals方法只考虑第一个参数列表,因此以下将错误地保存:

assert(Foo(1)(0) == Foo(1)(10))

>尽可能少的代码重复:例如,当然可以定义一个

def Bar(a: Int) = PartialA((b: Int) => Bar(a,b))

但是,对于扩展A的每个案例类,都必须这样做,即Foo,Bar等.

解决方法

您可能非常依赖于currrying(以及Foo.apply,因为任何方法,将自动升级到函数)和一个小帮助器来增强语法:

object partially {
  def apply[A1,A2,R]( f: (A1,A2) => R ) = f.curried
  def apply[A1,A2) => R,a1: A1 ) = f.curried( a1 )

  def apply[A1,A3,A3) => R ) = f.curried
  def apply[A1,A3) => R,a1: A1 ) = f.curried( a1 )
  def apply[A1,a1: A1,a2: A2 ) = f.curried( a1 )( a2 )


  def apply[A1,A4,A4) => R ) = f.curried
  def apply[A1,A4) => R,a2: A2 ) = f.curried( a1 )( a2 )
  def apply[A1,a2: A2,a3: A3 ) = f.curried( a1 )( a2 )( a3 )
  // ... and so on,potentially up to 22 args
}

然后你可以这样做:

scala> val x = partially(Foo)(1)
x: Int => Foo = <function1>
scala> x(2)
res37: Foo = Foo(1,2)

如果你真的想要使用你的has方法(而不是直接应用函数),那么在它上面引入一个隐式类:

implicit class Func1Ops[-A,+R]( val f: A => R ) extends AnyVal { 
  def has( arg: A ): R = f( arg ) 
}

现在你可以这样做:

scala> val x = partially(Foo)(1)
x: Int => Foo = <function1>

scala> x has 2
res38: Foo = Foo(1,2)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读