見出し画像

ハジメの一歩会⑤ 関数編

こんばんは、かーでぃです。
残すところ、ハジメの一歩会もあと2回となりました。今回は関数編をお届けいたします。

関数とは?に入るまえに、やっぱり自分と関数の出会いから…笑
そう、自分がやった頃のBASICに関数なんてなかったんです(ま、サブルーチンはありましたが…)。
とか言ってたら、QuickBasic4.5にはあったよ、と(笑)
懐かしいですね。Basicなのに行番号をなくして構造化プログラムっぽいことができましたよね。自分が書いていたのはN88-BASICでした。まさに下のような感じで、「THE BASIC」だったので、行番号は必須でしたし、GOTO文であっちに飛んだり、こっちに戻ったりで…プログラムはごちゃまぜスパゲッティでした!!!(ホントに、ぐちゃぐちゃです)
一度、人の作ったBASICの解析を頼まれたことありましたが、断念しました…。追いきれない…。

関数の話に入る前に、変数のスコープの話。第一回でローカル変数とグローバル変数の話をしたのですが、覚えてますか?
・Aブロックの中で宣言している変数aは、Aブロックの中のみ有効。
・Bブロックの中で宣言している変数bは、Bブロックの中のみ有効。
・Cブロックの中で宣言している変数cは、Cブロックの中のみ有効。
なので、Aブロックの中で変数bやcを使おうとしてもエラーになります。
このように宣言したブロックの中でしか使えない変数をローカル変数と呼びます。
一方、どのブロックでも使える変数をグローバル変数と呼びます。
それぞれのメリット/デメリットは下の表にありますが、グローバル変数は確かに楽です。が、それ以上にデメリットが大きいので、必要最低限にした方が無難だと思います。
実際、プログラミングをしてみれば、概ねローカル変数で事足りてしまいます。

これからやっと関数の説明です。長かったですね、、、
関数の目的としては下記があります。

・同じ処理を切り出すことで、一元管理できるようになる&可読性が上がる
・ローカル変数を利用することで、意図しないバグを減らせる
・ロジックのブラックボックス化です。

この中で、一番下のブラックボックス化が関数を利用する上で一番のメリットかな、と思っています。
例えば、エクセル関数のvlookup。中身はわかりませんがパラメータを正しく与えてあげれば、目的の値を取得できますよね。
このように、関数自体の中身を知らなくても、関数の目的や使い方さえしっていれば結果を得られるのが、関数のいいところです。

じゃ、その関数をどう使えばいいのか、というのがこちらになります。

・関数に渡すパラメータのことを「引数」
・関数から得られる値のことを「戻り値」と呼びます。

例として挙げたのは、曜日を漢字で取得するための関数になります。C#とPythonで書いてありますが、どちらも同じ内容です。
日付型のdteSpecDateを引数として受け取り、その曜日を番号で取得した上で、配列を使って漢字に変換して戻しています。
ここでは引数は1つだけですが、複数の値を指定することもできます。一方、戻り値は原則1つと思ってください。複数戻すやり方もありますが、まずは1つだけ返す、と思って頂いて大丈夫です。

ということで、実際に関数を作ってみよう!という問題です。
問題①は、素直な問題。
問題②は、先ほど戻り値は原則1つ!と言ったくせに、複数返す方法を問題に出すという(笑)
ただ、ここまでに習ってきたやり方を使えば、できちゃいますね!

下のプログラムが、C#による回答例になります。
getSyainName関数が、問題①の答え。
getSyainInfo関数が、問題②の答えとなります。
問題②の複数の値を戻り値として設定するのに、配列変数をつかっています。
※ちなみに、下にあるmain関数はC系で最初に実行される関数になります。

public class Hello{
    private static string getSyainName(int intSyainID)
    {
        string[] name = {"安室零","小林隼人","八島未来","浦木孝"};
        string ret;
        
        if(intSyainID>=0 && intSyainID<=3){
            ret=name[intSyainID];
        }else{
            ret="";
        }
        return(ret);        
    }

    private static string[] getSyainInfo(int intSyainID)
    {
        string[,] info = {
            {"安室零","amuro@wb.com","5135"},
            {"小林隼人","kobayashi@wb.com","5165"},
            {"八島未来","yashima@wb.com","2351"},
            {"浦木孝","uraki@albion.com","9-5193"}
            
        };
        string[] ret = new string[3];

        if(intSyainID>=0 && intSyainID<=3){
            ret[0]=info[intSyainID,0];
            ret[1]=info[intSyainID,1];
            ret[2]=info[intSyainID,2];
        }else{
            ret=null;
        }
        return(ret);        
    }

    public static void Main(){
        // Your code here!
        const int NAME = 0;
        const int MAIL = 1;
        const int EXT = 2;

        string[] info = getSyainInfo(0);

        System.Console.WriteLine(getSyainName(0));

        System.Console.WriteLine(info[NAME]);
        System.Console.WriteLine(info[MAIL]);
        System.Console.WriteLine(info[EXT]);

    }
}

配列以外にも、色々とやり方はあるようです。
個人的には、まずは戻り値1つだけ返す方法で組んでみて、どうしても処理が煩雑になる、複数返さないと先に進まない、等の理由が出来たときにチャレンジしてみるのがいいかな、と思います。

ちょっとだけ雑学です。

記憶の片隅にでも残っててくれた嬉しいな、程度ですので読み飛ばして頂いてもかまいません。
※ノーコードツールだと、この辺りはおそらく実装されていないので、ホント読み飛ばして大丈夫ですw

初心者のうちは、この辺りを意識しなくてもプログラミングは進めれます。壁にぶち当たったとき、崖に落ちそうになった時、参照渡しが助けてくれるかもしれません。

引数には、「値渡し」と「参照渡し」があります。
下の図は、kerdy関数→yurimy関数を呼んでいます。yurimy関数は引数を100倍にして返してくれる関数です。
黄色の四角は、値渡しで実施しています。一方、ピンクの四角は参照渡しで実施しています。
それぞれ結果が…
 黄色(値渡し) a=100 / b=10000
 ピンク(参照渡し) a=10000 / b=10000
となります。
値渡しの場合、引数aの「値」を変数bにコピーして処理をしています。
一方参照渡しの場合は、引数aの別名を変数bとして処理しています。
変数bは、変数aの別名なので変数aと同じ「場所」を参照しています。
場所、というのは変数が格納されたコンピュータ上のアドレスのことですね。

ぐだぐだと書きましたが、この辺りはちょっと記憶に残ってくれてればうれしいですが、忘れてもらっても問題ありません。
必要な時には、きっとこの辺りにたどり着くはずです。そしたら、「あ、このことね」と思い出して頂けると、うれしいですw

というわけで宿題です。

繰り返し処理編で出てきたプログラムですね。これを前半部と後半部を関数にしてみてください。
またご自身で作られたプログラムと下のプログラムを比較してみて、如何でしょうか?
プログラム自体が短いので実感があまりわかないかもしれませんが、恐らく関数化したプログラムの方が見やすくなっているかと。下のwhile文の中が、随分簡素になっているはずです。簡素になっていれば、パッと見でロジック全体が見えるので、可読性があがり、その分メンテナンス性もあがります。

宿題の回答


資料はこちら


この記事が気に入ったらサポートをしてみませんか?