Perl6 multi sub调用歧义问题咨询及命名参数解决方案验证
Perl 6 多子例程位置参数调用歧义的原因与解决方案
为什么会出现歧义?
咱们先拆解一下问题:你用位置参数定义的两个多子例程,在调用Screen_get_valid_string("enter value for string => ", True)时,Perl 6的调度器犯难了——它没法确定该选哪一个。
看这两个签名:
- 第一个:
($prompt, $accept_empty_string, $max_length = 999),第二个参数是接收布尔值的$accept_empty_string,第三个参数用默认值就行,完全匹配你传入的两个参数; - 第二个:
($prompt, $max_length = 999),第二个参数是$max_length,在Perl 6里布尔值True会被自动转成整数1,而$max_length没有类型约束,自然能接受这个值,所以这个签名也匹配。
两个签名都能对应上你的调用,调度器当然会抛出歧义错误了。
而用命名参数的时候,你明确指定了accept_empty_string => True,调度器一眼就知道该找带这个命名参数的子例程,自然没歧义。
除了命名参数,还有这些解决办法
1. 给参数加类型约束
最直接的方式就是明确参数类型,让调度器能精准区分:
multi sub Screen_get_valid_string(Str $prompt, Bool $accept_empty_string, Int $max_length = 999) { return "abc" } multi sub Screen_get_valid_string(Str $prompt, Int $max_length = 999) { return "def" } my $return = Screen_get_valid_string("enter value for string => ", True); say 'return is ', $return; # 输出 return is abc
现在第二个参数是Bool类型,只有第一个子例程能匹配;第二个子例程的第二个参数是Int,True不会被强制转换成Int来适配它,歧义直接消除。
2. 调整参数的必填性
如果让两个子例程的必填参数数量不一样,调度器也能轻松区分:
multi sub Screen_get_valid_string($prompt, $accept_empty_string, $max_length) { return "abc" } multi sub Screen_get_valid_string($prompt, $max_length = 999) { return "def" } # 传3个参数,调用第一个子例程 my $return1 = Screen_get_valid_string("enter value => ", True, 50); say 'return1 is ', $return1; # abc # 传2个参数,调用第二个子例程 my $return2 = Screen_get_valid_string("enter value => ", 50); say 'return2 is ', $return2; # def
不过这种方式会去掉原有的默认值逻辑,得根据你的实际需求调整。
3. 用where从句限制匹配条件
给子例程加上参数匹配的条件,让调度器能准确找到对应的候选:
multi sub Screen_get_valid_string($prompt, $arg, $max_length = 999) where $arg ~~ Bool { return "abc" } multi sub Screen_get_valid_string($prompt, $max_length = 999) { return "def" } my $return = Screen_get_valid_string("enter value => ", True); say 'return is ', $return; # abc
这里第一个子例程只接受第二个参数是布尔值的调用,完美匹配你的场景,歧义也就不存在了。
内容的提问来源于stack exchange,提问作者pcarrier
相关产品推荐
相关产品推荐

