在Rails中,可以使用:
returning Person.create do |p|
p.first_name = "Collin"
p.last_name = "VanDyck"
end
避免必须这样做:
person = Person.create
person.first_name = "Collin"
person.last_name = "VanDyck"
person
我认为前一种方式更清洁,重复性更低。我发现自己在Scala项目中创建了这个方法:
def returning[T](value: T)(fn: (T) => Unit) : T = {
fn(value)
value
}
我知道由于对象倾向于不可变,它的实用性有限,但是例如使用Lift,在Mapper类上使用这种方法效果很好。
是否有Scala模拟用于“返回”,我不知道?或者,在Scala中有类似的方法可以做到这一点吗?
答案 0 :(得分:6)
你的方法看起来很好,虽然我通常通过添加副作用的方法来做到这一点,这可以包括改变内部状态(或者像println
之类的东西):
class SideEffector[A](a: A) {
def effect(f: (A => Any)*) = { f.foreach(_(a)); a }
}
implicit def can_have_side_effects[A](a: A) = new SideEffector(a)
scala> Array(1,2,3).effect(_(2) = 5 , _(0) = -1)
res0: Array[Int] = Array(-1, 2, 5)
编辑:以防万一在原始示例中这将如何有用:
Person.create.effect(
_.first_name = "Collin",
_.last_name = "VanDyck"
)
编辑:将方法的名称更改为“效果”。我不知道为什么我之前没有这样做 - 侧面效果,而不是侧效果的命名。
答案 1 :(得分:5)
无法真正改善你已经写过的东西。正如你非常正确地指出的那样,惯用的Scala倾向于支持不可变对象,所以这种东西的用途有限。
另外,作为一个单行,如果你需要它,实现自己并不是那么痛苦!
def returning[T](value: T)(fn: T => Unit) : T = { fn(value); value }
答案 2 :(得分:3)
我愿意:
scala> case class Person(var first_name: String = "", var last_name: String = "")
defined class Person
scala> Person(first_name="Collin", last_name="VanDyck")
res1: Person = Person(Collin,VanDyck)
答案 3 :(得分:2)
我不明白为什么Vasil删除了他自己的答案,但我非常喜欢(这正是我要提出的建议):
val person = Person.create
locally { import person._
first_name = "Collin"
last_name = "VanDyck"
}
person
人们一直在寻求的功能之一就是能够自动导入某些内容。如果有可能,那么你可以这样做:
def returning[T](import value: T)(fn: => Unit) : T = { fn; value }
returning(Person.create) {
first_name = "Collin"
last_name = "VanDyck"
}
目前这是不可能的,也不是Scala的路线图。但有些人一次又一次地要求这样的事情。
答案 4 :(得分:1)
另一个建议是使用forward pipe operator中的Scalaz。
val person = Person.create |> { p =>
p.firstName = "Collin"
p.lastName = "VanDyck"
p // or p.saveMe
}
不同之处在于,如果要分配值,则必须自己返回值。如果您不需要返回值(如初始示例中所示),则事情会更容易:
Person.create |> { p =>
p.firstName = "Collin"
p.lastName = "VanDyck"
p.save
}
然后你去。
我不愿意在我自己的代码中真正使用它(尽管我喜欢这种做法 - 但它只是在scalaz中记录,并且很难找到其他人看代码),所以我希望这些例子能够奏效。
您当然可以使用|>
定义自己的“前进和返回管道”。
class ReturningPipe[A](value: A) {
import Scalaz._
def |>>[B](f: A => B):A = value.|>(a => { f(a); value})
}
implicit def returningPipe[A](value: A) = new ReturningPipe(value)
答案 5 :(得分:1)
可以避免重复变量名称,如下所示:
val person = Person.create
locally { import person._
first_name = "Collin"
last_name = "VanDyck"
}
请注意,这仅适用于val
。此外,locally
是一个Predef方法,它有助于创建块以限制变量范围,而不会与Scala的分号推断相冲突。一旦您完成初始化人员,这将阻止导入阻止您。