Perl Hackers Hub

第72回初学者に伝えたい Perl学習の勘所 ―勉強会を10年運営して培ったノウハウ(2)

前回の(1)こちらから。

よくある質問への回答

ここでは、Perl入学式でよく寄せられる質問と、それに対する回答を紹介します。

変数名の左にある記号がコロコロ変わって理解できない

Perlには、変数の種類によって変数名の前に付くシジルと呼ばれる記号があります。スカラは$配列は@ハッシュは%がシジルとして変数名の前に付きます。同じ変数名であっても、異なるシジルが付いていれば別の変数として扱われます。

シジルが$のスカラは、1つの値を保持する変数です。この値は、数値、文字列、そして後述するリファレンスのいずれかです。スカラが保持可能な値はスカラ値と呼ばれます。

シジルが@の配列とシジルが%のハッシュは、複数のスカラ値を要素として含む変数です。配列やハッシュの1要素であるスカラ値にアクセスするときは、シジルが$に変化します。サブルーチンの戻り値として配列を受け取るときは、シジルが@の配列に代入します。ハッシュリファレンスをデリファレンスしたものは、シジルが%のハッシュに代入します。

自分が操作したい対象を意識できると理解が進み、適切なシジルを選択できます。

配列とハッシュを使い分けられない

初学者であっても、スカラ値を格納するだけのスカラの理解は容易です。しかし、配列とハッシュは、ともに要素の集合を扱う用途のため、配列を使うべき場面でハッシュを使う(あるいはその逆)など、すぐに理解して使いこなすのは難しいようです。

配列は、要素を順番に処理する場面で活用します。

array_sample.pl
# 配列によるデータ管理例:出席番号順生徒名簿
my @members = ('Alice', 'Bob', 'Carol', 'Dave');
# 順番に表示する
for my $member (@members) {
    print "name: $member\n";
}

ハッシュは、要素に名前を付けて、必要な要素を名前で取り出せると便利な場面で活用します。そして、配列とは異なり順不同です。

hash_sample.pl
# ハッシュによるデータ管理例:テストの成績管理
my %score = (Japanese => 75, English => 80);
# 英語の点数を表示
print "English score: $score{English}\n";

配列とハッシュそれぞれの特徴を把握すると、正確に使い分けることができます。

初歩的文法を理解できているか不安

15年ほど前に話題になったFizzBuzz問題を解いてみましょう。

1から100までの数をプリントするプログラムを書け。ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、3と5両方の倍数の場合には「FizzBuzz」とプリントすること。

─⁠─ Jef Atwood著/青木靖訳どうしてプログラマに・プログラムが書けないのか?⁠ 2007年

この問題を解くためには、順次処理、変数、配列、条件分岐if文⁠⁠、論理演算子、繰り返しfor文)の適切な組み合わせが必要です。

fizzbuzz.pl
# 配列の使用
my @numbers = (1 .. 100);

# for文による繰り返し処理。変数へ値の格納
for my $num (@numbers) {

    # if文による条件分岐処理
    if ( $num % 3 == 0 && $num % 5 == 0 ) {
        print 'FizzBuzz' . "\n";
        } elsif ( $num % 3 == 0 ) {
        print 'Fizz' . "\n";
    } elsif ( $num % 5 == 0 ) {
        print 'Buzz' . "\n";
    } else {
        print $num . "\n";
    }
}

このFizzBuzz問題をスムーズに解ければ、初歩的文法の理解は十分と言えます。

リファレンスを使う理由がわからない

受講生から、リファレンスを使う理由がわからないという意見がよく寄せられます。使う理由がわからないから使わない、使わないから理解が進まないといった悪循環を繰り返し、結果的にPerlの学習を挫折する人もいます。

Perlのスカラには1つの値しか代入できません。配列やハッシュの要素として、別の配列やハッシュ全体を直接格納することはできません。

リファレンスは、実データがある場所を指し示すスカラ値です。配列やハッシュのリファレンスは、スカラに代入したり、配列やハッシュの1要素として格納できます。これを利用すれば、配列とハッシュが入れ子となる複雑なデータ構造を扱えます。

data_struct.pl
# リファレンスを利用し、複雑なデータ構造を扱う
my %person1 = (
    name => 'xtetsuji',
    mail => 'xtetsuji@example.com'
);
my %person2 = (
    name => 'sironekotoro',
    mail => 'sironekotoro@example.com'
);
my %person3 = (
    name => 'tomcha',
    mail => 'tomcha@example.com'
);
my @people = ( \%person1, \%person2, \%person3 );
# 情報を一覧表示する
for my $person (@people) {
    my $name = $person->{name};
    my $mail = $person->{mail};
    print "$name さんのメールアドレスは $mail です\n";
}

リファレンスを使う理由を理解し、応用的に使うことが理解への早道となるでしょう。

変数の中身が意図しない値になる

変数に格納された数値や文字列をコピーしてほかの変数へ渡した場合、それぞれの値への変更は互いに影響を受けません。これを値渡しと呼びます。

それに対してリファレンスをコピーしてほかの変数へ渡した場合、同一の値への参照を共有するため、それぞれの参照先への変更は互いにすべて反映されます。これを参照渡しと呼びます[1]⁠。

値渡しと参照渡しの違いは、次のコードの実行結果で確認できます。

reference_data_change.pl
# 値渡し時の挙動
my $number1 = 10;
my $number1_dup = $number1; # コピーを代入
$number1_dup *= 100;
print "もとのデータ: $number1\n"; # => 10
print "渡し先のデータ: $number1_dup\n"; # => 1000

# 参照渡し時の挙動
my $number2 = 10;
my $number2_ref = \$number2; # リファレンスを代入
$$number2_ref *= 100;
print "もとのデータ: $number2\n"; # => 1000
print "渡し先のデータ: $$number2_ref\n"; # => 1000

値渡し時のコードでは、コピーを渡した先の変数$number1_dupに加えた変更は、コピー元の変数$number1の値には影響しません。参照渡しのコードでは、参照している変数$number2_refに加えた変更が、参照されている変数$number2の値にも適用されます。

値渡しと参照渡しの特徴を理解して使い分けましょう。

エラーが発生したときはどうすればよいか

自分が書いたプログラムが思ったとおり動かないときはどうしたらよいのでしょうか。エラーが発生したときは、まず最初にエラーメッセージを読みましょう。

エラーメッセージに書かれたことすべてを理解するのは難しいですが、その一部をヒントに間違った箇所の見当を付けましょう。

エラーメッセージを読んでみよう

次のコードでは、1円の所持金を毎日倍にしていくと1ヵ月後にいくらになるかを計算しています。

double_money.pl
use strict;
use warnings;

my $money = 1;
for my $day (1 .. 31) {
    $money *= 2 …(1)
    print "$day 日後は $money 円\n"; …(2)
}
print "最終的に $money 円になりました\n";

ただし、間違いが1ヵ所含まれているので、コードの実行時にエラーメッセージが出力されます。

syntax error at double_money.pl line 7, near "print"
Execution of double_money.pl aborted due to
compilation errors.

エラーメッセージを読んでみましょう。

エラーメッセージの先頭に、syntax errorと書かれています。syntaxは日本語で構文を意味し、文法的な誤りがあることがわかります。

続いて、at double_money.pl line 7と書かれています。これは、double_money.plに書かれたコードの7行目という意味です。Perlがコードを先頭から順に実行していった結果、7行目でエラーとなったことを意味し、7行目あたりに間違いがあるのだろうと推察できます。

エラーの原因を見つけよう

7行目の(2)にはprint処理が書かれていますが、特に文法的な間違いは見当たりません。

そういうときは、前後、特に前の処理を追いかけると問題箇所にたどり着けることが多いです。6行目の(1)をよく見ると、$money *= 2の後ろに文末に必要な;が抜けていることがわかります。このため、6行目と7行目が1つの文としてPerlに解釈され、syntax errorが出力されています。

英語を苦手とする人も多いですが、エラーメッセージの一部だけでも読んで、問題箇所の見当を付けましょう。また、文末の;の書き漏れはよくあるミスなので注意してください。

コミュニティに参加しよう

プログラミングをゼロから学んでいくうえで、疑問点を独学で解消し、モチベーションを維持することは大変です。

各プログラミング言語にはユーザーによるコミュニティがあり、PerlにはPerl Mongersというコミュニティが世界各地にあります。また、日本国内では年に1~2回のペースでYAPC::Japanというカンファレンスが開催されています。YAPCでは、Perl Mongerたちの熱い発表やPerlに関する情報交換が行われています。

コミュニティに参加することで、Perlの熟練者に直接教わることができます。コミュニティに参加して得た知識や仲間は、普段の職場のつながりとは異なる次のような相乗効果をもたらします。

  • 大規模なカンファレンスに参加する楽しみが増える
  • 運営スタッフとしてカンファレンスの裏側を知ることができる
  • 技術系の執筆や、登壇の機会が得られる
  • 転職についての情報が得られる

これらを体験・経験することで、学習を持続するモチベーションが上がります。自分に合うコミュニティを見つけて参加しましょう。

もし自分が必要とする勉強会やコミュニティが見つからなければ、自ら作るのも一つの手です。Perl入学式も、そのようにして始まりました。

Perl入学式に参加しよう

Perl入学式は、プログラミング初学者のためにできるだけハードルを低くしたコミュニティです。小学生から還暦すぎまでさまざまな年代の人が参加します。

Perl入学式のカリキュラムは、プログラミング初学者が最低限知っておくべき項目を厳選しています。主な講義内容は、環境構築、基本的な変数、制御構造、サブルーチン、正規表現、リファレンスです。

また、Perl入学式では、講義に参加できなかった人や講義後に疑問がわいた人のために、チャットツールのDiscordを使用して、環境構築時のトラブルや質問に対応するサポートを行っています。

自分なりに頑張って勉強しても解決できないことはたくさんあります。筆者がPerl入学式の受講生としてプログラミングを学び始めたときは、講師の人に書いたコードとエラーメッセージをメールで送り、直接アドバイスをもらったこともありました。

初学者でも安心して参加できるコミュニティで、さまざまな気付きを得ながら楽しく成長しましょう。

まとめ

Perlは現在でもサーバの保守運用業務の領域で役立つなど、Perlをゼロから学ぶ価値は十分にあります。本稿を参考にPerlの環境を構築して、プログラミング学習の最初の一歩を踏み出してください。そして、Perlのコミュニティに参加して世界を広げましょう。

さて、次回の執筆者はmangano-itoさんと中岡大樹さんで、テーマは「PerlでつくるGraphQL API」です。お楽しみに。

WEB+DB PRESS

本誌最新号をチェック!
WEB+DB PRESS Vol.130

2022年8月24日発売
B5判/168ページ
定価1,628円
(本体1,480円+税10%)
ISBN978-4-297-13000-8

  • 特集1
    イミュータブルデータモデルで始める
    実践データモデリング

    業務の複雑さをシンプルに表現!
  • 特集2
    いまはじめるFlutter
    iOS/Android両対応アプリを開発してみよう
  • 特集3
    作って学ぶWeb3
    ブロックチェーン、スマートコントラクト、NFT

おすすめ記事

記事・ニュース一覧