instanceof中的模式匹配有时无法解析理论上可解析的作用域


import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
List<Node> list = new ArrayList<>();
Node x = list.get(0);
if (!(x instanceof Comment comment)) {
if (!(x instanceof Document doc && doc.getFirstChild() instanceof Comment comment)) {
return null;
}
}
System.out.println(comment.ToString()); // cannot resolve comment

变量comment不能被解析,但它应该被解析——我们覆盖了2条互斥的快乐路径,每条路径都分配Comment comment——并且系统输出应该能够看到comment,否则return null将被触发。

您不能使用模式匹配在两个不同的地方声明相同的变量。它们仍然是两个不同的变量,具有两个不同的作用域。

也许,我们可以通过给它们起不同的名字来消除混淆:

if (!(x instanceof Comment comment)) {
if (!(x instanceof Document doc && doc.getFirstChild() instanceof Comment comment2)) {
return null;
}
//comment2 and doc are in scope here,
//but their scope ends with an enclosing block
System.out.println(comment2.toString());
}
//FAIL! You can't access comment2 outside its scope
System.out.println(comment2.toString()); 
//FAIL! You can't access comment here because 
//the compiler can't guarantee that the block above exited.
System.out.prinltn(comment.toString()

您可以使用一个简单的示例来验证模式匹配的变量仍然保留在其封闭范围内:

{
Object o = null;
if(!(o instanceof String s)) {
return;
}
System.out.println(s); //OK
}
System.out.println(s); //Doesn't work

对不起,我真的没有一个优雅的替代方法供您使用。您可以使用一个有点难看的解决方案来实现您想要的:

Comment comment;
if (!(x instanceof Comment c)) {
if (!(x instanceof Document doc && doc.getFirstChild() instanceof Comment c)) {
return null;
}
comment = c;
} else {
comment = c;
}
System.out.println(comment.toString());

如果您可以将此代码段移动到单独的方法中,则此解决方法会更好:

private static Comment extractComment(Node x) {
if (!(x instanceof Comment comment)) {
if (!(x instanceof Document doc && doc.getFirstChild() instanceof Comment comment)) {
return null;
}
return comment;
} 
return comment;
}

甚至:

private static Comment extractComment(Node x) {
if (x instanceof Comment comment) {
return comment;
}     
if (x instanceof Document doc && doc.getFirstChild() instanceof Comment comment) {
return comment;
}
return null;
}

最新更新