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

在Scala中实现ifTrue,ifFalse,ifSome,ifNone等,以避免if(…)和简

发布时间:2020-12-16 08:52:34 所属栏目:安全 来源:网络整理
导读:在 Scala中,我逐渐失去了以控制流方式思考的 Java / C习惯,并习惯于先获取我感兴趣的对象,然后通常应用匹配或映射之类的东西收集的()或foreach().我非常喜欢它,因为它现在感觉像是一种更自然,更直接的方式来构建我的代码. 渐渐地,我希望我能以相同的方式为条
在 Scala中,我逐渐失去了以控制流方式思考的 Java / C习惯,并习惯于先获取我感兴趣的对象,然后通常应用匹配或映射之类的东西收集的()或foreach().我非常喜欢它,因为它现在感觉像是一种更自然,更直接的方式来构建我的代码.

渐渐地,我希望我能以相同的方式为条件编程;即,首先获得布尔值,然后匹配它以做各种事情.然而,一场全面的比赛对于这项任务来说似乎有点过分.

相比:

obj.isSomethingValid match {
  case true => doX
  case false => doY
}

与我接近Java的风格相比:

if (obj.isSomethingValid)
  doX
else
  doY

然后我想起了Smalltalk的ifTrue:和ifFalse:消息(及其变体).是不是可以在Scala中写这样的东西?

obj.isSomethingValid ifTrue doX else doY

与变种:

val v = obj.isSomethingValid ifTrue someVal else someOtherVal

// with side effects
obj.isSomethingValid ifFalse {
  numInvalid += 1
  println("not valid")
}

此外,这种风格是否可以用于简单的双状态类型,如Option?我知道使用Option的更惯用的方法是将其视为一个集合并在其上调用filter(),map(),exists(),但最后,我发现我想要执行一些doX,如果它是定义的,如果不是,则定义一些.就像是:

val ok = resultOpt ifSome { result =>
  println("Obtained: " + result)
  updateUIWith(result) // returns Boolean
} else {
  numInvalid += 1
  println("missing end result")
  false
}

对我而言,这(仍然?)看起来比一场成熟的比赛更好.

我提供了一个我想出的基础实现;欢迎对这种风格/技术和/或更好的实施的一般评论!

解决方法

首先:我们可能无法重用其他,因为它是一个关键字,并且使用反引号强制它被视为标识符相当难看,所以我将使用其他方式.

这是一个实施尝试.首先,使用pimp-my-library模式将ifTrue和ifFalse添加到Boolean.它们在返回类型R上进行参数化并接受单个名称参数,如果实现了指定的条件,则应对其进行评估.但在这样做的时候,我们必须允许另外一个电话.因此,我们返回一个名为OTHER0的新对象(为什么0将在后面解释),它将可能的中间结果存储为Option [R].定义当前条件(ifTrue或ifFalse)是否已实现,否则为空.

class BooleanWrapper(b: Boolean) {
  def ifTrue[R](f: => R) = new Otherwise0[R](if (b) Some(f) else None)
  def ifFalse[R](f: => R) = new Otherwise0[R](if (b) None else Some(f))
}
implicit def extendBoolean(b: Boolean): BooleanWrapper = new BooleanWrapper(b)

现在,这有效,让我写

someTest ifTrue {
  println("OK")
}

但是,如果没有以下其他条款,它当然不能返回R类型的值.所以这里是otherwise0的定义:

class Otherwise0[R](intermediateResult: Option[R]) {
  def otherwise[S >: R](f: => S) = intermediateResult.getOrElse(f)
  def apply[S >: R](f: => S) = otherwise(f)
}

当且仅当从前面的ifTrue或ifFalse获得的中间结果未定义时,它才会计算其传递的命名参数,这正是所需的.类型参数化[S>:R]具有以下效果:S被推断为命名参数的实际类型的最特定的常见超类型,例如,此片段中的r具有推断类型Fruit:

class Fruit
class Apple extends Fruit
class Orange extends Fruit

val r = someTest ifTrue {
  new Apple
} otherwise {
  new Orange
}

apply()别名甚至允许您为短代码块完全跳过其他方法名称:

someTest.ifTrue(10).otherwise(3)
// equivalently:
someTest.ifTrue(10)(3)

最后,这是选项的相应pimp:

class OptionExt[A](option: Option[A]) {
  def ifNone[R](f: => R) = new Otherwise1(option match {
    case None => Some(f)
    case Some(_) => None
  },option.get)
  def ifSome[R](f: A => R) = new Otherwise0(option match {
    case Some(value) => Some(f(value))
    case None => None
  })
}

implicit def extendOption[A](opt: Option[A]): OptionExt[A] = new OptionExt[A](opt)

class Otherwise1[R,A1](intermediateResult: Option[R],arg1: => A1) {
  def otherwise[S >: R](f: A1 => S) = intermediateResult.getOrElse(f(arg1))
  def apply[S >: R](f: A1 => S) = otherwise(f)
}

请注意,我们现在还需要otherwise1,以便我们可以方便地将unwrapped值传递给ifSome函数参数,还可以传递给ifNone后面的函数参数.

(编辑:李大同)

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

    推荐文章
      热点阅读