有没有简单的方法将布尔值转换为整数?

47

我刚接触 Scala,需要将布尔值转换为整数。我知道可以使用类似 if (x) 1 else 0 这样的方法,但我想知道是否有更好的方法或语言内置的方法(例如toInt())。


没有更多的上下文,我会说这不是一个好的实践。布尔值不是整数,我不会隐式地从一个转换为另一个...我会保持转换明确,否则很容易变得非常混乱。Scala高级特性的座右铭是:“伴随着强大的力量而来的是巨大的责任” :) - GClaramunt
我认为你所要求的函数的适当名称称为“伊弗森括号”(google它)。因此,它必须是implicit def ib (b:Boolean) = if (b) 1 else 0,尽管我更喜欢muxes:def mux[T](cond: Boolean, yes: => T, no: => T) = if (cond) yes else no(Scala通过延迟的=>参数慷慨地启用了它们),从而使得mux(cond, 1,-1)代替笨重的if (cond) 1 else -1 - Val
7个回答

67

如果您想混合使用BooleanInt类型进行操作,请使用上述示例中的implicit,但不需要创建一个类:

implicit def bool2int(b:Boolean) = if (b) 1 else 0

scala> false:Int
res4: Int = 0

scala> true:Int
res5: Int = 1

scala> val b=true
b: Boolean = true


scala> 2*b+1
res2: Int = 3

使用无类别的隐式有哪些优势? - Russ Bradberry
1
@Russ Bradberry,如果您尝试@Jackson Davis的答案,则必须显式调用函数asInt进行转换,因此无法执行==> val a:Int=true,也无法执行==> (1-true)。转换不是透明的。 - Patrick
那么这会使它变成全局的吗?还是我需要做一些特殊的事情来使它成为全局的?此外,如果我像这样插入到mysql中 "insert into blah (boolVal) values (" + b + ")",它会自动假定它是int版本而不是bool版本吗? - Russ Bradberry
@Russ Bradberry。在您的情况下,您将一个字符串与布尔值连接起来,因此编译器无法确定您想要整数而不是布尔值。您可以将该值转换为整数:"insert into blah (boolVal) values (" + (b:Int) + ")" - Patrick
1
@Russ Bradberry 这不是全局的,你可以将你的 implicits 放入一个对象中,然后在需要进行一些转换时导入它们。 - Patrick
1
请添加 import scala.language.implicitConversions - http://docs.scala-lang.org/tutorials/tour/implicit-conversions.html。 - prayagupa

17

你可以使用隐式转换轻松完成此操作:

class asInt(b: Boolean) {
  def toInt = if(b) 1 else 0
}

implicit def convertBooleanToInt(b: Boolean) = new asInt(b)

然后,你会得到类似下面的东西

scala> false toInt
res1: Int = 0

5
这项伟大的技术被称为“优化我的库”。 - David Crawshaw

16

在使用 implicit 的情况下可能是最好的选择,但如果你想要从 boolean 快速粗略地转换为 int,可以使用 boolean.compare(false)


1
注意:正如@KristjanVeskimäe所评论的那样,compare并不保证返回1,只能保证返回一个正数-参见 https://docs.oracle.com/javase/7/docs/api/java/lang/Boolean.html#compare(boolean,%20boolean) - Suma

7

实际上,我希望它是if (x) 1 else 0,而不是if (x) 0 else 1

这就是为什么你应该编写自己的转换函数。整数并不是布尔值,如果出于某种原因您想将布尔值存储为整数,则应该制定自己的标准,以表示真和假。

布尔值“true”不是数字,它是布尔类型的一个实例。例如java.lang.Boolean.TRUE。它可以在内部作为整数存储,但这是不应泄漏到语言中的实现细节。

我会说if (x) 0 else 1是首选的转换方法。它简单又快速。

如果您想使用更一般的模式匹配方法,也可以编写x match {case true => 0; case false => 1}


1
好的,这个想法是将它转换为C标准的0=false,1=true。但我为什么要使用match而不是三元if else呢? - Russ Bradberry

7

自从Scala 2.10版本以后,Jackson Davis的解决方案更常使用隐式类来实现:

implicit class BoolToInt(val b:Boolean) extends AnyVal {
  def toInt: Int = if (b) 1 else 0
  def * (x:Int): Int = if (b) x else 0
}

为了更加方便,我还添加了一个乘法运算符,因为对我来说,将布尔值转换为整数最常见的用途就是这个。我更喜欢这种方式,而不是将转换本身变得隐式(由Patrick提供的解决方案),因为那样会失去我想要的更多类型控制。

6
如果您不想采取隐式方式,那么这可能会有用:
var myBool:Boolean = true
myBool: Boolean = true

myBool.compare(false)
res3: Int = 1

myBool = false
myBool: Boolean = false

myBool.compare(false)
res3: Int = 0

4
我一开始也是这么想的,但是“compare”函数的契约只保证在true.compare(false)时返回一个正数。因此,有可能某个JVM实现返回大于1的值。 - Kristjan Veskimäe
这与Paul Murray的答案有何不同? - Suma

0

在 Paul 和 Gaurav 的回答基础上,最接近内置的可能是 b.compare(false).sign。这保证了你得到的是 0 或 1,并且可以说传达了 Iverson 括号的意图。

总的来说,我同意一些评论认为,与其使用分支结构,不如使用直线方法调用更好。这就是为什么 API 提供了像 getOrElse 这样的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接