如果仅为无,则如何分配给选项

时间:2014-01-04 09:56:43

标签: ruby scala

在红宝石中,可以这样做:

first ||= number

first 只有在 nil

时才会获得数字的值

如何在scala中做类似的事情?

到目前为止,我已经想出了这个并且看起来不像红宝石那么好。

var first: Option[Int] = None
...
first = if (first == None) Option(number) else first
// or
first = Some(first.getOrElse(number))

3 个答案:

答案 0 :(得分:5)

有一个scalaz运算符:

import scalaz._, Scalaz._

none[Int] <+> 1.some
// Some(1)

2.some <+> 1.some
// Some(2)

您可以使用a <+>= b代替a = a <+> b

var i = none[Int] // i == None
i <+>= 1.some // i == Some(1)
i <+>= 2.some // i == Some(1)

另请参阅scalaz cheatsheet中的加[F [_]]

Option plus implementedorElse

对于集合(ListVectorStream等),Plus实现为append

Vector(1, 2) <+> Vector(3, 4)
// Vector(1, 2, 3, 4)

我找不到按照你想要的方式组合Option[T]T的方法,但你可以这样编写这样的方法:

implicit class PlusT[T, M[_]: Plus : Applicative](m: M[T]) {
  def ?+?(t: T) = m <+> t.point[M]
}

none[Int] ?+? 1
// Some(1)

2.some ?+? 1
// Some(2)

var i = none[Int] // i == None
i ?+?= 1 // i == Some(1)
i ?+?= 2 // i == Some(1)

您可以将此方法重命名为||并像||=一样使用它,就像在Ruby中一样,但此名称可能会让其他开发者感到困惑 - 已经有方法|| Boolean

答案 1 :(得分:3)

这不是最佳做法或任何事情,但这里可以做类似的事情:

scala> implicit class RubyFriend[T](val value: Option[T]) extends AnyVal {
     |   def ||=(alt: T): Option[T] = value orElse Some(alt)
     | }
defined class RubyFriend

scala> var something: Option[Int] = None
something: Option[Int] = None

scala> something = something ||= 5
something: Option[Int] = Some(5)

scala> something ||= 4
res11: Option[Int] = Some(5)

scala> (None: Option[Int]) ||= 3
res12: Option[Int] = Some(3)

我们创建了从OptionRubyFriend的隐式转换,其中||=方法。这是一个皮条客我的图书馆模式。据我所知,在Scala赋值中它无法真正分配给原始变量的唯一区别是不能重载。

总体上尽量避免Scala中的变种。

这是另一种尝试,使其更像Ruby:

scala> import scala.language.implicitConversions
import scala.language.implicitConversions

scala> implicit class RubyFriend[T](var value: Option[T]) {
     |   def ||=(alt: T): Unit = value = value orElse Some(alt)
     | }
defined class RubyFriend

scala> implicit def ruby2Option[T](smth: RubyFriend[T]): Option[T] = smth.value
ruby2Option: [T](smth: RubyFriend[T])Option[T]

scala> var ropt: RubyFriend[Int] = None
ropt: RubyFriend[Int] = RubyFriend@2d483fef

scala> ropt.value
res0: Option[Int] = None

scala> val opt: Option[Int] = ropt
opt: Option[Int] = None

scala> ropt ||= 6

scala> ropt.value
res2: Option[Int] = Some(6)

scala> val opt: Option[Int] = ropt
opt: Option[Int] = Some(6)

scala> ropt ||= 7

scala> ropt.value
res4: Option[Int] = Some(6)

这使得包装类围绕Option并且隐式地来回转换。同时,可选值显示为可变字段(yikes)。

这两个例子只是为了展示Scala中可能的不是一个好方法:)。

@senia建议的第一个例子的“改进”:

scala> implicit class RubyFriend[T](val value: Option[T]) extends AnyVal {
     |   def ||(alt: T): Option[T] = value orElse Some(alt)
     | }
defined class RubyFriend

scala> var something: Option[Int] = None
something: Option[Int] = None

scala> something ||= 5

scala> something
res1: Option[Int] = Some(5)

scala> something ||= 6

scala> something
res3: Option[Int] = Some(5)

答案 2 :(得分:3)

我不知道为什么其他海报删除了他的答案,但我会采取评论中建议的方法:

first = first orElse Some(number)