:5hours
是Pair
,hours => 5
也是Pair
:
> DateTime.now.truncated-to('day').later(:5hours)
2022-02-14T05:00:00+08:00
> :5hours.WHAT
(Pair)
> DateTime.now.truncated-to('day').later(hours => 5)
2022-02-14T05:00:00+08:00
> (hours => 5).WHAT
(Pair)
然而,当我手动创建Pair
时,它与later
:的签名不匹配
> DateTime.now.truncated-to('day').later(Pair.new('hours', 5))
Cannot resolve caller later(DateTime:D: Pair:D); none of these signatures match:
(Dateish:D: *%unit --> Dateish:D)
(Dateish:D: @pairs, *%_)
in block <unit> at <unknown file> line 1
但在Pair
参数正常之前使用垂直:
> DateTime.now.truncated-to('day').later(|Pair.new('hours', 5))
2022-02-14T05:00:00+08:00
那么:5hours
、Pair.new('hours', 5)
和hours => 5
之间有什么区别呢?为什么不能将手动创建的Pair
(如Pair.new('hours', 5)
(传递给later
方法?
下面两个不是同一件事吗?
> :5hours === Pair.new('hours', 5) === hours => 5
True
> :5hours eqv Pair.new('hours', 5) eqv hours => 5
True
> my $pair1 = Pair.new('hours', 5); dd $pair1; # Pair $pair1 = :hours(5)
> my $pair2 = :5hours; dd $pair2; # Pair $pair2 = :hours(5)
> my $pair3 = hours => 5; dd $pair3; # Pair $pair3 = :hours(5)
> my $pair4 = 'hours' => 5; dd $pair4; # Pair $pair4 = :hours(5)
尽管:5hours
和hours => 5
、:hours(5)
、Pair.new(hours,5)
和Pair.new(key => "hours", value => 5)
都是创建Pair
对象的不同方法,但只有前三个是表示命名参数的语法糖。
当您将Pair.new("hours",5)
作为参数传递时,它被视为位置参数。观察:
sub foo(*@_, *%_) {
dd @_, %_
}
foo hours => 5;
# []
# {:hours(5)}
foo Pair.new("hours",5);
# [:hours(5)]
# {}
至于为什么会这样?好吧,有时你想传递一个Pair
作为位置参数。如果一个Pair
总是被认为是一个命名的参数,你就不能这么做
至于为什么|Pair.new("hours",5)
作为命名参数工作?在此上下文中,|
将给定对象(通常是Capture
或Hash
/Map
(展平为给定子例程的参数。在这种情况下,Pair
被视为Map
的退化情况:具有单个键/值的不可变Map
。观察:
foo |Pair.new("hours",5);
# []
# {:hours(5)}
嗯,可能是任何Associative
:-(
say Pair ~~ Associative; # True
.say for (:5hours).keys; # hours
.say for (:5hours).values; # 5
最后,从技术上讲,本文中的|
不是Slip
,而是语法糖,用于将给定值扁平化为调用的参数。
该语法早于Slip
的概念(该概念于2015年大名单重构期间引入(。直到2015年很晚,@Larry才允许|
也用于表示Slip
,因为它们在概念上也做类似的事情。