Gaiax TechEgg's Blog

非エンジニアがエンジニアを目指すブログ

基礎① 7.サブルーチンをやってみた

今回はサブルーチンについてです!
どんな時に役に立つのか、考えながらやっていきましょう!
配列、リファレンス、など今までの知識を
ふんだんに使うので復習にもなります:)

エンジニア基礎①
1. Perl環境基礎
2. Hello,world!
3. Perl基礎
4. 配列・for文
5. ハッシュ
6. リファレンス
7. ⭐️ サブルーチン ⭐️
8. 正規表現
9. Amon2 入門 第一部
10. Amon2 入門 第二部

ゴール?(めやす:30分)


  • サブルーチンがわかる
  • サブルーチンを作れる
  • リファレンス渡しができる

おさえておきたいこと


サブルーチン

意味や内容をひとまとまりにしたもののことをいいます。モジュール化ともいい、自分で関数を作成・定義するための手法です。そのため「ユーザ関数」と呼ばれたりもします。

たとえば、3人の教科ごとの平均を取りたいとき、
今までの方法なら、まず配列に挿入して合計や個数や平均の変数を定義して、計算して・・・という方法でしたが、

my @kokugo = (80, 70, 65);
my $count1 = 0;
my $sum1   = 0;
for my $score (@kokugo) {
    $sum1 += $score;
    $count1 ++;
}
print "$sum1 / $count1\n";


my @sugaku = (80, 88, 60);
my $count2 = 0;
my $sum2   = 0;
for my $score (@sugaku){
    $sum2 += $score;
    $count2 ++;
}
print "$sum2 / $count2\n";

.
.

サブルーチンだと、以下のように最初に平均を出す方法を定義することで、ひとつひとつの数字に対しての変数定義の数が減ったりや計算式などは省くことができます!

sub ave{
        my($i,$j,$k) = @_;
        my$sum = ($i+$j+$k)/3;
        return print"$sum\n";
}

my $kokugo = ave(80, 70, 65);
my $sugaku = ave(80, 88, 60);
.
.

何回もおなじことを繰り返したいとき、修正箇所を極力抑えたい場合など、サブルーチンを使うと簡単にできるようになるのです!

いざスタート!


1. サブルーチン

このようなサブルーチンがあったとします!

sub foo {
    my $hoge = shift @_;
    print "$hoge\n";
}
foo("hello,world!");
foo("hi,Bob!");

◼︎サブルーチンの設定

sub サブルーチン名 { 処理 }

上記の例だとfooが「サブルーチン名」で{ my $hoge ... }が処理内容になります。
サブルーチン名は変数名と同じようにつければOKです!大文字・小文字の英数字とアンダーバー(先頭も可)が使用可能です。*ただし、数字から始められないのでそこだけ注意です!

◼︎サブルーチンの呼び出し

サブルーチンを設定したら、

サブルーチン名 ("...");


で呼び出します。上記だと

foo("hello,world!");
foo("hi,Bob!");


の部分になります。()内に先ほど設定したサブルーチンが適用されます!

◼︎サブルーチンの引数

サブルーチンの引数には@_という配列を用います。
サブルーチンに与えられた引数が格納されている*@_は省略することができます。

sub foo {
    my $hoge = shift;
    print "$hoge\n";
}
foo("hello,world!");
foo("hi,Bob!");


2. サブルーチンをつくってみる!「add」

二つの引数を受け取り、その和を返すサブルーチン「add」をつくってみましょう。

sub add{
    my ($left, $right) = @_;
    return $left + $right;
}
my $result = add(7, 22);
print "$result\n";


29


サブルーチンに複数の引数が与えられた場合、配列のように,(コンマ)で区切って渡すと、$leftには7が、$rightには22が入ります。
返り値returnをつかうことで、任意のデータ($left + $right)を呼び出し、元へ返す($resultに格納する)ことができます。

3.返り値

◼︎返り値return複数ある場合

返り値が複数ある場合は以下の挙動になります。

sub compare {
    my ($i, $j) = @_;
    if ($i == $j) { 
        return "true";
    } else { 
        return "false";
    }
}

my $result = compare(4,4);
print "$result\n";


true


returnに達した場合はそれ以降の処理は全く行われず、終了します。今回の場合はi=j=4で最初の条件に正であったため、trueを呼び出し、$resultに格納しています。
i=4,j=5にした場合、以下のようになります。

sub compare {
    my ($i, $j) = @_;
    if ($i == $j) {
        return "true";
    } else {
        return "false"; 
    }
}

my $result = compare(4,5);
print "$result\n";


false


◼︎返り値をかかなかった場合

返り値returnをかかなかった場合の挙動をみてみましょう。

sub add{
    my ($left, $right) = @_;
    $left + $right;
}
my $result = add(7, 22);
print "$result\n";


29


返り値をかかなかった場合は、最後の実行結果である$left + $rightが適用されます。

4.リファレンスで引数をわたす方法

なぜサブルーチンにリファレンス!?とお思いの方、リファレンスを少し思い返してみましょう。

gaiax-techegg.hatenablog.com

「おさえておきたいこと」で「サブルーチンなどで引数をわたすときに複数の配列やハッシュが指定可能になります。」と記述しました。
配列は一次元しか取れないために、二次元以降にしたいときはリファレンスをしてスカラ値にしてからまた配列として格納します。
今までの学習を元にした方法とリファレンス渡しの方法を比べてみましょう。
配列@hoge``@fooの中身を二段に分け展開するサブルーチン「output」を作りましょう!

◼︎今までの方法

my @hoge = ("hoge", "fuga");
my @foo  = ("foo", "bar", "baz");
sub output {
    my (@array1, @array2) = @_;
    print "@array1\n";
    print "@array2\n";
}
output(@hoge, @foo);


hoge fuga foo bar baz
(空白の行)


なんで2つに分けた変数が一緒の行になってしまったのか??
my (@array1, @array2) = @_;hoge fuga foo bar baz@_に格納されます。しかし、printで出力する際に、@array1@array2の境がわからず、@array1hoge fuga foo bar bazすべてをいれてしまいます。

そこで以下のようなリファレンスで引数の渡しをします。

◼︎リファレンスで引数を渡す方法

my @hoge = ("hoge", "fuga");
my @foo  = ("foo", "bar", "baz");
sub output {
    my ($array1, $array2) = @_;
    print "@$array1\n";
    print "@$array2\n";
}
output(\@hoge, \@foo);


hoge fuga
foo bar baz

my ($array1, $array2) = @_;により、@_にスカラ値である$array1$array2つ入れます。これで出力する際に、先ほどみたいなことはおこりません!
スカラ値で設定しているのでoutput(\@hoge, \@foo);で呼び出すときはリファレンスを行い、配列変数からスカラ変数に変えます。
これがリファレンスで引数を渡している方法です。

リファレンスで渡す方法は同じようにハッシュの場合もできます。



サブルーチンは使えるようになるとすごく便利なので
ぜひ使いこなしたいですね!!!


次回は正規表現についてです!!
正規表現とっても楽しいですよ!
Perlでは「正規表現」でまるまる一冊本があるくらい奥深いですが、
やってみるととっても楽しい!!

*部分は内容補足しました(9/7)