Tcl – 手続きのモジュール化 -proc,return-

procコマンドは複数のコマンドをひとまとめにして手続きを作成します。作成した手続きは、Tclのコマンドと同じように利用できます。

この記事では手続きを作成するprocコマンドと手続きを実行した結果を返すreturnコマンドについて紹介します。

手続き(procedure)のモジュール化

手続き(procedure:プロシージャ)とは物事を行う順序や手順といった意味がります。これまで紹介してきたサンプルプログラムは、1プログラム1手続きで完結するものでした。

手続きが複雑になってくると、計算処理の手続き、判定処理の手続き、出力処理の手続きなど、それぞれ別々に分ける必要が生じます。

また、1つのプログラムの中で同じ手続きを何度も実行する場合に、同じ手続きを何度も記述するよりも、その手続きをモジュール化して再利用可能な部品(パーツ)として利用できると便利です。

Tclのprocコマンドは、一連のコマンドを1つの手続きとしてグループ化を行い、モジュールにして再利用できるようにします。procコマンドで作成した手続きは、Tclのコマンドと同じように、呼び出して利用することが出来ます。

同じような機能をもったものを、他の言語では、関数(function)、サブルーチン(subroutine)などと呼びます。「関数を定義(define)する」からとって def と呼ぶ言語もあります。

procコマンド

<procコマンドのイメージ>

[書式]

proc name args body

name : プロシージャ名
args : 引数
body : 一連のコマンド群

procコマンドは、一連のコマンドを1つにまとめて、name という名前の新しいプロシージャ(手続き)を作成します。

プロシージャ名の命名規則

  • 英字の大文字、小文字は区別される。
  • 変数名と同じ名前でもOK。
  • 文字の種類に制約はありません。日本語も使用できます。

引数はリストで列挙します。引数にはデフォルト値を設定することができます。引数を空のリストにすると引数を持たないプロシージャを作成することが出来ます。

プロシージャの実行結果は、プロシージャ本体の中で最後に実行されたコマンドの実行結果が呼び出し元に返されます。

returnコマンドを使用して特定の値を実行結果として返す事も出来ます。値を返す必要がある場合、returnコマンドを使って値を返すことがほとんどです。

[参考]
http://wiki.tcl.tk/463

[サンプル1] add.tcl

#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

proc add {n1 n2} {
    expr $n1 + $n2
}

# main

set a 3
set b 5
set c [add $a $b]
puts "$a + $b = $c"

[実行例1]

$ ./add.tcl
3 + 5 = 8

[説明]

使用例1は、プロシージャ名:add の引数に3と5を指定して呼び出し、実行結果を受け取って変数名:c に代入しています。

プロシージャの実行結果は、プロシージャ本体の中で最後に実行したコマンドの実行結果が戻り値として返されます。

例の場合は、「expr $n1 + $n2」の実行結果が返されます。

Tclの構文解析は上から順番に文法を解釈していきます。よって、プロシージャの定義は呼び出しの記述より前に記述する必要があります。

呼び出す命令を記述した後に定義を記述した場合、そのプロシージャを呼び出した際に「無効なコマンドです。」というエラーになります。

$ ./add.tcl
invalid command name "add"
    while executing
"add $a $b"
    invoked from within
"set c [add $a $b]"
    (file "./add.tcl" line 6)

[サンプル2] proc_test.tcl

# 引数の数
proc add {n1 n2} {
    expr $n1 + $n2
}

[実行例2]

% source proc_test.tcl
% add 6 9
15
% add 6
wrong # args: should be "add n1 n2"
% add 6 7 8
wrong # args: should be "add n1 n2"

呼び出し側はプロシージャの仮引数と同じ数の引数を与える必要があります。

wrong:違う should be:~のはずだ。~であるべき。

日本語に直すと「引数の指定が違いますよ。”add n1 n2″のはず」というような意味かな。

引数のデフォルト値

プロシージャの仮引数はデフォルト値を設定することが出来ます。デフォルト値を設定するには、引数名とデフォルト値をサブリスト(「{ }」で囲む)にします。

[サンプル3] proc_test2.tcl

# 引数のデフォルト値
proc add {n1 {n2 5}} {
    expr $n1 + $n2
}

[実行例3]

% source proc_test2.tcl
% add 3
8
% add 3 6
9

使用例3では n2 にデフォルト値:5 を設定しているので、呼び出す際に渡す引数は1つでも2つでも構いません。

可変個の引数

引数に args という名前を指定すると、可変個の引数を扱うことが出来ます。args はリスト型の変数として扱うことが出来ます。

[サンプル4] proc_test3.tcl

# 可変個の引数
proc average {args} {
    set sum 0
    foreach n $args {
        set sum [expr $sum + $n]
    }
    expr $sum / [llength $args]
}

[実行例4]

% source proc_test3.tcl
% average 1 2 3
2
% average 1 2 3 4 5
3
% average 41 53 62 65 76 86 92
67

空の引数

引数が不要な時は、引数を空のリストにすると引数を持たないプロシージャを作成することが出来ます。

[サンプル5] proc_test4.tcl

# 空の引数
proc getRandom {} {
    expr int ([expr rand () * 100])
}

[実行例5]

% source proc_test4.tcl
% getRandom
10
% getRandom
85

getRandomプロシージャは、0~99までの乱数を返します。

rand関数の使い方
ブログの[Tcl – 数学関数]>rand関数、srand関数 で紹介してます。

returnコマンド

returnコマンドを使うと、特定を値を返すことが出来ます。

[サンプル6] proc_test5.tcl

# 大きい値を返す
proc maxof {n1 n2} {
    if {$n1 > $n2} {
        return $n1
    } else {
        return $n2
    }
}

[実行例6]

% source proc_test5.tcl
% maxof 20 30
30
% maxof 50 40
50

[サンプル7] proc_test6.tcl

# 奇数・偶数の判定
proc oddEvenCheck {num} {
    if {$num % 2 == 0} {
        set result "$num is even number."    ;# 偶数
    } else {
        set result "$num is odd number."     ;# 奇数
    }
    return $result
}

[実行例7]

% source proc_test6.tcl

% oddEvenCheck 123
123 is odd number.

% oddEvenCheck 128
128 is even number.

コメント

タイトルとURLをコピーしました