Raku中first例程无匹配值时为何$result === Nil返回False
问题说明
根据Raku官方文档记载,List类型的first例程在无匹配值时会返回Nil。但运行如下代码时,say ($result === Nil);语句为何没有输出True?
sub MAIN() { my @myNumberList is Array[Int] = [2, 2, 5, 7] ; my $result = @myNumberList.first( {$_ > 10} ) ; say '$result' ; say $result ; say $result.WHAT ; say ($result === Nil) ; } # end sub MAIN
上述代码的运行输出如下:
$result (Any) (Any) False
核心原因
这是Raku里Nil的特殊行为导致的:
Nil本质是「缺失值」标记,不会被普通标量变量存储。当你把Nil赋值给一个没有显式类型约束的$标量变量时,变量会被重置为自身类型对应的默认值:无类型约束的标量默认类型是Any,对应默认值就是(Any),所以你拿到的$result根本不是原来返回的Nil,自然和Nil做同一性判断会返回False。- 如果要接住
Nil做判断,要么直接在表达式里判断不做中间赋值,要么给变量显式声明Nil类型约束,要么直接用first自带的布尔语义判断,不需要硬比对Nil。
更推荐的存在性判断方案
提问者的实际目标是判断列表或数组中是否存在满足给定谓词的元素,不需要绕路接Nil判断,有两种更稳妥的写法:
方案1:用grep判断结果元素个数
仅当列表/数组存在至少一个满足谓词的元素时,grep返回结果的elems值才会大于0,示例代码如下:
sub MAIN() { my $myList = (2, 2, 5, 7) ; say '$myList' ; say $myList ; say $myList.WHAT ; my $grepResult1 = $myList.grep( * > 10, :p ) ; say '$grepResult1' ; say $grepResult1 ; say $grepResult1.WHAT ; say ($grepResult1.elems <= 0) ; my $grepResult2 = $myList.grep( * > 4, :p ) ; say '$grepResult2' ; say $grepResult2 ; say $grepResult2.WHAT ; say ($grepResult2.elems <= 0) ; my @myArray = [2, 2, 5, 7] ; say '@myArray' ; say @myArray ; say @myArray.WHAT ; my $grepResult3 = @myArray.grep( * > 10, :p ) ; say '$grepResult3' ; say $grepResult3 ; say $grepResult3.WHAT ; say ($grepResult3.elems <= 0) ; } # end sub MAIN
运行输出如下:
$myList (2 2 5 7) (List) $grepResult1 () (Seq) True $grepResult2 (2 => 5 3 => 7) (Seq) False @myArray [2 2 5 7] (Array) $grepResult3 () (Seq) True
方案2:直接用first返回值做布尔判断
first找不到元素时返回的结果在布尔上下文里本身就是False,不需要和Nil做===判断,直接写if @arr.first( {$_ > 10} ) { ... }就能正确判断是否存在匹配元素,写法更简洁。
内容的提问来源于stack exchange,提问作者user3134725
相关产品推荐
相关产品推荐

