perl5和perl6
在本系列的第一篇文章中,比较了Perl 5和Perl 6,我们研究了将代码迁移到Perl 6时可能遇到的一些问题。在第二篇文章中 ,我们研究了Perl 6中垃圾回收的工作方式。第三篇文章,我们将重点介绍Perl 5的参考以及在Perl 6中如何处理它们,并介绍绑定和容器的概念。
参考资料
Perl 6中没有引用,这使许多习惯于Perl 5语义的人感到惊讶。 但不必担心:由于没有引用,因此您不必担心是否应取消引用某些内容。
# Perl 5
my
$foo
=
\@bar
;
# must add reference \ to make $foo a reference to @bar
say
@bar
[
1
]
;
# no dereference needed
say
$foo
->
[
1
]
;
# must add dereference ->
# Perl 6
my
$foo
=
@bar
;
# $foo now contains @bar
say
@bar
[
1
]
;
# no dereference needed, note: sigil does not change
say
$foo
[
1
]
;
# no dereference needed either
有人可能会说Perl 6中的所有内容都是参考。 来自Perl 5(其中的对象是一个受祝福的引用),这将是关于Perl 6的逻辑结论,在Perl 6中, 一切都是对象(或可以认为是对象)。 但这并不能使Perl 6的情况公平化,并且会妨碍您了解Perl 6的工作方式。当心虚假的朋友 !
捆绑
在开始分配之前,了解Perl 6中的绑定概念很重要。您可以使用:=
运算符将某些内容明确绑定到其他内容。 定义词法变量时,可以将值绑定到它:
my $foo := 42 ; # note: := instead of =
简而言之,这将在词汇垫(lexpad)中创建一个名称为“ $foo
”的键(您可以考虑将其包含在该词汇范围内可见的事物的信息的编译时哈希),并将其字面值设为42
。 因为这是一个文字常量,所以不能更改它。 尝试这样做将导致异常。 所以不要那样做!
此绑定操作在许多情况下都在后台使用,例如在迭代时:
my
@a
=
0
..
9
;
# can also be written as ^10
say
@a
;
# [0 1 2 3 4 5 6 7 8 9]
for
@a
{
$_
++
}
# $_ is bound to each array element and incremented
say
@a
;
# [1 2 3 4 5 6 7 8 9 10]
如果尝试遍历常量列表,则$_
绑定到文字值 ,您不能将其递增:
for 0 .. 9 { $_ ++ } # error: requires mutable arguments
分配
如果在Perl 5和Perl 6中比较“创建词法变量并分配给它”,则外部看起来是相同的:
my $bar = 56 ; # both Perl 5 and Perl 6
在Perl 6中,这还将在lexpad中创建一个名称为“ $bar
”的键。 但是,而不是直接绑定的值到lexpad条目, 容器 ( Scalar
对象)为您创建和绑定到“的lexpad进入$bar
”。 然后,将56
作为值存储在该容器中。 在伪代码中,您可以将其视为:
my $bar := Scalar . new ( value => 56 ) ;
注意, Scalar
对象是bound ,未分配。 在Perl 5中,与此最接近的是束缚标量 。 但是当然“ = 56
”要少得多!
诸如Array
和Hash
类的数据结构也会自动将值放入绑定到该结构的容器中。
my
@a
;
# empty Array
@a
[
5
]
=
42
;
# bind a Scalar container to 6th element and put 42 in it
货柜
对于Perl 6中的大多数操作来说, Scalar
容器对象是不可见的,因此大多数时候您不必考虑它。 例如,每当调用一个子程序(或方法)与变量作为自变量,它会结合在容器中的值。 而且由于无法分配值,您将获得:
sub frobnicate
(
$this
)
{
$this
=
42
;
}
my
$foo
=
666
;
frobnicate
(
$foo
)
;
# Cannot assign to a readonly variable or a value
如果要允许分配外部值,可以将is rw
特性添加到签名中的变量。 这会将签名中的变量绑定到指定变量的容器 ,从而允许赋值:
sub oknicate
(
$this is rw
)
{
$this
=
42
;
}
my
$foo
=
666
;
oknicate
(
$foo
)
;
# no problem
say
$foo
;
# 42
代理
从概念上讲,Perl 6中的Scalar
对象具有FETCH
方法(用于生成对象中的值)和STORE
方法(用于更改对象中的值),就像Perl 5中的绑定标量一样。
假设您稍后将值768
分配给$bar
变量:
$bar = 768 ;
从概念上讲,发生的事情等同于:
$bar . STORE ( 768 ) ;
假设您要在$bar
的值上加上20
:
$bar = $bar + 20 ;
概念上发生的是:
$bar . STORE ( $bar . FETCH + 20 ) ;
如果您想在容器上指定自己的FETCH
和STORE
方法,则可以通过绑定到Proxy对象来实现。 例如,创建一个变量,该变量将始终报告分配给它的值的两倍:
my
$double
:=
do
{
# $double now a Proxy, rather than a Scalar container
my
$value
;
Proxy
.
new
(
FETCH
=> method
(
)
{
$value
+
$value
}
,
STORE
=> method
(
$new
)
{
$value
=
$new
}
)
}
请注意,您将需要一个额外的变量来将值存储在这样的容器中。
约束和默认
除值外, 标量还包含其他信息,例如类型约束和默认值。 采取以下定义:
my Int $baz is default ( 42 ) = 666 ;
它在lexpad上创建一个名称为“ $baz
”的标量绑定,将该容器中的值约束为与Int
成功进行智能匹配的类型,将容器的默认值设置为42
,并将值666
放入容器中。
由于类型限制,将字符串分配给该变量将失败:
$baz
=
"foo"
;
# Type check failed in assignment to $baz; expected Int but got Str ("foo")
如果在定义变量时未提供类型约束,则将假定为Any
类型。 如果未指定默认值,则将采用类型约束。
将Nil
(相当于Perl 5的undef
的Perl 6)分配给该变量会将其重置为默认值:
say
$baz
;
# 666
$baz
= Nil
;
say
$baz
;
# 42
摘要
Proxy (很像Perl 5中的绑定标量)和Scalar 。 简而言之,变量以及List , Array或Hash的元素都是值(如果已绑定 )或容器(如果已分配 )。 每当调用子例程(或方法)时,给定的参数都将被取消容器化并绑定到子例程的参数(除非被告知要这样做)。 容器还保留诸如类型约束和默认值之类的信息。 将Nil
分配给变量将使其返回其默认值,如果您未指定类型约束,则为Any
。
perl5和perl6