┌──────────────────┐
│Perl入門 〜構造化プログラミング編〜 │
│(1)変数とコンテキスト        │
│2005/09/03             │
└──────────────────┘

[▲Perl Home▲]

●スカラー変数

 ・あるプログラミング言語を使いこなすには、概要言語の「データに対する考え方」
  をしっかりと把握するのが早道です。ここではPerlの3種類の変数
   + スカラー変数
   + 配列
   + ハッシュ
  について、その構造を解釈していきたいと思います。

 ◆スカラー変数に関する疑問
 
  ・Perlのスカラー変数は、データ型によらず全ての「単一値」を格納することがで
   きます。
    ┌──────────────────────────────────┐
     $sVal = 100;      # 数値
     $sChr = 'a';      # 文字
     $sStr = 'Taro Suzuki'; # 文字列(単一値?)
    └──────────────────────────────────┘
  
  ・しかし 'a'等の1byte文字は単一値であるとしても、'Taro Suzuki'等の文字列は
   単一値であると言えるでしょうか?
  
  ・しかもC言語等と異なって、特にデータ型を指定する必要も無い上に、数値/文字
   を都合よく解釈させることもできます。いったい、何故こんなことができるので
   しょうか。
    ┌──────────────────────────────────┐
     $a = 100;
     $b = 200;
     print '数値解釈 :', $a + $b,"\n";
     print '文字列解釈:', $a . $b,"\n";
    ───────────────────────────────────
     [結果]
     数値解釈 :300
     文字列解釈:100200
    └──────────────────────────────────┘

 ◆スカラー変数の構造
 
  ・恐らくですが、Perlのスカラー値は、下記のようなマルチバイトデータ構造にな
   っていると想像できます。
    ┌──────────────────────────────────┐
     データ : $a = 'あいうえお';
    
     (データの本体)
      先頭アドレス「a」: リンク時に割付
         ↓
         ┌──┐
        a:│1000│→┐アドレスaが示す場所には、数値データとして
         └──┘ │実データの置き場所(アドレス1000)が入っている。
              │これはOS/インタープリタが与える
              ↓
              ┌─────┬─┐
           1000:│あいうえお│E│
              └─────┴─┘
                     ↑
                     スカラー値最後を意味する番兵データ
    
     (変数名とデータの中身)
      ・変数自身はデータへのアドレスである。(*1)
      ・「$」を付けるとアドレスが示すデータにアクセス。
      ・つまり、上記の例に対しては
        + aの値は「100」というアドレスを示す。
        + $aは「100番地のデータ」を意味する。(よって$は単項演算子)
      ・簡単に言うとC言語のポインタに近い。
    └──────────────────────────────────┘

  ・C言語との違いでは、Cの場合変数を定義する際、その型(メモリサイズ上大きさ)
   も指定します。よって宣言された型によりデータの置かれ方が異なります。例え
   ば数値データとして宣言された変数は、OS/コンパイラ規定バイトのchar列とは
   異なるフォーマットにてメモリ上に置かれます。当然Perlのように、ご都合主義
   で数値解釈したり文字列解釈(*2)したりすることはできません。
   
  ・Perlの場合、全てのデータを文字列に近い形で認識するので、変数の演算子に応
   じてデータの解釈を変えることができるようです。ただし数値データについては
   それらを文字列とみなす分、メモリ確保サイズが大きくなる傾向にあると予想し
   ています。


●配列
 
 ◆配列データの構造
 
  ・スカラー変数の構造から容易に類推できると思いますが、配列は文字通りスカラ
   ー変数を配列にしたものです。
  
  ・先ほどスカラー変数については「C言語のポインタに近い」と説明しました。つ
   まりPerlの配列は「ポインタ配列」と解釈できます。
    ┌──────────────────────────────────┐
     @list = ('toride', 'fujishiro', 'ushiku', 'hitachinoushiku');
    
             ┌───┐       ┌───┬─┐
      list+Index×0:│addr_0│-----> addr_0:│toride│E│
             ├───┤       ├───┴─┼─┐
      list+Index×1:│addr_1│-----> addr_1:│fujishiro │E│
             ├───┤       ├───┬─┼─┘
      list+Index×2:│addr_2│-----> addr_3:│ushiku│E│
             ├───┤       ├───┴─┴──┬─┐
      list+Index×3:│addr_3│-----> addr_4:│hitachinoushiku │E│
             └───┘       └────────┴─┘
    └──────────────────────────────────┘

  ・上手の「Index」は「アドレスデータ格納限定」のメモリ確保サイズです。実際
   に配列化されてるのは実データの置き場所アドレスデータです。

  ・この構造であれば、データの追加/挿入についても、実データ用のメモリ領域を
   確保した後、それをアドレステーブルに登録するだけなので、リストの実装も簡
   単にできると考えられます。

 ◆配列のスライス
 
  ・ある意味配列の一部を扱うことも可能なはず。これを「スライス」と呼びます。
  
  ・ターゲットデータとする配列のインデックスが指定できれば良いので、これを
   「構文」として認識させる記述法を理解すれば良いのです。
    ┌──────────────────────────────────┐
     @list[2,4,5] = ('kamihongo', 'minoridai', 'yahashira');  (1)
    
     @lidx = (2, 4, 5);
     @list[@lidx] = ('kamihongo', 'minoridai', 'yabashira');  (2)
     ※(1)と(2)は同じです。
    
    └──────────────────────────────────┘

 ◆未定義のIndex
 
  ・未定義のIndexに値を設定することができます。例えば、現在の最終Indexが10だ
   として、14等「間が空いて」いてもOKです。
  
  ・このとき、飛ばされた[11,12,13]インデックスは「undef」の値を持ちます。以
   下に例を示します。
    ┌──────────────────────────────────┐
     @list = ('shinden', 'minoridai', 'yabashira');
     $list[4] = 'goko';
     $list[6] = 'kunugiyama';
    
     for ($i=0; $i<@list; $i++) {
       if (defined($list[$i])) { # undefならfalse
         print "$list[$i]\n"
       } else {
         print '!!undef!!',"\n";
       }
     }
    ───────────────────────────────────
     [結果]
     shinden
     minoridai
     yabashira
     !!undef!!
     goko
     !!undef!!
     kunugiyama
    └──────────────────────────────────┘

 ◆リストの平坦化
 
  ・二つの配列
     @list0 = (1, 2, 3 );
     @list1 = (10, 20, 30);
   があった場合、この配列を
     (1, 2, (10, 20, 30), 3)
   と表記すると、この配列は
     (1, 2, 10, 20, 30, 3)
   という一つの配列と認識されます。
  
  ・また
     @lista = (@list0, @list1);
   と表記しても、ソースとなる2つの配列は平坦化され
     @lista = (1, 2, 3, 10, 20, 30);
   と表記した場合と同じ結果になります。
   
  ・Perlの配列には、この「平坦化」があることをよく覚えておいてください。これ
   は後に扱う「サブルーチン」において重要となります。


●ハッシュ

 ◆Perlのハッシュ
 
  ・先ほど配列の説明で「未定義のIndexに値が設定できる」と書きました。Perlの
   配列は、実体データの大きさによって変わらないようにできているとすれば、
   Indexの指定は自由度が高くなるでしょう。
  
  ・つまりハッシュの実装も難しくありません。keyのハッシュ整数値でIndex付けし
   た配列とすれば良いのです。
 
 ◆ハッシュのスライス
 
  ・ハッシュも配列と同様にスライスが有効です。
    ┌──────────────────────────────────┐
     %hash = ( ch4 => 'nihon',
          ch6 => 'tbs',
          ch8 => 'fuji',
          ch10 => 'asahi',
          ch12 => 'tokyo');
     print "@hash{'ch4', 'ch8', 'ch12'}\n";
    ───────────────────────────────────
     [結果]
     nihon fuji tokyo
    └──────────────────────────────────┘
  
  ・スライスした結果はリストとして扱うことができます。
  
  ・またエントリ値の割り当てにも適用できます。
    @hash{'ch4', 'ch8'} = ('nittere', 'sankei');


●コンテキスト

 ◆コンテキストとは
 
  ・スカラー変数の説明にて「Perlは数値/文字を都合良く解釈する」と説明しまし
   た。Perlでは、オペレータ(演算子)とオペランド(被演算子)の組み合わせを解釈
   しています。
 
  ・この解釈ですが、文字通り「コンテキスト」と呼ばれています。コンテキストに
   は大きく分けて2種類あり
     + スカラーコンテキスト
     + リストコンテキスト
   があります。
 
  ・コンテキストは、オペレータの右辺に置かれるオペランド、又は特定のオペレー
   タを使用することで決められます。
    ┌──────────────────────────────────┐
     @list = (0,'val0',1,'val1');
     $list_c = @list;      # スカラーコンテキスト(要素数)
     print "scalar : $list_c\n";
    
     ($list_0, $list_1) = @list; # リストコンテキスト
     print "list : $list_0, $list_1\n";
    
     %hash = @list;       # リストコンテキスト
     while (($key, $val) = each(%hash)) {
       print "hash : $key, $val\n";
     }
    ───────────────────────────────────
     [結果]
     scalar : 4
     list : 0, val0
     hash : 1, val1
     hash : 0, val0
    └──────────────────────────────────┘

 ◆スカラーコンテキストの種類
  
  ・スカラーコンテキストには、明示的なものとして
    + 数値コンテキスト   (numeric)
    + 文字列コンテキスト  (string)
   そして特殊なものとして
    + ブール値コンテキスト (bool)
   が存在します。
  
  ・数値/文字列コンテキストは最初に説明しているでしょう。ブール値コンテキス
   トは、条件判断が論理値(ブール値)すなわち真/為として解釈するコンテキスト
   です。
    ┌──────────────────────────────────┐
     @list = ('aaa', 'bbb', 'ccc', 'ddd');
    
     while (@list) {
       $buf = shift(@list); # List要素出す
       print "$buf\n";
     }
    ───────────────────────────────────
     [結果]
     aaa
     bbb
     ccc
     ddd
    └──────────────────────────────────┘
   
  ・上記の例では、while中の条件判断で @list をスカラーコンテキストで受けてい
   ますが、要素の有る無しをブール値として判定しています。
  
  ・コンテキストの考え方は、変数だけでなくサブルーチンの戻り値にも適用されま
   す。これについては、サブルーチンのところで説明したいと思います。
  
  
  ・次回は、リファレンスとデータ構造を扱います。
  

(*1)アドレスは、データサイズに従ってダイナミックに再割付される可能性もあるので
  プログラムリンク時に固定されると言い切れません。よって「ラベル」とは異なる
  と考えています。

(*2)変換の関数はありますが、それは文字列として定義された変数(ポインタ)へ割り付
  けねばいけません。

[▲Perl Home▲]

Copyright(c)2005 Monpe
All Rights Reserved