2015-05-22 33 views
0

Rust's try!宏解开Result s。 Ok值被解包; Err导致封装方法立即返回Err。这里实现:https://doc.rust-lang.org/std/macro.try!.html等同于Rust的尝试!宏Scala

这大致相当于斯卡拉Option.getOrElse(return None)

是否有可能在Scala中为Option s写等价宏?看来宏需要检查封闭方法的返回类型是Option。我在这里找到了一些相关的讨论:https://groups.google.com/forum/#!topic/scala-user/BH0xz74f4Zk如果是这样,怎么办?

这将是非常好的。也许可以概括为展开其他类型,如FutureTry。这比有效的项目完成的效果要弱但类似:https://github.com/pelotom/effectful。实际上,我想你可以用效果很好但有效的方式来实现,要求整个块被包含在宏中,而try!使用return来允许更多的本地语法,这是更好的。

回答

0

你确定你需要一个宏吗? 如果你不想处理异常,而是返回一个选项,你也可以尝试理解。这种方法也适用于期货和trys顺便说一句。

def f1(): Option[Int] = ??? 
def f2(): Option[String] = ??? 
def f3(): Option[Double] = ??? 

def test(): Option[String] = { 
    for { 
    i <- f1() 
    s <- f2() 
    d <- f3() 
    } yield { 
    val n = i * 2 
    s + (d * n) 
    } 
} 
+0

是的我想要一个宏。 Rust的'try!'让我们可以用很少的语法开销展开值 - 无缩进。我想在Scala中模拟同样的事情。 – tksfz

0

我能做到这一点(在REPL)有:

import scala.language.experimental.macros 

def impl[T](c: reflect.macros.whitebox.Context)(opt: c.Expr[Option[T]]): c.Tree = { 
    import c.universe._ 
    q"$opt.getOrElse(return None)" 
} 

def unwrap[T](opt: Option[T]): T = macro impl[T] 

然后,我可以按如下方式使用它:

def concat(str1: Option[String], str2: Option[String]): Option[String] = { 
    Some(unwrap(str1) + unwrap(str2)) 
} 

concat(Some("hello"), Some(" world")) == Some("hello world") 
concat(Some("hello"), None) == None 

(请注意,在SBT项目,宏需要在一个单独的项目中定义它们的用法。)