q3256 发表于 2018-8-31 07:37:47

《中级perl》笔记 - 2, 数组引用 (1)

  正式进入主题,perl之所以受欢迎,主要有赖于两大利器: 强大的正则表达式支持 & 强大的复杂数据结构。 复杂数据结构有赖于引用这个重要的实现方式,接下来的几篇笔记将重点讨论列表(也叫数组)引用、哈希引用和函数(也叫子程序)引用。此外还有文件(目录)句柄引用和正则表达式引用,将在后续笔记简略讨论。
  引用类似于C语言的指针,它提供间接访问一个(或一组)对象的方法。直接上例子:
  my @required = qw(preserver sunscreen warter_bottle jacket);
  my @skipper   = qw(blue_shirt hat jacket preserver sunscreen);
  for my $item (@required) {
  unless (grep $item eq $_, @skipper) {    # 如果$item不在@skipper里
  print “skipper is missing $item.\n”;
  }
  }
  这段程序中, @required是Skipper先生需要带的物品,@skipper是他实际带的物品。
  for循环判断@required中,@skipper没有的元素,遇到一个打印一个。没有问题,这些代码能很好的工作,我们还可以写出以下代码来检查Gilligan和Professor有什么没带。
  my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
  for my $item (@required) {
  unless (grep $item eq $_, @gilligan) {    # 如果$item不在@gilligan里
  print “gilligan is missing $item.\n”;
  }
  }
  my @professor = qw(sunscreen water_bottle silde_rule batteries radio);
  for my $item (@required) {
  unless (grep $item eq $_, @professor) {    # 如果$item不在@professor里
  print “professor is missing $item.\n”;
  }
  }
  看起来也没什么问题,不过你将发现我们重复写类似的代码,解决相同的问题。
  sub check_required_items {
  my $who = shift;
  my @required = qw(preserver sunscreen warter_bottle jacket);
  for my $item (@required) {
  unless (grep $item eq $_, @_) {
  print “$who is missing $item.\n”;
  }
  }
  }
  my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
  check_required_items (‘gilligan’, @gilligan);
  my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
  my @professor = qw(sunscreen water_bottle silde_rule batteries radio);
  check_required_items(‘skipper’, @skipper);
  check_required_items(‘professor’, @professor);
  写成函数,我们省去了一部分重复代码。尽管解决了最初的问题,我们还有两个问题需要解决。
  •    每次调用函数都需要拷贝整个数组给@_,这是不小的开销,尤其当数组很大时
  •    如果我们需要改变原数组,函数调用的方式将无法做到。因为传给函数的@_参数只是原数组的一个拷贝,任何应用在@_上的改变,无法应用到原数组。
  引用可以很好地解决这两个问题。
  ** 对数组进行引用 **
  产生一个引用的方法很简单,在被引用的变量前放一个反斜杠 \就产生这个变量的引用。
  my $reference_to_skipper = \@skipper;
  引用是一个标量,它能使用在任何需要标量的场合 : 函数的标量参数、数组的元素、哈西的键或者值 。。。等等。 像普通标量那样,引用可以进行赋值操作。
  my $second_reference_to_skipper = $reference_to_skipper;
  my $third_reference_to_skipper = \@skipper;
  这三个对@skipper的引用是完全相同的东西,他们都直接指向数组@skipper的内存地址。
  ** 解析数组引用 **
  如何访问被引用的数组? 我们通过解析引用来访问数组元素。访问数组引用,类似于访问普通的数组(@后面的空格是故意加的),区别是要把引用放在大括号里:
  @skipper
  @{ $ref_of_skipper }
  访问数组中某个元素的方法也类似:
  $ skipper
  $ {$ref_of_skipper}
  于是我们可以改写之前的函数,通过引用来访问数组。
  sub check_required_items {
  my $who = shift;
  my $items = shift;
  my @required = qw(preserver sunscreen water_bottle jacket);
  for my $item (@required) {
  unless (grep $item eq $_, @{$items}) {
  print “$who is missing $item.\n”;
  }
  }
  }
  我们可以重复调用这个函数,检查人们是否遗失了什么。
  my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
  check_required_items (‘gilligan’, \@gilligan);
  my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
  check_required_items(‘skipper’, \@skipper);
  my @professor = qw(sunscreen water_bottle silde_rule batteries radio);
  check_required_items(‘professor’, \@professor);
  函数定义部分,我们只是把@_替换成数组引用;调用函数时,我们把第二参数换成待检查数组的引用。这样做解决了之前的第一个问题,不需要再拷贝原数组给@_,而是函数直接访问目标数组。后面我们将看到引用是如何解决第二个问题的。
  我们还可以把函数中的两个shift语句去掉,不过这样维护起来更困难了。
  sub check_required_items {
  my @required = qw(preserver sunscreen water_bottle jacket);
  for my $item (@required) {
  unless (grep $item eq $_, @{$_}) {    #$_是传给函数的@_第二个参数
  print “$_ is missing $item.\n”;    #$_是传给函数的第一个参数
  }
  }
  }

页: [1]
查看完整版本: 《中级perl》笔记 - 2, 数组引用 (1)