第5章 関数

Luaに限らず,多くのプログラミング言語に欠かせない概念の一つとして関数というものが存在します. 実は今まで関数を何回も使っていました. 例えばprintですが,これは関数です.io.readも関数です. 関数とはいくつもの命令を集め1つの塊として定義したものです. 同じ処理を何回も行いたい場合は,関数を1つ定義して呼び出すだけでよいです.

関数の作り方

では,関数を作ってみましょう. 関数は次のように定義します.

書式

function 関数名( 引数 )
    処理
end

ここで,二つの値を引数として渡し,その和を求める関数を作ってみましょう.

function sum(x, y)
    return x + y
end

hoge = 10
piyo = 20

result = sum( hoge, piyo )
print( hoge .. " + " .. piyo .. " = " .. result )

実行結果

10 + 20 = 30

まずsum関数を使う前に,関数を定義しておかなければならない事に注意してください. 関数には好きな名前をつけてください.ただし,すでに使われている関数名や変数名は使わないでください. 例えば,printなどの名前をつけないでください. 関数命名のルールは変数の場合と同じです.

C言語との違い

プロトタイプ宣言は無い

さて,関数を呼び出す際に

sum( hoge, piyo )

としました. 関数を呼び出す際には引数と呼ばれるものを渡します. この引数とはどういったものでしょうか.

func

上図は引数の様子を示した図です. 呼び出した側の引数を実引数といい,呼び出された側の引数を仮引数といいます.

このとき,実引数の値が仮引数の値にコピーされます. つまり,

function func(x, y)
    x = 10
    y = 20
end

hoge = 12
piyo = 22
func( hoge, piyo )

print(hoge, piyo )

としても,x,y はhoge, piyoのコピーなので,中身をいくら書き換えても呼び出しもとのhoge, piyoには影響を及ぼしません.

引数に関して,もしかしたら何も受け取る必要が無い場合があるかもしれません. そういった場合は,引数の中は空にしておきます.

関数の戻り値に関しては次節で説明します.

関数の戻り値

関数には戻り値と呼ばれるものが存在しています. 前節のプログラムと下図を見てください.

image1

returnは値を関数を呼び出した側に返す命令です. よって,x + y の計算結果を呼び出し元に返しています. つまり,変数resultには計算結果が代入されます.

Luaは複数の値を戻り値として返すことができます. 例えば,次のようなことができます.

function func()
    return 10, 20
end

hoge, piyo = func()
print(hoge, piyo)

実行結果

10 20

hogeには10が,piyoには20が代入されます. では,次のようなコードを書いた場合どうなるでしょうか.

function func()
    return 10, 20
end

hoge = func()
print(hoge, piyo)

この場合,第2の戻り値である20は使われず消滅します.

実行結果

10    nil

また,次のようなコードを書いた場合はどうでしょうか

function func()
    return 10
end

piyo = 20

hoge, piyo = func()

print(hoge, piyo)

第2の戻り値はありません. この場合,piyoにはnilが代入されます. piyoは20ではないので注意してください.

実行結果

10      nil

何も返さない関数

戻り値の関数,つまり何も返さない関数を作ることもできます. その場合returnを書かなければ良いのです.

function func()
    print("関数が呼び出されました")
end

func()

実行結果

関数が呼び出されました

また,明示的に戻り値が無いことを示すため,returnだけを書くこともできます.

function func()
    print("関数が呼び出されました")
        return
end

func()

上記の二つのコードは全く同じものです.

変数に関数を代入する

Luaの変数にはどんな値でも代入することができます. たとえ関数であろうとも代入が可能です.例えば次のようなことも可能です.

function sum(x, y)
    return x + y
end

function mul(x, y)
    return x * y
end

hoge = sum
print("hoge is " .. type(hoge) );
print("10 + 20 is " .. hoge(10, 20) )

hoge = mul
print("10 * 20 is " .. hoge(10, 20) )

type関数は現在の変数の型を調べるものでしたね. hogeにはsum関数やmul関数を代入しています. そして,hogeを使い関数にアクセスすることもできます. C言語をご存知の方は関数ポインタのようなことができると思ってください

実行結果

hoge is function

10 + 20 is 30

10 * 20 is 200

関数中に関数を定義する

Luaでは関数内に関数を定義することも可能です.

function func(x)
    local function get()
        return x
    end

    local function add(value)
        x = x + value
    end
    return get, add
end

firstGetValue, firstAddValue = func(10)
secondGetValue, secondAddValue = func(30)

print("first value : " .. firstGetValue() )
print("second value : " .. secondGetValue() )

firstAddValue( 15 )
secondAddValue( 20 )

print("first value : " .. firstGetValue() )
print("second value : " .. secondGetValue() )

func関数はgetとadd関数を戻り値として返しています. ここでlocalという新しいキーワードが登場しました. このlocalについては有効範囲の章で詳しく説明します. 簡単に説明しておきますと,localというキーワードを付けることでローカル変数(またはローカル関数)を作成することができます. 要は,get関数もadd関数もfunc関数内からでしか呼び出せないということです.

実行結果

first value : 10
second value : 30
first value : 25
second value : 50

無名関数

名前無し関数を作成することも可能です. 例えば次のようなコードを書くことができます.

function createSquare()
    return function(x)
        return x*x
    end
end

square = createSquare()
print("10 * 10 is " .. square(10, 10) )

reateSquare関数は戻り値にx*xを行う関数を返しています.

実行結果

10 * 10 is 100

基本ライブラリ

ここでは,基本ライブラリに用意されている関数の一部を紹介します.

assert関数

定義

assert (v [, message])
assert関数はvが偽条件ならばエラーを発生させる関数です.
messageにはエラーメッセージを渡します. エラーメッセージは省略可能です.
hoge = true
assert( hoge, "Error #1")
hoge = false
assert( hoge, "Error #2")

実行結果

lua51m.exe: test.lua:4: Error #2
stack traceback:
    [C]: in function 'assert'
    test.lua:4: in main chunk
    [C]: ?

dofile関数

定義

dofile( filename)

dofile関数はfilenameで指定したファイルを実行する関数です. 例えば以下のようにして使います. 今回は二つのLuaファイル,test.luaとcall.luaにコードを記述しています.

-- call.lua
function testFunc()
    print ("Hello")
    return "World!"
end
-- test.lua
dofile("call.lua")

hoge = testFunc()
print( hoge )

実行結果

Hello
World!

dofileでcall.luaを読み込む事により,test.lua側で testFunc関数を利用することができます.

type関数

定義

type (v)

type関数は,データの型を返す関数です.

hoge = nil
print("hoge : " .. type(hoge))
hoge = 10
print("hoge : " .. type(hoge))
hoge = true
print("hoge : " .. type(hoge))
hoge = "Hello"
print("hoge : " .. type(hoge))

実行結果

hoge : nil
hoge : number
hoge : boolean

tonumber関数

定義

tonumber (e [, base])

tonumber関数は引数eを数値に変換する関数です. 数値変換が可能な場合は数値を返し,そうでなければnilを返します.

また,baseを指定すると,eをbase進法の数値として変換します. 省略すると,10が自動的に指定されます.

hoge = "25"
print("hoge :" .. hoge .. " type :" .. type( hoge ) )
piyo = tonumber( hoge )
print("piyo :" .. piyo .. " type :" .. type(piyo) )

実行結果

hoge :25 type :string
piyo :25 type :number

tostring関数

定義

tostring ( e )

tostring関数はeを文字列に変換する関数です.

hoge = 25
print("hoge :" .. hoge .. " type :" .. type( hoge ) )
piyo = tostring( hoge )
print("piyo :" .. piyo .. " type :" .. type(piyo) )

実行結果

hoge :25 type :number
piyo :25 type :string

数値から文字列に変換する際は,わざわざtostring関数を使用しなくても,空の文字列を追加するだけでよいです.

piyo = hoge .. ""