Scala 相当于 ActiveSupport 的 Object.try in Ruby



try方法是核心Ruby的常见扩展。例如,它在Rails中默认是可用的。try只在对象不是nil (Ruby的null)时才在对象上执行方法或代码块。它的用法有三种:

  1. 在非nil对象上调用方法并返回结果:
    customer_or_nil.try(:save) .

  2. 如果结果不是nil,在表达式中链接任意代码块:
    obj.try { |non_nil_obj| do_something(non_nil_obj) }

  3. (2)的扩展,不是用于可选的处理,而是作为继续链式表达式的一种方式,其中步骤n+1中的方法需要一个必须根据步骤n的结果计算的参数:
    data.analyze.try { |result| result.compress(optimal_settings(result)) }.save

我对Scala等价的(3)或另一种Scala习语特别感兴趣,例如,这段与Apache Spark的DataFrame相关的代码:

val df = ctx.sql("select * from my_table")
df.
  repartition(max(1, df.rdd.partitions.size / 4)).
  saveAsTable("repartitioned_table")

将被重构成如下内容(使用Ruby语法)

ctx.
  sql("select * from my_table").
  try { |df| df.repartition(max(1, df.rdd.partitions.size / 4)) }.
  saveAsTable("repartitioned_table")

重构的目标是通过维护单个方法链来提高可读性,并通过将df严格限定在链中绝对需要的步骤来减少作用域污染。

注意:我对讨论使用Option进行可选处理的利弊特别不感兴趣,因为这不是这个问题所关注的try的主要用例。

不在标准库中,但是等价于3很容易编写(try是关键字,因此重命名为ap (apply的缩写)):

implicit class TryOp[A](x: A) {
  def ap[B](f: A => B): B = f(x)
}
ctx.
  sql("select * from my_table").
  ap { df => df.repartition(max(1, df.rdd.partitions.size / 4)) }.
  saveAsTable("repartitioned_table")

最新更新