我一直遇到取消引用的问题,尤其是在从函数返回值时。
问题似乎是,每当您返回标量以外的任何内容时,您实际上是通过引用返回该对象 - 这对我来说很好 - 但是当我们将这些引用传递给其他函数并且我们需要再次访问它们的胆量时,我们如何正确地做到这一点?
我一直遇到这样的错误:">期望偶数个参数得到引用">或类似的东西。
是否有一般的经验法则可用于简化整个过程?我几乎希望我不必担心取消引用!
这是我今天早些时候尝试做的一个例子, 并遇到了各种各样的去引用问题, 我花了几个小时试图解决我的方式 所以在阅读,尝试和失败之后,我在这里问你低谷。
人员对象
Person
has name [Str]
has madeby [Str]
has height [Num]
has id [Num]
制作 Person 对象的各种方法
sub person_maker{
my($this,%options) = @_;
my $person = Person->new(%options);
return $person;
}
sub make_person_named_james{
my($this,$options) = @_;
my $default = { name => 'James', madeby => 'name' };
$options = ($options,$defaults); #merge default and options hash
return($this->person_maker($options));
}
sub make_person_from_id{
my($this,$id) = @_;
my $default = { name => 'nameless person', madeby => 'id' };
$default = ($default,{ id => $id });
return($this->person_maker($default);
}
sub make_person_from_person{
my($this,$person) = @_;
my $person_options = {
name => $person->name().'_twin',
height => $person->height(),
id => $person->id() + 1,
madeby => 'person'
};
return($this->person_make($person_options));
}
- Func 返回哈希对象 =>它实际上作为哈希返回参考
- Func 返回哈希引用 =>它实际上作为标量
- Func 返回数组对象 =>它实际上返回一个数组参考
- Func 返回数组引用 =>它实际上返回一个标量?
- Func 返回一个标量 =>它实际上返回的值标量?
如果我理解得错了,请纠正我。
然后对我来说另一个问题是在消耗函数的参数时。
根据我回来的东西,这些坏男孩的行为都会有所不同!
sub myfunc{
my($self,$args) = @_ # list of arguments (what if the args are mixed?)
OR
my($self,$args) = $_ # scalar (this wont work here $args will by undef
OR
my $self = shift; # pop the first arg
my $args = shift; # pop the second arg
OR
my $self = $_[0]
my $args = $_[1]
加!那里有太多的文档,其中许多已经过时,因此很难确切地弄清楚在这些情况下正确或最好的做法是什么。
如果有人有一个魔术图表,详细说明何时使用这些不同的设置,以及如何在特定情况下取消引用,祝福哈希、哈希引用、标量等。我将永远感激,因为我浪费了几个小时试图破译这一点。
所有引用都是标量值
取消引用引用需要知道引用的类型。可以使用 ref
函数找到引用的类型。
my $array_ref = [];
print ref $array_ref; # prints: ARRAY
取消引用不同类型的
标量参考:
$$scalar_ref
数组参考:
@$array_ref
哈希引用:
%$hash_ref
@_
@_
包含参数的别名。修改@_
会导致修改原始值。始终尽快复制参数并处理这些副本;您可以安全地修改它,而无需更改原始值。
参数和返回值
在Perl中,所有函数调用参数都被平展(折叠(为一个列表(从而失去它们的身份(,返回值也是如此。从函数的角度来看,它只能接受单个值列表,并且只能返回单个值列表。
示例方案:
函数的标量参数:
sub foo {
my $arg = shift;
}
这同样适用于所有引用;引用是标量值。
函数的数组参数:
sub foo {
my @args = @_;
}
foo( 'bar', 'baz' );
foo( ( 'bar', 'baz' ), ( 'qux', 'spam' ) ); # In no way can the foo subroutine identify that the original arguments were two lists (same with arrays).
函数的哈希参数:
sub foo {
my %arg = @_;
}
foo( 'bar' => 'baz' );
foo( ( 'bar' => 'baz' ), ( 'qux' => 'spam' ) ); # In no way can the foo subroutine identify that the original arguments were two hashes.
当涉及多个列表(数组(或哈希时,始终传递引用。这样,您可以单独标识列表。
$_
和@_
不同
引用您的代码(错误地使用$_
(:
my($self,$args) = $_ # scalar (this wont work here $args will by undef
$_
称为默认变量,用于许多未声明显式变量的情况。 另一方面,@_
仅用于在函数内保存数组参数(别名(。要引用每个元素,我们可以使用: $_[0]
, $_[1]
, 等等。
引用
您可以从
perldoc perlvar
中阅读有关 Perl 中预定义变量的更多信息。我总是从我的终端使用perldoc -v '$special_variable'
。如果使用 Windows,则单引号必须替换为双引号:perldoc -v "$special_variable"
。Perl 子例程:
perldoc perlsub
Perl 引用和嵌套数据结构:
perldoc perlref
您缺少使用引用的一些关键方面。
从基础开始,Perl 中的标识符是一个字符串匹配[a-zA-Z_]w+
排除了 unicode 的复杂性。 此标识符可以是裸的,也可以以符号为前缀。
重要和最常被忽视的符号是 glob,*
,它是所有可变事物的容器(至少在my
不得不破坏派对并与众不同之前,躲在垫子里(。
当您有一个名为 foo
的标识符时,*foo
glob 包含所有foo
可能的内容:
$foo as a scalar, a singular value
@foo as an array, a plural value
%foo as a hash, a plural value
&foo as code, singular if a reference &foo, could be plural if making a call
还有其他类型,但它们不太常见。
在上面的每个示例中,符号都放在标识符的前面,并取消引用存储在 glob *foo
中的引用值。 它的完整语法有点笨拙@{*foo{ARRAY}}
,所以perl让你省略可悲的被忽视的glob signil,直接使用其他符号。 不过,您可以保留括号,${foo}
或@{foo}
或任何其他符号,它们分别与$foo
和@foo
的含义相同。
事实证明,您不必在符号后面或括号内放置一个裸词标识符,而是任何单数值。
my $scalar_foo_ref = $foo;
say $$scalar_foo_ref; # prints $foo
say ${$scalar_foo_ref}; # same
符号始终期望取消引用其类型的值(或可以假装的值(,否则将引发错误。
所以假设以下代码:
my @array = qw(a b c);
say $array[0]; # a
say join ', ' => @array; # a, b, c
您可以轻松地将其转换为使用引用。 首先,您将声明更改为使用引用,这些引用是标量,因此存储在$foo
中:
my $array = [qw(a b c)]; # square brackets make an array ref
# or
my $array = @array_of_hopefully_another_name; # does too
然后在代码的其余部分,将字符串array
替换为引用的名称,$array
:
say $$array[0]; # a
say join ', ' => @$array; # a, b, c
就是这样,所有参考资料。 所以,最后是你的代码。 采取以下几行:
my $default = { name => 'James', madeby => 'name' };
$options = ($options,$defaults); #merge default and options hash
首先,正确使用 {...}
构造来创建匿名哈希引用。 你也可以用非常冗长的形式写成:
my $default = do {my %hash = (name => 'James', madeby => 'name'); %hash};
但不要那样做。
下一行是问题发生的地方,也是您需要遵循上面的替换规则的地方。 您可能看到如下所示的代码:
%options = (%options, %defaults);
当你改变符号时,一切都出错了。 perl 在看到时实际做了什么:
$options = ($options, $defaults);
它是否执行然后丢弃除列表最后一个元素之外的所有元素(在本例中($options,
然后将最后一个元素分配给=
lhs 上的标量,使您的行等效于:
$options = $defaults;
这当然不是你想要的。 相反,用你的哈希引用名称代替裸词名称:
%$options = (%$options, %$defaults);
这恰好可能以错误的顺序合并,您的默认值覆盖了选项。 要解决此问题,只需反转两者:
%$options = (%$defaults, %$options);
在使用这些引用的代码中应用这些更改。 事情应该又开始变得有意义了。