scala – 如何开发宏来短路null?
在斯卡拉,如果我有
hub = myBicycle.getFrontWheel.getHub() 并且可能缺少前轮,即myBicycle.getFrontWheel()== null,我只想在这种情况下将hub指定为null,表达它的最简洁方法是什么? 我现在不得不这样做 hub = if (myBicycle.getFrontWheel() == null) null else myBicycle.getFrontWheel.getHub() 当访问者链更长时,它会变得更糟. 不熟悉Scala宏,我想知道是否有可能编写一个Scala宏以某种方式捕获方法名称并仅在对象引用为非null时才应用它? 解决方法
实际上,我最近写的是这样一个宏,受到
a question about null-safe dereferences in Scala的启发.顺便说一下,这是一个非常类似的问题,并且包含了一个很长的讨论,你可以做些什么来实现这一点,包括使用Option,花哨的捕获方式NPE等.
我写的一些关于宏的评论(来源包括在下面): >它返回一个Option,当某个时候存在空取消引用时它将是None. 宏: def withNullGuards[T](expr: T): Option[T] = macro withNullGuards_impl[T] def withNullGuards_impl[T](c: Context)(expr: c.Expr[T]): c.Expr[Option[T]] = { import c.universe._ def eqOp = newTermName("==").encodedName def nullTree = c.literalNull.tree def noneTree = reify(None).tree def someApplyTree = Select(reify(Some).tree,newTermName("apply")) def wrapInSome(tree: Tree) = Apply(someApplyTree,List(tree)) def canBeNull(tree: Tree) = { val sym = tree.symbol val tpe = tree.tpe sym != null && !sym.isModule && !sym.isModuleClass && !sym.isPackage && !sym.isPackageClass && !(tpe <:< typeOf[AnyVal]) } def isInferredImplicitConversion(apply: Tree,fun: Tree,arg: Tree) = fun.symbol.isImplicit && (!apply.pos.isDefined || apply.pos == arg.pos) def nullGuarded(originalPrefix: Tree,prefixTree: Tree,whenNonNull: Tree => Tree): Tree = if (canBeNull(originalPrefix)) { val prefixVal = c.fresh() Block( ValDef(Modifiers(),prefixVal,TypeTree(null),prefixTree),If( Apply(Select(Ident(prefixVal),eqOp),List(nullTree)),noneTree,whenNonNull(Ident(prefixVal)) ) ) } else whenNonNull(prefixTree) def addNullGuards(tree: Tree,whenNonNull: Tree => Tree): Tree = tree match { case Select(qualifier,name) => addNullGuards(qualifier,guardedQualifier => nullGuarded(qualifier,guardedQualifier,prefix => whenNonNull(Select(prefix,name)))) case Apply(fun,List(arg)) if (isInferredImplicitConversion(tree,fun,arg)) => addNullGuards(arg,guardedArg => nullGuarded(arg,guardedArg,prefix => whenNonNull(Apply(fun,List(prefix))))) case Apply(Select(qualifier,name),args) => addNullGuards(qualifier,prefix => whenNonNull(Apply(Select(prefix,args)))) case Apply(fun,args) => addNullGuards(fun,guardedFun => whenNonNull(Apply(guardedFun,args))) case _ => whenNonNull(tree) } c.Expr[Option[T]](addNullGuards(expr.tree,tree => wrapInSome(tree))) } 编辑 这是一段额外的代码,使语法更好: def any2question_impl[T,R >: T](c: Context {type PrefixType = any2question[T]})(default: c.Expr[R]): c.Expr[R] = { import c.universe._ val Apply(_,List(prefix)) = c.prefix.tree val nullGuardedPrefix = withNullGuards_impl(c)(c.Expr[T](prefix)) reify { nullGuardedPrefix.splice.getOrElse(default.splice) } } implicit class any2question[T](any: T) { def ?[R >: T](default: R): R = macro any2question_impl[T,R] } 最后,您可以使用以下代码: val str1: String = "hovercraftfullofeels" val result1 = str1.substring(3).toUpperCase ? "THERE WAS NULL" println(result1) // prints "ERCRAFTFULLOFEELS" val str2: String = null val result2 = str2.substring(3).toUpperCase ? "THERE WAS NULL" println(result2) // prints "THERE WAS NULL" (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |