┌──────────────────┐
│Perl入門 〜構造化プログラミング編〜 │
│(2)リファレンスとデータ構造     │
│2005/09/10             │
└──────────────────┘

[▲Perl Home▲]

●リファレンス

 ◆リファレンスとは
 
  ・Perlでプログラミングを、可読性の良い再利用に適したコードを組むには、サブ
   ルーチンによる構造化が必要ですが、これを実践するためにはリファレンスとデ
   ータ構造についての知識を持たなければいけません。
  
  ・リファレンスはデータを間接的に指す方法です。リファレンスは
    + 構造化されたコードでデータの処理を重ねる
    + データそのものを構造化する
   場合に必要となります。
  
  ・変数へのリファレンス(*1)を取得するには「\(バックスラッシュ)」演算子を使
   用します。
   
     $ref_scalar = \$scalar; # スカラー
     $ref_list  = \@list;  # リスト
     $ref_hash  = \%hash;  # ハッシュ
    ┌──────────────────────────────────┐
     $scalar = 'あいうえお';
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      scalar     AAAA
       ↓      ↓
       ┌──┐   ┌─────┬─┐
       │AAAA├──→│あいうえお│E│
       └──┘   └─────┴─┘
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     $ref_scalar = \$scalar;
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       ┌──┐   ┌──────┐
       │BBBB├──→│AAAA:SCALAR │ ※BBBBはOS/インタプリタからの割り
       └──┘   └──────┘  当て。中身がAAAAで$scalarと同じ
       ↑      ↑
      ref_scalar   BBBB
    └──────────────────────────────────┘

  ・リファレンスからデータの実体を取得(デリファレンス)するには、下記のような
   表記(*2)を行います。
   
    + スカラー
      ${$ref_scalar}  : スカラーのデリファレンス
    + リスト
      @{$ref_list}   : リストのデリファレンス
      $ref_list->[1]  : リファレンスからのリスト要素指定
    + ハッシュ
      ${$ref_hash}   : ハッシュのデリファレンス
      $ref_hash->{ele} : リファレンスからのハッシュ要素指定
    ┌──────────────────────────────────┐
     ${$ref_scalar}; # デリファレンス
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      ref_scalar   BBBB         AAAA
       ↓      ↓          ↓
       ┌──┐   ┌──────┐   ┌─────┬─┐
       │BBBB├──→│AAAA:SCALAR ├─┬→│あいうえお│E│
       └──┘   └──────┘ │ └─────┴─┘
       ┌──┐            │
       │AAAA├────────────┘※同じデータを指す
       └──┘
       ↑
      scalar
    └──────────────────────────────────┘

  ・リスト及びハッシュのデリファレンスで使用されている「->」はアロー演算子と
   呼ばれています。リファレンスからリスト要素、ハッシュ要素を参照する(*3)際
   に使用します。

 ◆リファレンスの使用例
 
  ・ここで、リファレンス/デリファレンスを具体的なコードを通じて見ることにし
   ます。
    ┌──────────────────────────────────┐
     $scalar = 'スカラーデータ';
     $ref_scalar = \$scalar;
      print "ref:$ref_scalar\n";
      print "deref:${$ref_scalar}\n";
      print "\n";
    
     @list = ('リスト0', 'リスト1', 'リスト2', 'リスト4');
     $ref_list = \@list;
      print "ref:$ref_list\n";
      print 'deref[1]:', $ref_list->[1], "\n";
      print "\n";
    
     %hash = ( 'キー0' => 'ハッシュ0',
          'キー1' => 'ハッシュ1',
          'キー2' => 'ハッシュ2');
     $ref_hash = \%hash;
      print "ref:$ref_hash\n";
      print 'deref{キー1}:', $ref_hash->{'キー1'}, "\n";
    ───────────────────────────────────
     [結果]
     ref:SCALAR(0x275cc4)
     deref:スカラーデータ
     
     ref:ARRAY(0x275dc0)
     deref[1]:リスト1
     
     ref:HASH(0x182dba4)
     deref{キー1}:ハッシュ1
    └──────────────────────────────────┘


●リファレンスとデータ構造

 ◆リファレンスとリスト
 
  ・複数のリストデータをハンドリングしたい場合
     @list = ( ('d0', 'd1', 'd2'),
          ('d3', 'd4', 'd5'),
         );
   としても、リストは平坦化され、一つのリストと見なされます。
  
  ・つまり
     @list0 = qw(d0 d1 d2); # (*4)
     @list1 = qw(d3 d4 d5);
     
     @lista = (@list0, @list1);
   でも1つのリストに平坦化されてしまいます。しかし別々のリストとして扱いた
   いとき、「リストの集合」として扱いたいときはリストのリファレンスを使用し
   ます。
   
    ┌──────────────────────────────────┐
     @list0 = qw(d0 d1 d2);
     @list1 = qw(d3 d4 d5);
     
     @lista = (\@list0, \@list1);
     
     print '$lista[0]->[1]:',$lista[0]->[1],"\n";
     print '$lista[1]->[2]:',$lista[1]->[2],"\n";
     print "\n";
     
     ($r_list0, $r_list1) = @lista;

     print '$r_list0->[1]:',$r_list0->[1],"\n";
     print '$r_list1->[2]:',$r_list1->[2],"\n";
    ───────────────────────────────────
     [結果]
     $lista[0]->[1]:d1
     $lista[1]->[2]:d5
     
     $r_list0->[1]:d1
     $r_list1->[2]:d5
    └──────────────────────────────────┘

 ◆無名リスト
 
  ・リストのリファレンスを直接得る方法もあります。
    $r_list0 = [0, 1, 2];
    $r_list1 = [3, 4, 5];
  
  ・この機能を利用して、データを階層的に記述することもできます。例えば、以下
   のような構造化されたデータを一つのリストで表現することもできます。
   
    ┌──────────────────────────────────┐
     名簿
     +------+----------+------+------------------------+-------------+
     | 番号 | 氏名   | 年齢 | スキル         | コメント  |
     +------+----------+------+------------------------+-------------+
     | 0  | 山田太郎 | 20  | 速記, 珠算, 簿記    |       |
     | 1  | 佐藤一郎 | 22  | 情報処理, ネットワーク |       |
     | 2  | 山本健太 | 18  | 特殊大型, SAJ1級    | 何故SKIが? |
     +------+----------+------+------------------------+-------------+
    
     $member = [
       [ # 番号[0]
         '山田太郎',     # 氏名   [0]->[0]
         '20才',       # 年齢   [0]->[1]
         [
           '速記',     # スキル  [0]->[2]->[0]
           '珠算',     # スキル  [0]->[2]->[1]
           '簿記'     # スキル  [0]->[2]->[2]
         ],
       ],
       [ # 番号[1]
         '佐藤一郎',     # 氏名   [1]->[0]
         '22才',       # 年齢   [1]->[1]
         [
           '情報処理',   # スキル  [1]->[2]->[0]
           'ネットワーク', # スキル  [1]->[2]->[1]
         ],
       ],
       [ # 番号[2]
         '山本健太',     # 氏名   [2]->[0]
         '18才',       # 年齢   [2]->[1]
         [
           '特殊大型',   # スキル  [2]->[2]->[0]
           'SAJ1級',    # スキル  [2]->[2]->[1]
         ],
         '何故SKIが?'    # コメント [2]->[3]
       ]
     ];

     print '1番->スキル->[1]:',$member->[1]->[2]->[1],"\n";
    ───────────────────────────────────
     [結果]
     1番->スキル->[1]:ネットワーク
    └──────────────────────────────────┘
  
  ・上記のように、1つのリファレンスから構造化データを参照できるようにするこ
   とは、今回はまだ説明しませんが「リファレンスカウント」を使用する際に意味
   を持ちます。
 
 ◆無名ハッシュ
 
  ・先ほど構造化されたデータをリストで表しましたが、「[1]->[2]->[1]」ではち
   ょっとわかりにくい部分があります。するとハッシュを使いたいと思うのが自然
   です。
  
  ・リストと同様にハッシュ自身も、直接リファレンスを得ることができます。
    $r_hash = {'名前' => '鈴木太郎', '年齢' => '20才'};
  
  ・すると先ほどリストで作成した「名簿」をもう少しわかりやすい形で表現するこ
   とが可能になります。
  
    ┌──────────────────────────────────┐
     $member = {
       '山田太郎' => {
         '番号'  => 0,
         '年齢'  => '20才',
         'スキル' => ['速記', '珠算', '簿記']
       },
       '佐藤一郎' => {
         '番号'  => 1,
         '年齢'  => '22才',
         'スキル' => ['情報処理', 'ネットワーク']
       },
       '佐藤一郎' => {
         '番号'  => 2,
         '年齢'  => '18才',
         'スキル' => ['特殊大型', 'SAJ1級'],
         'コメント' => '何故SKIが?'
       }
     };
     
     print $member->{'佐藤一郎'}->{'スキル'}->[1];
    ───────────────────────────────────
     [結果]
     SAJ1級
    └──────────────────────────────────┘
  
 ◆データの追加

  ・リファレンスのハッシュ/リストについてもデータの追加変更は従来と同じよう
   に行うことができます。

    ┌──────────────────────────────────┐
     $member->{'新メンバ'} = {
       '番号'   => 3,
       '年齢'   => 24,
       'スキル'  => ['鬼ごっこ', '隠れんぼ'],
       'コメント' => '謎のスキル...大人?'
     };

      print $member->{'新メンバ'}->{'スキル'}->[0];
    └──────────────────────────────────┘
  
  
  ・ここで例を示したようにPerlではデータの構造化をC++等に比べて容易に行うこ
   とができます。次回はサブルーチンの話に移っていきたいと思います。
   
  

(*1)サブルーチンのリファレンスを取得する方法もあります。

(*2)デリファレンスの表記には何種類かあるのですが、ここではMonpeの独断で「後か
  ら見やすいもの」を選んで書いています。

(*3)Perlにもオブジェクト指向プログラミングの概念が存在します。このときクラス内
  のメソッドや変数にアクセスする場合もアロー演算子を使用しますが、本講座では
  範囲外となるため、クラスについての詳しい説明はしません。

(*4)qw関数は、クォート(データ区切り)を「,」からホワイトスペース(半角空白,Tab,
  改行)に変更します。

[▲Perl Home▲]

Copyright(c)2005 Monpe
All Rights Reserved