这是我第一次听到Scalar这个词(nothing beats the first time😏)。Scalar的字面意思是标量,在矩阵中用来表示无方向的向量。Let’s take a wild guess here. Scalar在Perl语言中应该是单一维度的变量的意思,包括字符串(string),数字(numerical),引用(reference),通配符(glob)。

字符串

构建字符串

和Shell一样,Perl的特殊符号在双引号内会被转义,在单引号内不会(除了\')。以下面的表达式为例,\t在双引号内转义为一个tab,在单引号内输出字面的”\t”.

print "perl"  # <----------.
print 'perl' # same as ---'

print "hello\tworld" # <------------------.
print 'hello\tworld' # not the same as ---'

另一种单引号的quoting格式:q<char>...<char>

# 以下全部输出hello 'world'
print 'hello \'world\'';
print q!hello 'world'!;
print q<hello 'world'>;

另一种双引号的quoting格式:qq<char>...<char>。另外,双引号里面的特殊符号会被解析。

# 以下全部输出Hello "world"
print "Hello \"world\""
print qq!Hello "world"!
print qq<Hello "world">
特殊符号种类
sequence           | output
-------------------+------------------
\t | tab character
\n | newline
\x<xdigit><xdigit> | character code "\x41" => "A"
\x{<xdigits>} | unicode character code "\x{263A}" => "☺"
\N{<name>} | unicode character name "\x{BICYCLIST}" => "🚴"
多行字符串

Perl的<<有类似于Shell的作用。

# "<<FOO"会被下一行到第二个"FOO"的多行字符串替代后输出
print <<FOO;
abc
def
ghi
FOO
字符串运算
  • 拼接

    # 输出Hello World
    print 'Hello' . ' ' . 'World';
  • 复制

    # 连续输出3次Hello
    print 'Hello' x 3;
    # 遵从数学运算符优先原则,先复制后拼接
    print '-' x 10 . "\n" . '*' x 10;
  • 比较

    • 字符串的比较是根据字符在ASCII码表中对应的数值来的。比如’!’小于’0’, ‘a’小于’b’, ‘a’大于’A’。可以通过’ord’函数来换算字符的ascII码,通过’chr’函数计算ascII码代表的字符。
    • 如果第一位字符相同则比较后一位字符,比如,’aa’小于’ab’, ‘a’小于’aa’,依此类推。
    • Boolean comparison: eq, ne, gt, lt, ge, le 返回 true 或 false
    • 3-state comparison: cmp 返回 -1, 0 or 1

数字

数字42的几种表示方法

42          # decimal
4_2 # _ for grouping
4200E-2 # scientific notation
4.2E1 # floating point
0x2a # hex (base 16)
052 # octal (base 8)
0b101010 # binary (base 2)
'42' # string
运算符

运行符和其他编程语言没差:

computation: +, -, *, /, %(modulo), **(power)
boolean: ==, !=, >, <, >=, <=
3-state: <=>
Bitwise operations: <<, >>, |, &, ~(negation), ^(xor)
Perl中的Context

上下文(context)由运算符来决定。

# Operator "-" forces numerical context for the operands.
print '72' - 30; # 等价于 72 - 30
# Operator "." forces string context for the operands.
print 4 . '2'; # 等价于 '4' . '2'

任何数字类型都可以转换为字符串,任何字符串可以转换为数字,但有可能会导致一个警告信息”non-numerical value in numeric context”.

'42'        =>  42
'fortytwo' => 0 and a warning
'' => 0 and a warning
'result 42' => 0 and a warning
'42 mice' => 42 and a warning
使用print和printf进行输出
  • print函数接受一串表达式,用,, ., 或其他数学运算符分隔,然后输出到STDOUT.

    print 'This', 'is', 'another', "World\n";
  • printf函数用第一个参数作为模板字符串,其后的参数代入模板中的占位符,然后输出到STDOUT.

    # "The Result", 42, 42 分别代入占位符%s, %x, %b
    printf "%s: %x (%b)\n", 'The Result', 42, 42;
  • 其他点位符: 字符串%s,整型%d,十六进制数%x,八进制数%o,二进制数%b,浮点数%f,等等。

  • 占位符可以格式化代入参数的长度和浮点数精度:%20s, %5.2f.

  • 关于printprintf函数更详细的解释参考文档:perldoc -f print.

练习

Write a script that computes and outputs in order:

  • the decimal sum of the binary value 100110 and the octal value 36
  • a new line
  • the binary sum of the binary value 100110 and the octal value 36
  • a new line
  • a line of 72 dashes, terminated with a new line

答案:

#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';

printf "%s: %d", "Decimal sum", 0b100110 + 036;
print "\n";
printf "%s: %b", "Binary sum", 0b100110 + 036;
print "\n";
say "-" x 72 . "\n";

变量

  • Scalar类型的变量不会区分字符串和数字类型。

  • 变量的命名要在简练和准确达意之间做好平衡。

  • 变量未赋值之前是undef, 类似于Javascript中的undefined.

    my $greeting;	        # declare and set to <undef>
    my $greeting = undef; # same
  • Scalar变量在双引号中会被解析(context是字符串)。

    my $result = "42";
    print "result: $result\n";
    print "result: ${result}\n";
  • 操作符

    • 赋值

      my $name = 'Tom';   # declare and assign
      $name = 'Tom'; # assign (needs to be declared already)
    • 所有Scalar变量可以使用 <op>= 格式的操作(inplace modification)

      # $variable <operator>= <operand>;
      my $result = 0;
      $result = $result + 12;
      $result += 12; # same as above
    • 加减g 操作还有++--

      my $y = 0;
      print $y++; # post increment
      print ++$y; # pre increment

      print $y--; # post decrement
      print --$y; # pre decrement

      # 注意避免`++$x$x++`这样的表达式,有可以会产生意想不到的Bug
练习
  • Write a script that computes the the time (in seconds), an electrical signal
    would need to travel around the globe (assume the signal travels at
    the speed of light)

    speed of light: 300'000 km/s
    distance: 40'000 km

    Make use of variables, put the computation result into a variable
    and print it with a nice explanative text around.

  • Bonus: Create a script, that

    • sets a variable x to 41

    • output the variable

    • Now the following lines:

    print ++$x, "\n";	    #  say ++$x;
    print $x++, "\n"; # say $++;
    print $x, "\n"; # say $x;
    • What output do you expect?
    • What output do you get?

答案:

#!/usr/bin/perl
use strict;
use warnings;

my $speed_of_light = 300000;
my $distance = 40000;

printf "The time an electrical travel global one circle: %f seconds.\n", $distance / $speed_of_light;

my $x = 41;
print ++$x, "\n";
print $x++, "\n";
print $x, "\n";