Perl变量基础

Perl中的变量可以是标量类型、数组类型或hash类型的,标量类型的变量在变量名前使用$前缀,数组类型的变量在变量名前使用@前缀,hash类型的变量在变量名前使用%前缀。

变量类型 前缀
标量 $
数组 @
hash %

 

Perl严格区分标量、数组、hash这三种类型,因为这决定了perl如何划分内存空间来保存数据

  • 标量类型意味着只保存单个数据,perl会为这样的变量分配用于保存单个数据的内存空间
  • 数组类型意味着可保存多个数据,perl会为这样的变量分配用于保存多个数据的连续内存空间
  • hash类型意味着可保存多个key-value键值对数据,perl会为这样的变量分配用于保存多个键值对数据的内存空间

参考下面的简图:

变量声明和变量赋值

声明全局变量并为变量赋值:

#!/usr/bin/perl
$name = "liujunjun";
print $name, "\n"

使用变量时,可以使用$name的方式,也可以使用更安全更标准的${name}方式。有时候必须使用${name}这个形式来使用变量name,否则会产生歧义。

#!/usr/bin/perl
${name} = "liujunjun";
print ${name}, "\n"

例如,假如声明并赋值了变量name,如果在双引号字符串中使用变量内插,那么"$nameold"很可能是错误的写法(但不一定会报错),因为这会寻找名为nameold的变量而不是名为name的变量,因此,写成"${name}old"可能才是正确的。

#!/usr/bin/perl
${name}="liujunjun";
print "${name}old", "\n"

Perl也允许直接使用未声明、未赋值的变量,此时将根据上下文来决定该变量(这里暂且只考虑标量变量)的值是undef还是空字符串还是数值0。

use指定使用某个版本的perl,如5.10版本。注意,use中是5.010而不是5.10,use 5.10会被perl认为是5.100版
print和say类似,print不自带换行符,say自带换行符,但要使用say,必须写use语句use 5.010;
#!/usr/bin/perl
use 5.010;
use utf8;
say "name: $name";  # 未声明变量在字符串上下文中当作空字符串使用
say "age: ", $age + 20 + 100;  # 未声明变量在数值上下文中当作数值0使用
say "hello+word";
say "id" + "ie"
执行结果:
name:
age: 120
hello+word
0

但是注意,在strict模式下,不允许声明全局变量,也不允许使用未声明的变量。

在strict模式下,需要使用my来声明变量,此时可以先声明,后赋值。已声明但未手动赋值的变量,默认被初始化赋值为undef值。

my函数将 LIST 中的变量声明为封闭块内的词法范围。如果指定了多个变量,则所有变量都必须括在括号中。
#!/usr/bin/perl
use strict;
my ($age,$ip);    # 先声明,默认被初始化赋值为undef
$age = 23;  # 再赋值
$ip = 9;
my $name = "liujunjun";  # 声明并赋值
print "$name, $age, $ip\n"
执行结果
liujunjun, 23, 9
复制代码
#!/usr/bin/perl
use 5.010;
use strict;
my ($age,$ip);    # 先声明,默认被初始化赋值为undef
$age = 23;  # 再赋值
$ip = 9;
my $name = "liujunjun";  # 声明并赋值
print "$name, $age, $ip\n";
say "$name, ", "$age, ", "$ip "

执行结果
liujunjun, 23, 9
liujunjun, 23, 9
复制代码
复制代码
#!/usr/bin/perl -w
use v5.010;
say 10+20;
say 10/2;
say 30*10

执行结果
30
5
300
复制代码

Perl中的变量可以重复声明,后声明的变量将掩盖(mask)已声明的变量。如果开启了warning,将给出变量掩盖的警告信息。

复制代码
#!/usr/bin/perl
use warnings;
my $name = "liujunjun";
my $name = "yanjing";
print "$name\n"

或者

#!/usr/bin/perl -w
my $name = "liujunjun";
my $name = "yanjing";
print "$name\n"

执行结果
"my" variable $name masks earlier declaration in same scope at 2.plx line 3.
yanjing
复制代码

实际上,变量保存的是指向内存中数据的引用(指针),重新声明或重新赋值变量只是改变了变量中保存的指针所指向的内存位置。上例中,name标量中保存的是指向堆内存中字符串liujunjun的指针,随后重新声明并赋值,表示让name保存指向堆内存中字符串yanjing的指针。但是,之前的变量name和它指向的数据liujunjun并没有消失,它只是被掩盖了而无法再被使用,这意味着这部分内存数据将无法被回收。

Perl中的变量只区分是标量、数组还是hash,这决定了perl如何为它们划分内存空间。但是,它们所保存的实际数据不区分数据类型。比如,标量可以保存字符串,也可以保存数值。

#!/usr/bin/perl -w
my $name = "liujunjun";
$name = 123;
$name = 1.23;
print "$name\n"

Perl中的变量赋值自身也有返回值,它的返回值是变量自身(或者说是左值lvalue)。多数时候,也可以将变量赋值看作是返回变量所保存的值。

复制代码
#!/usr/bin/perl -w
# 先执行my $y = "hello",它返回$y
# 再执行赋值操作$x = $y
# 使得$x和$y都保存了"hello"
my $x = my $y = "hello";
print "$x ","$y\n"

执行结果
hello hello
复制代码

因为变量赋值返回变量自身,因此,可以直接在赋值语句上执行那些会原地修改的操作,这会直接修改变量

复制代码
#!/usr/bin/perl -w
use v5.12;

my $y = "hello";
# 先执行赋值,使得$x也保存字符串数据"hello"
# 然后返回变量自身$x作为左值,参与s///替换
# 因此替换后,$x已被修改
( my $x = $y ) =~ s/.*/12345/;
say $x;
say $y;

执行结果
12345
hello
复制代码

Perl中可以一次性为多个变量赋值。

#!/usr/bin/perl -w
my ($x, $y, $z) = (11, 22, 33);
#my $x = 11, my $y = 22, my $z = 33;
print "$x ","$y ","$z\n"

执行结果
11 22 33

对于Perl来说,这两条等价的赋值语句很有研究意义。

Perl中执行赋值语句时,总是先计算赋值操作符(即等号=)右边的表达式,然后将表达式的结果赋值给左边的变量(严格来说是左值lvalue)。

复制代码
#!/usr/bin/perl -w
# 先计算第一个`=`右边的表达式,即`my $y = 22`,
# 发现该表达式还是一个赋值表达式,于是再计算
# 第二个`=`右边的表达式,即数值22,于是将22赋值
# 给$y,而$y = 22返回$y自身,于是将$y的值赋值给$x
my $x = my $y = 22;
print "$x ","$y \n"

执行结果
22 22
复制代码

将一次性为多个变量赋值的特性和先计算赋值操作符右边表达式的特性结合起来,使得交换变量变得非常轻松:

#!/usr/bin/perl -w
my $x = 22;
my $y = 33;
($x, $y) = ($y, $x);  # 赋值之后,$x=33,$y=22
print "$x ","$y \n"

执行结果
33 22

甚至,允许保存外部作用域中的同名变量的值:

复制代码
#!/usr/bin/perl -w
use 5.010;
my $x = 22;
{
  # 将大括号外面的$x的值赋值给当前作用域内的$x
  my $x = $x;
  $x = $x + 1; # 修改当前作用域内的$x
  say $x;     # 23
}
say $x; # 22

执行结果
23
22
复制代码

关于my和局部变量

不使用my声明的变量是全局变量,my声明的变量是局部变量,它有自己生效的作用域范围。关于作用域规则,在后面会详细介绍。这里只需要知道,大括号是一个独立的作用域。

复制代码
#!/usr/bin/perl -w
my $out = 11;
$global_out = 111;    # 全局变量
{
  my $in = 22;
  $global_in = 222;    # 全局变量
}
print $global_in, "\n"

执行结果
222
复制代码

除了使用my声明变量,还可以使用our、local、state声明变量,它们都有自己的变量作用域规则,但目前无需深究它们的用法。

那么是直接声明全局变量还是使用my声明局部变量?几乎任何一种语言,任何一个有编程经验的人,都建议尽量使用局部变量,且少用全局变量。

但是,在Perl里面可以忽略这样的建议,至少需要看情况来决定是否使用局部变量:

  • 写行数较多的Perl脚本时(功能相对复杂),尽量使用my声明局部变量
  • 写涉及多个Perl文件(即使用了package时)的Perl程序时,尽量使用my声明局部变量,甚至要合理使用out、local
  • 写较小的Perl脚本、写一个简单的Perl命令工具时,请随意,因为这时即使使用全局变量出问题也很容易调试
  • 写Perl一行式命令时,全部使用全局变量,尽可能地缩减命令行的字符数量,如非必须,否则不要使用my声明局部变量,因为没有必要

undef和defined()

在Perl中,如果一个变量未声明,那么这个变量会被当作undef来使用,如果声明了变量,但未手动赋值,那么这个变量会被初始化赋值为undef。也可以将undef赋值给某个变量,使得这个变量回到未赋值状态。

say $name;   # 使用未声明变量
my $age;     # 声明变量但未手动赋值
my $gender = undef;  # 手动赋值为undef

在strict模式下,不允许使用未声明变量,但可以使用undef值,而在warnings模式下,某些地方使用未声明值(undef)将给出警告。

实际上,undef是一个函数,但几乎总是可以将它当作一种表示未定义的值来看待。

undef作为值,表示的含义是此处缺失或没有,例如$age=undef(这里调用了undef函数)表示age变量缺失数据、没有数据。

undef作为函数,如果不给任何参数,将直接返回未定义值,如果undef一个变量(如undef $name),则取消变量的声明。

undef可以当作数值0或空字符串使用,它自身也代表布尔假。例如:

my $age;
say $age + 1;    # 1
say "age: $age"; # age: 空字符串

很多场景下需要判断一个值是否是undef,Perl提供了defined()函数,当测试的值为undef时,返回undef,否则返回1(Perl中使用1代表布尔真值)。

复制代码
#!/usr/bin/perl -w
use 5.010;
my $name = "liujunjun";
say defined($name);   # 1

if(defined($age)){
  say "defined";
} else {
  say "undefined";
}

执行结果
1
undefined
复制代码
posted @   星火撩原  阅读(294)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 快收藏!一个技巧从此不再搞混缓存穿透和缓存击穿
· Blazor Hybrid适配到HarmonyOS系统
· 支付宝 IoT 设备入门宝典(下)设备经营篇
· 万字调研——AI生成内容检测
· 解决跨域问题的这6种方案,真香!
历史上的今天:
2021-12-14 PLC是工业控制系统的核心力量
2021-12-14 3分钟看懂物联网网关那点事
2020-12-14 Linux 关闭/开启密码登录(仅证书登录)
2020-12-14 服务器禁止ping
2020-12-14 centos/linux 禁止root用户远程登录
2019-12-14 Kvm命令集管理虚拟机
点击右上角即可分享
微信分享提示

目录导航