1. ホーム
  2. スクリプト・コラム
  3. ルア

Luaプログラミングにおける例外処理の解析

2022-02-10 19:45:07

 必要なエラー処理

実際の業務では、ファイル操作、データベーストランザクション、Webサービス呼び出しなど、複雑な操作を必要とすることが多いため、エラー処理が必要です。機密情報や金銭の取引が絡む場合、大きな損失をもたらす誤操作を気にする人はいない。

どんなプログラミングでも、エラー処理は必ず必要です。エラーには2種類あり、特に次のようなものがあります。

  •     シンタックスエラー
  •     ランタイムエラー

シンタックスエラー

演算子や式など、プログラムのさまざまな構成要素において、不適切な使用によって生じる構文エラー。簡単な例でのシンタックスエラーを以下に示します。

コピーコード コードは以下の通りです。
a == 2

ご存知のように、シングル・イコールとダブル・イコールの使い分けがあります。どちらか一方を使用すると、エラーが発生する可能性があります。イコールは、代入、比較を意味します。同様に、表現とその意図する実装はこれらの方法です。

また、構文エラーの例として、以下のようなものがあります。

コピーコード コードは以下の通りです。
for a= 1,10
   print(a)
end

上記のプログラムを実行すると、次のような出力が得られます。

コピーコード コードは以下の通りです。
lua: test2.lua:2: 'do' expected near 'print'

構文エラーは、Luaの説明にあるように、実行時エラーの場合よりもエラーの位置が明確になるため、実行時エラーではないプログラムでは扱いやすいと言えます。上記のエラーから、print文の前にdo文を追加することは、Luaのすべての構成で必要であることが簡単に分かります。
ランタイムエラー

実行時エラーが発生した場合、プログラムは正常に実行されますが、入力にエラーが発生したり、不適切な処理が行われたりして、機能的な実行時エラーが発生することがあります。ランタイムエラーを示す簡単な例を以下に示す。

コピーコード コードは以下の通りです。
function add(a,b)
   return a+b
end

add(10)

プログラムをビルドすると、正常にビルドされ実行されます。実行すると、実行されてランタイムエラーが表示されます。

コピーコード コードは以下の通りです。
lua: test2.lua:2: attempt to perform arithmetic on local 'b' (a nil value)
stack traceback:
 test2.lua:2: in function 'add'
 test2.lua:5: in main chunk
 [C]: ?

2つの変数を渡していないため、実行時エラーが発生します。b パラメータの期待値は nil であり、エラーが発生する。
メンテナンス・障害対応機能

エラーを処理するために、assertとerrorの2つの関数を使うことが多い。簡単な例を以下に示す。

コピーコード コードは以下の通りです。
local function add(a,b)
   assert(type(a) == "number", "a is not a number")
   assert(type(b) == "number", "b is not a number")
   return a+b
end
add(10)

上記のプログラムを実行すると、以下のようなエラー出力が得られます。

コピーコード コードは以下の通りです。
lua: test2.lua:3: b is not a number
stack traceback:
 [C]: in function 'assert'
 test2.lua:3: in function 'add'
 test2.lua:6: in main chunk
 [C]: ?

Error error (message [, level]) は、最後に呼び出された保護関数を終了し、そのメッセージに対するエラーメッセージを返します。この関数のエラーは返されません。通常、errorはメッセージの最初にエラーの場所に関する情報を追加します。 levelパラメータは、エラーの場所を取得する方法を指定します。レベル1(デフォルト)では、エラー関数が呼び出された場所がエラーの場所となります。レベル2は、エラーの場所を、エラーが呼び出された関数で割ったものなど。レベル0を渡すと、メッセージにエラーの場所に関する情報を追加することを避けることができる。
pcallとxpcall

Luaでこれらのエラーを発生させないようにプログラミングし、エラーを処理するには、pcallまたはxpcallという関数を使用する必要があります。

pcall (f, arg1, ...) 関数呼び出し保護モードが要求する関数です。関数fで何らかのエラーが発生しても、エラーを発生させない。エラーの状態を返すだけである。pcallの簡単な使用例を以下に示す。

コピーコード コードは以下の通りです。
function myfunction ()
   n = n/nil
end

if pcall(myfunction) then
   print("Success")
else
 print("Failure")
end

上記のプログラムを実行すると、次のような出力が得られます。

コピーコード コードは以下の通りです。
Failure

xpcall (f, err) 関数は要求された関数を呼び出し、またエラーハンドラを設定します。 f どんなエラーも伝播しません。代わりに xpcall はエラーをキャッチし、オリジナルのエラーオブジェクトで Err 関数を要求し、ステータスコードを返します。

xpcallの簡単な例を以下に示す。

コピーコード コードは以下の通りです。
function myfunction ()
   n = n/nil
end

function myerrorhandler( err )
   print( "ERROR:", err )
end

status = xpcall( myfunction, myerrorhandler )
print( status)

上記のプログラムを実行すると、次のような出力が得られます。

コピーコード コードは以下の通りです。
ERROR: test2.lua:2: attempt to perform arithmetic on global 'n' (a nil value)
false

プログラマーとして最も重要なことは、エラーを正しく処理することです。エラー処理を使うことで、境界条件を超えた予期せぬ事態が、そのプログラムのユーザーの処理に支障をきたすことがないようにするのです。