gpt4 book ai didi

scala - 在 Scala 中实现 ifTrue、ifFalse、ifSome、ifNone 等以避免 if(...) 和简单的模式匹配

转载 作者:行者123 更新时间:2023-12-04 09:28:15 26 4
gpt4 key购买 nike

在 Scala 中,我逐渐失去了 Java/C 以面向控制流的方式思考的习惯,并习惯于先获取我感兴趣的对象,然后通常应用类似 match 的东西。或 map()foreach()用于收藏。我非常喜欢它,因为它现在感觉像是一种更自然、更直接的方式来构建我的代码。

渐渐地,我希望我能以同样的方式为条件编程;即先获取 bool 值,然后match它做各种事情。一个成熟的match但是,对于这项任务来说似乎有点矫枉过正。

比较:

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如果它被定义,还有一些 doY如果不是。就像是:
val ok = resultOpt ifSome { result =>
println("Obtained: " + result)
updateUIWith(result) // returns Boolean
} else {
numInvalid += 1
println("missing end result")
false
}

对我来说,这(仍然?)看起来比成熟的 match 更好。 .

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

最佳答案

第一:我们可能无法重用 else , 因为它是一个关键字,并且使用反引号来强制它被视为一个标识符是相当难看的,所以我将使用 otherwise反而。

这是一个实现尝试。首先,使用 pimp-my-library 模式添加 ifTrueifFalseBoolean .它们在返回类型 R 上进行了参数化并接受单个按名称参数,如果实现指定条件,则应评估该参数。但在这样做时,我们必须允许 otherwise称呼。所以我们返回一个名为 Otherwise0 的新对象。 (为什么后面会解释为什么是 0),它将可能的中间结果存储为 Option[R] .如果当前条件( ifTrueifFalse )实现则定义,否则为空。

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")
}

但是,如果没有以下 otherwise子句,它不能返回 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 的效果被推断为命名参数的实际类型的最具体的常见父类(super class)型,例如, r在这个片段中有一个推断类型 Fruit :
class Fruit
class Apple extends Fruit
class Orange extends Fruit

val r = someTest ifTrue {
new Apple
} otherwise {
new Orange
}
apply()别名甚至允许您跳过 otherwise短代码块的方法名称:
someTest.ifTrue(10).otherwise(3)
// equivalently:
someTest.ifTrue(10)(3)

最后,这里是 Option 的相应 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这样我们就可以方便地将展开的值传递给 ifSome函数参数,但也适用于 otherwise 的函数参数关注 ifNone .

关于scala - 在 Scala 中实现 ifTrue、ifFalse、ifSome、ifNone 等以避免 if(...) 和简单的模式匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5654004/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com