代码是:
def mergeTrees(t1: TreeNode, t2: TreeNode): TreeNode = {
if (t1 == null && t2 == null) null
else if (t1 == null) t2
else if (t2 == null) t1
val root = new TreeNode(t1.value + t2.value)
root.left = mergeTrees(t1.left, t2.left)
root.right = mergeTrees(t1.right, t2.right)
root
}
如果我将其更改为:
def mergeTrees(t1: TreeNode, t2: TreeNode): TreeNode = {
if (t1 == null && t2 == null) null
else if (t1 == null) t2
else if (t2 == null) t1
else {
val root = new TreeNode(t1.value + t2.value)
root.left = mergeTrees(t1.left, t2.left)
root.right = mergeTrees(t1.right, t2.right)
root
}
}
然后它起作用。这是什么原因造成的?
答案 0 :(得分:1)
在第一个示例中,您有一个if
语句,该语句计算一个值,然后将该值丢弃。然后假设t1
或t2
都不是null
,然后计算根。
第二个示例添加了else子句,该子句仅在t1
或t2
都不是null
时使用。现在,该函数的结果就是该函数中最后一条语句(即整个if
语句)的结果。 if
语句其他分支上的那些值很有用(它们可能是函数的最后一个值,因此也就是返回值)。
答案 1 :(得分:1)
一组if
,else if
,...
条件组成一个具有单个结果的单个表达式。
在第一个示例中,if else ...
链产生null
或t2
或t1
。但是if else
表达式不是代码块中的唯一表达式,因为if else
的结果没有保存在任何地方,所以它被丢弃了,处理移至下一个表达式。这不是您想要或想要的。
第二个代码示例之所以有效,是因为mergeTrees()
方法中只有一个表达式,即if else
表达式。因此,在那种情况下,if else
的结果就是整个方法的结果。
答案 2 :(得分:1)
在Scala语言规范中,以下语法支持def
的语法,
Def ::= ‘def’ FunDef
FunDef ::= FunSig [‘:’ Type] ‘=’ Expr
FunSig ::= id [FunTypeParamClause] ParamClauses
因此,在您的def mergeTrees(t1: TreeNode, t2: TreeNode): TreeNode = {...}
中,RHS是Expr
,以下语法支持Expr
的特定语法,
Expr := Expr1
Expr1 := PostfixExpr
PostfixExpr := InfixExpr [id [nl]]
InfixExpr := [‘-’ | ‘+’ | ‘~’ | ‘!’] SimpleExpr
SimpleExpr := BlockExpr
BlockExpr := ‘{’ Block ‘}’
Block ::= BlockStat {semi BlockStat} [ResultExpr]
因此...解析器确定您的RHS为BlockExpr
,
如果您在-https://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#blocks上阅读了Scala语言规范中的blocks
,您将会发现以下植入物,
A block expression {s1s1; ……; snsn; ee} is constructed from a sequence of block statements s1,…,sns1,…,sn and a final expression e
。
现在,block statement
中的BlockStat
是什么?
我们只考虑以下情况
def abc(i: Int): Int = {
i + 1
i + 5
}
在这种情况下,i + 1
将被忽略(作为语句),而i + 5
将作为返回值。
与您的情况类似(但更简单),然后将RHS BlockExpr解析如下,
'{'
i + 1 (BlockStat)
i + 5 (ResultExpr)
'}'
但是,i + 1
看起来像Expr
(或表达式),然后为什么将其视为语句,这是因为遵循BlockStat
的语法,
BlockStat ::= Import
| {Annotation} [‘implicit’ | ‘lazy’] Def
| {Annotation} {LocalModifier} TmplDef
| Expr1
这意味着Expr
语法中的任何Expr1
也可以被视为BlockStat
。
因此,在这种情况下,由于以下原因,
{
i + 1
i + 5
}
与语法最佳匹配
'{'
BlockStat
ResultExpr
'}'
因此,实际上是i + 1
的{{1}}被视为Expr1
而不是statement
。这意味着它不会成为块表达式的expression
,而下一个value
将成为块的i + 5
。
现在,从您以下的value
开始,
expression
后跟更多的语句,这些语句将被视为 if (t1 == null && t2 == null) null
else if (t1 == null) t2
else if (t2 == null) t1
,因此不会成为您的statement
的返回值。进一步的表达/陈述也将被评估。
既然您的下一条语句是
def
val root = new TreeNode(t1.value + t2.value)
或t1.value
将在评估时抛出NullPointerException,以防t2.value
或t1
为t2
的情况。