Lua Programming

wikibooks https://en.m.wikibooks.org/wiki/Lua_Programming

Lua Programming

GNU Lesser General Public License, GNU Free Documentation License, GNU GENERAL PUBLIC LICENSE

cat2.PNG

Lua Programming

Introduction

Lua(「LUA」という表記は正しくありません)は、強力で、高速で、軽量で、埋め込み可能なプログラミング言語です。多くのフレームワーク、ゲーム、その他のアプリケーションで使用されています。単独で使用することもできますが、他のアプリケーションに簡単に組み込むことができるように設計されています。これは、非常に移植性の高いCプログラミング言語のサブセットであるANSI Cで実装されています。つまり、他のほとんどのスクリプト言語では実行できない多くのシステムやデバイスで実行できます。この本の目的は、以前のプログラミング経験に関係なく、誰にでもLuaプログラミングを教えることです。この本は、プログラミングの紹介として、これまでプログラミングしたことがない人のために、またはLuaの紹介として、他の言語でのプログラミング経験のある人のために使用できます。Luaを使用する開発プラットフォームやゲームはたくさんあるので、この本はLuaの使い方を学び、その開発プラットフォームでそれを使用するためにも使用できます。

この本は、Lua の最新バージョンの使用法を教えることを目的としています。これは、Lua の新しいバージョンがリリースされると、定期的に更新が試みられることを意味します(Luaのリリースはそれほど頻繁ではないため、それほど難しくはありません)。現在、この本は以前のバージョンである Lua5.2 の最新版です。5.xブランチ(Lua5.0およびLua5.1)で古いバージョンの Lua を使用する組み込み環境で Lua を使用している場合でも、資料は十分に関連しているはずです。

Lua は、リオデジャネイロのポンティフィカルカトリック大学の研究所で設計および保守されています。作成者は、 Roberto Ierusalimschy、Waldemar Celes 、Luiz Henrique de Figueiredoです。

「ルア」(LOO-ahと発音)はポルトガル語で「月」を意味します。そのため、頭字語でも略語でもありませんが、名詞です。より具体的には、「ルア」は名前、地球の月の名前、そして言語の名前です。ほとんどの名前と同様に、小文字で最初の大文字、つまり「Lua」を使用して記述する必要があります。ひどくて紛らわしい「LUA」とは書かないでください。人によって意味が異なる略語になります。だから、ぜひ「Lua」と書くようにしてくださいね!

Luaの作者、Luaについて

Luaは、TeCGraf(リオデジャネイロのポンティフィカルカトリック大学の研究所)によって設計された2つの言語、DELとSolに由来します。 DELは「データ入力言語」を意味し、Solは「単純なオブジェクト言語」を意味し、ポルトガル語で太陽も意味します。そのため、ポルトガル語で「月」を意味するため、Luaという名前が選ばれました。ブラジルの石油会社であるPetrobrasのために作成されましたが、TeCGrafの他の多くのプロジェクトでも使用され、現在では世界中の多数のプロジェクトで使用されています。 Luaは、組み込みゲーム開発の分野における主要な言語の1つです。

Lua の主な利点の1つは、そのシンプルさです。一部の企業は、その利点のためだけにそれを使用しています。プログラミング言語を使用して特定のタスクを実行できれば、従業員はよりよく働くことができると考えていますが、複雑なプログラミング言語のフルコースを従業員に提供する余裕はありません。ここでの Bash や Batch のようないくつかの非常に単純な言語は、これらのタスクを実行するのに十分強力ではありませんが、Lua は強力で単純です。 Luaのもう1つの重要な利点は、組み込み機能です。これは、開発全体を通じて最も重要な特性の1つでした。 World of Warcraft や ROBLOX のようなゲームは、ユーザーが使用できるように、アプリケーションにLuaを埋め込むことができる必要があります。

プログラミングは、組み込みアプリケーション内で実行されるプログラムの場合はスクリプトとも呼ばれ、コンピュータープログラムを作成するプロセスです。プログラミング言語は、コンピュータープログラムに含まれているコンピューターコードを介してコンピューターに指示を与えるために使用される言語です。プログラミング言語は、英語の文法に似た構文と、言語で提供される基本関数であるライブラリの2つで構成されています。これらのライブラリは、英語の語彙と比較できます。

Hello, world

Lua は、アプリケーションに埋め込まれて使用することも、単独で使用することもできます。この本では、Luaをコンピューターにインストールするプロセスについては説明していませんが、codepadまたはthe Lua demoを使用してコードを実行できます。この本の Lua コードの最初の例は、基本的で伝統的な「hello world」プログラムです。

Hello World」のプログラムは、表示装置に「Hello world」出力するコンピュータプログラムです。これは通常、ほとんどのプログラミング言語で可能な最も単純なプログラムの1つであるため、プログラミング言語の最も基本的な構文を初心者に説明したり、言語またはシステムが正しく動作していることを確認したりするためによく使用されます。

ウィキペディアHello world program

print("Hello, world!")

上記のコードは、Hello, world! というテキストを出力します。紙に何かを印刷するのではなく、出力にテキストを表示することを参照してプリントします。これは、printという関数を呼び出すことによって引数として文字列 "Hello, world!" を使用して行われます。これについては、関数に関する章で説明します。

Lua はほとんどの場合、低レベルのアプリケーションに埋め込まれていることに注意してください。つまり、print関数は、ユーザーに表示される領域にテキストを常に表示するとは限りません。これらのアプリケーションのプログラミングインターフェイスのドキュメントでは、一般に、テキストをユーザーに表示する方法について説明します。

Comments

コメントとは、プログラミング言語によって無視されるコード注釈です。コメントは、1行または複数行のコードの説明、プログラムの文書化、コードの一時的な無効化、またはその他の理由で使用できます。Luaがコメントだと認識できるようにするには、接頭辞として2つのハイフン--を付ける必要があり、独自の行または別の行の末尾に配置できます。

print("This is normal code.")
-- This is a comment
print("This is still normal code.") -- This is a comment at the end of a line of code.

これらのコメントはショートコメントと呼ばれます。長い括弧--[[で始まり、多くの行に続く長いコメントを作成することもできます。

print("This is normal code")
--[[Line 1
Line 2
]]

長い角かっこは2つの角かっこ [[ で 構成され、その中央に任意の数の等号 =を付けることができます。その等号の数は、長い括弧のレベルと呼ばれます。長い角かっこは、同じレベルの次の角かっこがあるところまで続きます。等号のない長い角かっこは、レベル0の長い角かっこと呼ばれます。このアプローチでは、2つの角かっこの中央に等号を追加することにより、長いコメントの内側で閉じている二重角かっこを使用できます。コメントを使用してコードのブロックを無効にする場合は、これを行うと便利なことがよくあります。

--[==[
This is a comment that contains a closing long bracket of level 0 which is here: ]]
However, the closing double bracket doesn't make the comment end, because the comment was opened with an opening long bracket of level 2, and only a closing long bracket of level 2 can close it.
]==]

上記の例では、レベル0の閉じている長い括弧(]])はコメントを閉じませんが、レベル2の閉じている長い括弧(]==])で閉じます。

Syntax

プログラミング言語の構文は、文法が文や単語の書き方を定義するのと同じように、ステートメントや式をそのプログラミング言語で書く方法を定義します。文と表現はそれぞれ文と単語と比較することができます。式は、値を持ち、評価できるコードの断片です。一方、ステートメントは、実行可能で、命令とその命令を使用する1つまたは複数の式を含むコードの断片です。たとえば、3 + 5は式であり、variable = 3 + 5 はその式の値を変数に設定するステートメントです。

Lua の構文全体は、Lua Webサイトの拡張バッカスナウア記法で見つけることができますが、それを読んでも何も理解できません。拡張バッカスナウア記法メタ言語であり、メタウェブサイトがウェブサイトに関するウェブサイトであるように、別の言語を説明するために使用される言語であり、Lua ではメタテーブルが他のテーブルの動作を定義するテーブルです(この本の後半のメタテーブルとテーブルについてで学習します)。ただし、この本では、拡張バッカスナウア記法を学ぶ必要はありません。Luaのような言語はメタ言語を使用して説明できますが、単語や文を使用して英語で説明することもできます。これはまさに、この本がしていることです。

英語は別の言語を説明するために使用できるため、それ自体がメタ言語である必要があります(メタ言語の定義に対応しているため)。これは確かに事実です。また、プログラミング言語の目的は命令を記述することであり、英語でそれを行うことができるため、英語もプログラミング言語である必要があります。これは、ある意味で、そうです。実際、英語は多くのことに使用できる言語です。ただし、拡張バッカスナウア記法は特殊言語であり、プログラミング言語も特殊言語です。専門化は、特定のことを行うのは非常に得意であるが、他のことを行うことができないという特徴です。拡張バッカスナウア記法は他の言語の記述に非常に優れていますが、指示を書いたりメッセージを伝えたりするために使用することはできません。プログラミング言語は指示を与えるのに非常に優れていますが、言語の記述やメッセージの伝達には使用できません。

英語は、言語の説明、指示の提供、メッセージの伝達など、すべてを行うことができます。しかし、プログラミング言語と同等のことはあまり得意ではありません。実際、英語では指示を与えるのは非常に苦手なので、コンピューターに指示を与えるために使用された場合、コンピューターは何も理解しません。これは、コンピューターが非常に正確で明確な指示を必要とするためです。

Obtaining Lua

Lua は、Lua公式Webサイトダウンロードページから入手できます。手順もそこにあります。ダウンロードボタンはソースコード用ですが、おそらくあなたが望むものではありません。おそらくバイナリを探しているので、ページを見てそれらに関する情報を見つける必要があります(使用しているプラットフォームによって異なります)。この本の目的は、Lua 言語を教えることだけであり、Lua ツールの使用法を教えることではありません。この本では読者は組み込み環境で Lua を使用すると想定れていますが、必ずしもそのとおりであるわけではありません。それは、この本の中では、Lua の使用法をスタンドアロン言語として説明していないことを意味するだけです。

Quiz

この章の内容を理解したことを確認するために質問がいくつかあります。これらの質問の対する答えを見つけるには、この章に記載されていない知識が必要になる場合があることに注意してださい。これは正常なことです。クイズは学習体験の一部であり、本の他の場所では入手できない情報を紹介することができます。

1 ポルトガル語で「Lua」とはどういう意味ですか?

2 レベル0の長いコメントはどれですか?

選択肢
--Comment
[[Comment]]
--[[Comment]]
--[=[Comment]=]
[=[Comment]=]

3 拡張バッカスナウア記法とは何ですか?

選択肢
A language
A programming language
A natural (or ordinary) language
A notation
A metalanguage
A markup language

Expressions

前に説明したように、式は値を持ち、評価できるコードの断片です。これらは(関数呼び出しを除いて)直接実行できないため、式で構成される次のコードのみを含むスクリプトはエラーになります。

3 + 5
-- The code above is erroneous because all it contains is an expression.
-- The computer cannot execute '3 + 5', since that does not make sense.

コードは一連のステートメントで構成されている必要があります。これらのステートメントには、ステートメントが命令を実行するために操作または使用する必要のある値となる式を含めることができます。

この章の一部のコード例は、式のみで構成されているため、有効なコードを構成していません。次の章では、ステートメントについて説明し、有効なコードの記述を開始できるようにします。

Types

式を評価することは、式を計算してその値を見つけることです。特定の式が評価する値は、環境とスタックレベルに依存する可能性があるため、コンテキストごとに異なる場合があります。この値は、数値、テキスト、その他の多くのデータ型のいずれかになる場合があります。そのため、型があると言われます。

Lua および一般的なプログラミングでは、式は通常、0個以上の演算子を持つ1つ以上の値で構成されます。一部の演算子は、一部のタイプでのみ使用できます(たとえば、テキストを分割しようとするのは非論理的ですが、数値を分割することは理にかなっています)。演算子には、単項演算子二項演算子の2種類があります。単項演算子は、1つの値のみを取る演算子です。たとえば、単項演算子は、パラメータとして -5、-3、-6 などの1つの数値のみを取ります。パラメータとして1つの数値を取り、その数値を無効にします。ただし、同じ演算子ではない2項演算子は、2つの値を取り、最初の値から2番目の値を減算します:5-3、8-6、4-9など。

type関数を使用して、数値の型を文字列として取得することができます。

print(type(32425)) --> number

Numbers

数字は一般的に数量を表しますが、他の多くのことに使用できます。Luaの数値型は、実数とほとんど同じように機能します。数値は、整数、10進数、10進数の指数、または16進数で構成できます。有効な番号は次のとおりです。

  • 3

  • 3.0

  • 3.1416

  • 314.16e-2

  • 0.31416E1

  • 0xff

  • 0x56

Arithmetic operations

Luaの数値の演算子は次のとおりです。

操作 構文 説明
算術否定 -a aの符号を変更し、値を返します -3.14159
添加 a + b aとbの合計を返します 5.2 + 3.6
減算 a-b aからbを減算し、結果を返します 6.7 - 1.2
乗算 a * b aとbの積を返します 3.2 * 1.5
べき乗 a ^ b aをbの累乗、またはaのbによるべき乗に返します 5 ^ 2
分割 a / b aをbで除算し、結果を返します 6.4 / 2
モジュロ演算 a % b aをbで割った余りを返します 5 % 3

最後のものを除いて、これらの演算子(基本的な数学演算子と同じ)はすべてすでに知っているでしょう。最後のものはモジュロ演算子と呼ばれ、ある数値を別の数値で除算した余りを単純に計算します。たとえば、5 % 3 は、式の意味するところは 5 を 3 で割った余りであるため、結果として 2 ということになります。モジュロ演算子は他の演算子ほど一般的ではありませんが、複数の用途があります。

Integers

数値の新しいサブタイプである整数がLua5.3で追加されました。数値は整数または浮動小数点数のいずれかです。浮動小数点数は上記の数値に似ていますが、整数は小数部のない数値です。浮動小数点の除算(/)とべき乗は、常にオペランド浮動小数点数に変換しますが、他のすべての演算子は、2つのオペランドが整数の場合、整数を返します。その他の場合、フロア分割演算子//)を除いて、結果はフロートになります。

Nil

Nilは値 nilのタイプであり、その主なプロパティは他の値とは異なります。これは通常、有用な値がないことを表します。nilを値に持つものの例:

  • 値を割り当てる前にアクセスする変数の値
  • スコープ外の変数にアクセスしようとしたときに取得する値
  • 割り当てられていないテーブル内のキーの値
  • tonumberによって文字列を数値に変換できない場合に返される値

より高度な注意点として、意図的にnil値を割り当てると、変数またはテーブルへの参照が削除され、ガベージコレクターがそのメモリを再利用できるようになります。

Booleans

ブール値は true または false のいずれかになりますが、それ以外はありません。これは、予約キーワードであるtruefalseとして Lua で記述されています。注意すべき重要な点は、これは前述nilのように異なるデータ型であるということです。andornot() は通常ブール値と関連していますが、Luaの任意のデータ型で使用することができます。

操作 構文 説明
ブール否定 not a aがfalseまたはnilの場合、trueを返します。それ以外の場合は、falseを返します。
論理積 a and b falseまたはnilの場合、最初の引数を返します。それ以外の場合は、2番目の引数を返します。
論理和 a or b falseでもnilでもない場合、最初の引数を返します。それ以外の場合は、2番目の引数を返します。

基本的に、not演算子はブール値を否定するだけで(trueの場合はfalseにし、falseの場合はtrueにします)、and演算子は両方がtrueの場合はtrueを返し、そうでない場合はfalseを返し、or演算子はいずれかの引数がtrueの場合はtrueを返します。それ以外の場合はfalse。ただし、上記の表で正確な動作方法が説明されているため、これは正確には動作しません。Luaでは、論理式では値falseとnilの両方がfalseと見なされ、その他はすべてtrueと見なされます(0と空の文字列も含む)。

次の章で紹介する関係演算子<><=>=~===)は必ずしもオペランドとしてブール値を取ることはありませんが、常に結果としてブール値が得られます。

これを調整するのは難しい場合があります。わかりやすくするために、ここにいくつかの真理値表または式と結果のペアを示します。ここでxniltrueまたはfalse

結果
true and x x
false and x false
nil and x nil
true or x true
false or x x
nil or x x

これはやや直感に反することを意味します

結果
false and nil false
nil and false nil

加えて

結果
false == nil nil == false false
nil and false nil
結果
not(false) not(nil) true
not(true) false

Strings

文字列は、テキストを表すために使用できる文字のシーケンスです。これらは、コメントに関するセクションで前に説明した二重引用符、一重引用符、または長い角かっこで囲むことにより、Lua で記述でき[ます。コメントと文字列には、コメントの場合は2つのハイフンを前に付けて、両方を長い角かっこで区切ることができるという事実以外に共通点がないことに注意してください)。長い括弧に含まれていない文字列は、1行だけ続きます。このため、長い角かっこを使用せずに多くの行を含む文字列を作成する唯一の方法は、エスケープシーケンスを使用することです。これは、特定の場合に一重引用符または二重引用符を挿入する唯一の方法でもあります。エスケープシーケンスは、Luaでは常にエスケープ文字であるバックスラッシュ( ' \ ' )と、エスケープする文字を識別する識別子の2つで構成されます。

Escape sequence Description
\n 改行
\" 二重引用符(ダブルクォーツ)
\' 一重引用符(またはアポストロフィ
\ バックスラッシュ
\t 水平tab
### 0から255 までの数字でなければなりません。結果は対応する ASCII文字 .

文字を文字列に直接入れると問題が発生する場合は、エスケープシーケンスを使用します。たとえば、二重引用符で囲まれ、二重引用符を含める必要があるテキストの文字列がある場合は、文字列を別の文字で囲むか、二重引用符をエスケープする必要があります。長い角かっこで区切られた文字列内の文字をエスケープする必要はありません。これはすべての文字に当てはまります。長い括弧で区切られた文字列内のすべての文字は、そのまま使用されます。% 文字は、魔法の文字をエスケープする文字列パターンで使用されていますが、用語のエスケープは、別のコンテキストで使用されています。

"This is a valid string."

'This is also a valid string.'

"This is a valid \" string 'that contains unescaped single quotes and escaped double quotes."

[[
This is a line that can continue
on more than one line.

It can contain single quotes, double quotes and everything else (-- including comments). It ignores everything (including escape characters) except closing long brackets of the same level as the opening long bracket.
]]

"This is a valid string that contains tabs \t, double quotes \" and backlashes \\"

"This is " not a valid string because there is an unescaped double quote in the middle of it."

便宜上、開いている長い文字列ブラケットの直後に新しい行が続く場合、その新しい行は無視されます。したがって、次の2つの文字列は同等です。

[[This is a string
that can continue on many lines.]]

[[
This is a string
that can continue on many lines.]]

-- Since the opening long bracket of the second string is immediately followed by a new line, that new line is ignored.

単項長演算子 ( '#' )を使用すると、文字列の長さを数値として取得できます。

print(#("This is a string")) --> 16

Concatenation

形式言語理論コンピュータプログラミング文字列の連結は、 2つの文字列&usg=ALkJrhi_O9cTd4GHux39enA4M1-llG5B1w)エンドツーエンドをつなげる操作です。たとえば、「雪」と「ボール」の連結は「雪玉」です。

ウィキペディアConcatenation

In formal language theory and computer programming, string concatenation is the operation of joining two character strings) end-to-end. For example, the concatenation of "snow" and "ball" is "snowball".

Wikipedia, Concatenation

Luaの文字列連結演算子は、2つのドット ('..') で示されます。これは、「snow」と「ball」を連結して結果を出力する連結の例です。

print("snow" .. "ball") --> snowball

このコードは「snow」と「ball」を連結し、結果を出力します。

Other types

Lua の4つの基本タイプ(数値、ブール値、nil、文字列)については前のセクションで説明しましたが、関数、テーブル、ユーザーデータ、スレッドの4つのタイプがありません。関数は、呼び出して値を受け取り、値を返すことができるコードの断片です。テーブルは、データ操作に使用できるデータ構造です。ユーザーデータは、Luaが組み込まれているアプリケーションによって内部的に使用され、Lua がアプリケーションによって制御されるオブジェクトを介してそのプログラムと通信できるようにします。最後に、スレッドはコルーチンによって使用されます。これにより、多くの関数を同時に実行できます。これらはすべて後で説明するので、他のデータ型があることだけを覚えておいてください。

Literals

リテラルは、ソースコードで固定値を表すための表記法です。Lua ではスレッドとユーザーデータを除くすべての値は、リテラルとして表すことができます。文字列リテラル(文字列として評価されるリテラル)は、たとえば、テキストの文字列を一重引用符、二重引用符、または長い角かっこで囲んで構成します。一方、数値リテラルは、10進表記(例: 12.43)、科学的記数法(例:3.1416e-2および0.31416E1)、または16進表記(例:0xff)を使用して表現された数値で構成されます。

Coercion

Coercion とは、あるデータ型の値を別のデータ型の値に変換することです。Lua は、文字列値と数値の間の自動変換を提供します。文字列に適用される算術演算は、この文字列を数値に変換しようとします。逆に、文字列が予期され、代わりに数値が使用される場合は常に、数値は文字列に変換されます。これは、Lua演算子とデフォルト関数(言語で提供される関数)の両方に適用されます。

print("122" + 1) --> 123
print("The number is " .. 5 .. ".") --> The number is 5.

数値から文字列への Coercion および文字列から数値への Coercion は、tostring 関数と  tonumber 関数を使用して手動で行うこともできます。前者は数値を引数として受け入れて文字列に変換し、後者は文字列を引数として受け入れて数値に変換します(デフォルトの10進数とは異なるベースをオプションで2番目の引数に指定できます)。

Bitwise operations

Lua 5.3以降、2進数(ビットパターン)を操作するためのビット演算子が提供されています。これらの演算子は他の演算子ほど頻繁には使用されないため、不要な場合はこのセクションをスキップできます。

Lua のビット演算子は常に整数を操作し、必要に応じてオペランドを変換します。それらは整数も与えます。

ビット単位のAND演算(演算子&を使用)は、同じ長さの2つのバイナリ表現のビットの各ペアに対して論理積を実行します。たとえば、5 & 3 は 1 と評価されます。これは、これらの数値の2進表現を調べることで説明できます(下付き文字は基数を示すために使用されます)。

(5)_{{10}}=(0101)_{2}

(3)_{{10}}=(0011)_{2}

(1)_{{10}}=(0001)_{2}

5と3の両方のバイナリ表現の特定の位置にあるビットが1である場合(最後のビットの場合のように)、その位置にあるビットは1になります。それ以外の場合はすべて0になります。

ビット単位のOR演算(演算子|を使用)は、ビット単位のAND演算と同じように機能し、論理積を実行する代わりに論理和を実行します。したがって、5 | 3 は7と評価されます。

(5)_{{10}}=(0101)_{2}

(3)_{{10}}=(0011)_{2}

(7)_{{10}}=(0111)_{2}

ここで、2つのオペランドのバイナリ表現がその位置に0ビットを持っていた場合にのみ、最終結果の各位置のビットが0であることがわかります。

ビット単位のXOR演算(演算子~を使用)は他の2つの演算と同じように機能しますが、特定の位置では、オペランドのビットの両方ではなく片方が1の場合、最後のビットは1になります。

(5)_{{10}}=(0101)_{2}

(3)_{{10}}=(0011)_{2}

(6)_{{10}}=(0110)_{2}

これは前の例と同じですが、両方のオペランドの最後のビットが1であったため、結果の最後のビットが1ではなく0であることがわかります。

ビット単位のNOT演算(演算子~を使用)は、一意のオペランドの各ビットに対して論理否定を実行します。つまり、0が1になり、1が0になります。したがって、~7 は -8 と評価されます。

(7)_{{10}}=(0111)_{2}

(8)_{{10}}=(1000)_{2}

ここで、最初のビットはオペランドが0であるため結果で1になり、他のビットはすべて1であるため0になります。

Left shiftRight shift

これらのビット演算子に加えて、Lua5.3は算術ビットシフトもサポートしています。演算子<<を使用して左側に示されている左シフトは、すべてのビットを、第2オペランドに対応するビット数だけ左にシフトすることで構成されます。演算子>>で示され、右に示されている右シフトも同じですが、ビットシフトは反対方向です。

Operator precedence

演算子の優先順位は、Lua でも数学で通常行われるのと同じように機能します。特定の演算子は他の演算子よりも先に評価され、括弧を使用して、操作を実行する順序を任意に変更できます。演算子が評価される優先度は、優先度の高いものから低いものへと、以下のリストにあります。これらの演算子のいくつかはまだ議論されていませんが、それらはすべてこの本のある時点でカバーされます。

  1. べき乗: ^

  2. 単項演算子not#-~

  3. レベル2数学演算子*///%

  4. レベル1の数学演算子+-

  5. 連結: ..

  6. ビットシフト:<<>>

  7. ビットごとのAND: &

  8. ビットごとのXOR: ~

  9. ビットごとのOR: |

  10. 関係演算子<><=>=~===

  11. ブール値と: and

  12. ブール値または: or

Quiz

この章の内容を理解したことを確認するために回答できる質問がいくつかあります。これらの質問のいくつかに対する答えを見つけるには、この章に記載されていない知識が必要になる場合があることに注意してください。これは正常です。クイズは学習体験の一部であり、本の他の場所では入手できない情報を紹介することができます。

1 何が出力されますか?print(type(type(5.2)))

2 0 or 8 この式は何を返しますか?

選択肢
true
false
0
8

3 どの文字列が有効ですか?

選択肢
"test's test"
'test\'s test'
"test"s test"
'test"s test'
"test\'s test"
'test's test'

4 どの式が"1223"の文字列を与えますか?

選択肢
"122" + 3
"122" .. 3
"12" + "23"
12 .. 23

5 正誤問題 not 5^3 == 5 true or false?

選択肢
true
false

Statements

ステートメントは、実行可能なコードの一部であり、ステートメントで使用する命令と式が含まれています。一部のステートメントには、たとえば特定の条件下で実行される可能性のあるコードも含まれます。式とは異なり、式に直接入れることができ、実行されます。Lua にはいくつかの命令がありますが、これらの命令を他の命令や複雑な式と組み合わせると、ユーザーに十分な制御と柔軟性が与えられます。

Assignment

プログラマーは、後で使用できるように、値をメモリーに格納できる必要があることがよくあります。これは変数を使用して行われます。変数は、コンピューターのメモリに格納されている値への参照です。それらは、メモリに保存した後、後で番号にアクセスするために使用できます。割り当ては、変数に値を割り当てるために使用される命令です。これは、値を格納する必要がある変数の名前、等号、および変数に格納する必要がある値で構成されます。

variable = 43
print(variable) --> 43

上記のコードで示されているように、変数の値にアクセスするには、変数の名前を値にアクセスする必要があります。

The assignment operator

Lua では、他のほとんどのプログラミング言語と同様に、等号(=)は、右側のオペランドの式の値を左側のオペランドで指定された変数に割り当てる2項代入演算子として機能します

Assignment of variables

次の例は、変数の割り当てに等号を使用する方法を示しています。

fruit = "apple"   -- assign a string to a variable
count = 5         -- assign a numeric value to a variable

Strings and Numeric Values

リテラル文字列は、変数名と区別するために引用符で囲む必要があることに注意してください。

apples = 5
favourite = "apples"   -- without quotes, apples would be interpreted as a variable name

変数名は数字で始めることができないため、数値を引用符で囲む必要はなく、変数名として誤って解釈することはできないことに注意してください。

apples = 6    -- no quotes are necessary around a numeric parameter
pears = "5"   -- quotes will cause the value to be considered a string

Multiple Assignments

Lua プログラミング言語は複数の割り当てをサポートしています。

apples, favorite = 5, "apples" -- assigns apples = 5, favorite = "apples"

Identifiers

Lua では、識別子は名前とも呼ばれます。文字、数字、アンダースコアで構成され、数字で始まらない任意のテキストを使用できます。これらは、テーブルに関する章で説明する変数とテーブルフィールドに名前を付けるために使用されます

いくつかの有効な名前は次のとおりです。

  • name
  • hello
  • _
  • _tomatoes
  • me41
  • __
  • _thisIs_StillaValid23name

いくつかの無効な名前は次のとおりです。

  • 2hello :数字で始まる

  • th$i :文字、数字、またはアンダースコアではない文字が含まれている

  • hel!o :文字、数字、またはアンダースコアではない文字が含まれている

  • 563text :数字で始まる

  • 82_something :数字で始まる

また、次のキーワードのLUAによって予約されており、名称として使用することはできません:andendinrepeatbreakfalselocalreturndofornilthenelsefunctionnottrueelseififoruntilwhile

変数またはテーブルフィールドに名前を付けるときは、その有効な名前を選択する必要があります。したがって、文字またはアンダースコアで始まり、文字、アンダースコア、および数字のみを含める必要があります。Luaでは大文字と小文字が区別されることに注意してください。これは、Hellohelloが2つの異なる名前であることを意味します。

Scope

変数&usg=ALkJrhgPIty13LsluvhQl0GnViEF63s0ow)のスコープ&usg=ALkJrhgPIty13LsluvhQl0GnViEF63s0ow)は、その変数が意味を持つプログラムのコードの領域です。これまでに見た変数の例はすべてグローバル変数の例であり、プログラムのどこからでもアクセスできる変数です。一方、ローカル変数は、それらが定義されたプログラムの領域から、およびプログラムのその領域内にあるプログラムの領域でのみ使用できます。これらはグローバル変数とまったく同じ方法で作成されますが、接頭辞としてlocalキーワードを付ける必要があります。

doステートメントは、それらを記述するために使用されます。このdoステートメントは、新しいコードブロック、つまり新しいスコープを作成する以外の目的がないステートメントです。endキーワードで終わります:

local variable = 13 -- This defines a local variable that can be accessed from anywhere in the script since it was defined in the main region.
do
    -- This statement creates a new block and also a new scope.
    variable = variable + 5 -- This adds 5 to the variable, which now equals 18.
    local variable = 17 -- This creates a variable with the same name as the previous variable, but this one is local to the scope created by the do statement.
    variable = variable - 1 -- This subtracts 1 from the local variable, which now equals 16.
    print(variable) --> 16
end
print(variable) --> 18

スコープが終了すると、スコープ内のすべての変数が削除されます。コードの領域では、含まれているコードの領域で定義された変数を使用できますが、同じ名前のローカル変数を定義して変数を「上書き」すると、コードの他の領域で定義された変数の代わりにそのローカル変数が使用されます。これが、print関数の最初の呼び出しが16を出力し、doステートメントによって作成されたスコープ外の2番目の呼び出しが18を出力する理由です。

実際には、ローカル変数のみを使用する必要があります。ローカル変数は、グローバル変数のように現在の関数の環境に格納されるのではなく、レジスタに格納されるため、グローバル変数よりも高速に定義およびアクセスできるためです。レジスターは、Lua がローカル変数を格納してそれらにすばやくアクセスするために使用する領域であり、通常は最大200個のローカル変数しか含めることができません。すべてのコンピューターの重要なコンポーネントであるプロセッサーにもレジスターがありますが、これらは Luaレジスターとは関係ありません。各関数(メインスレッド、プログラムのコア、関数でもある)にも独自の環境があります。これは、変数名にインデックスを使用し、これらの変数の値をこれらのインデックスに対応する値に格納するテーブルです。

Forms of assignment

Augmented assignment

複合代入とも呼ばれる拡張代入は、変数に前の値を基準にした値を与えるタイプの代入です。たとえば、現在の値をインクリメントする、aの値を8ずつインクリメントするコードa += 8相当するものは、C&usg=ALkJrhiCKRK36t_KSDoPF3Pn4cHeTdDEkg)、JavaScriptRuby&usg=ALkJrhjzUGQdMGYRxbbFJVnabYKtQcLMTw)、Python&usg=ALkJrhhE0iY1VFHE7kYCrOh5VrK0LUblFQ)に存在しますが、Luaには存在しません。つまり、a = a + 8 と記述する必要があります。

Chained assignment

連鎖割り当ては、多くの変数に単一の値を与える割り当ての一種です。たとえば、このコードa = b = c = d = 0は、CおよびPythonでa、b、c、およびdの値を0に設定します。Luaでは、このコードはエラーを発生させるため、前の例は次のように記述する必要があります。

d = 0
c = d -- or c = 0
b = c -- or b = 0
a = b -- or a = 0

Parallel assignment

並列割り当ては、同時割り当ておよび複数割り当てとも呼ばれ、異なる変数に異なる値(同じ値にすることもできます)を同時に割り当てるタイプの割り当てです。連鎖割り当てや拡張割り当てとは異なり、Luaでは並列割り当てを使用できます。

前のセクションの例は、並列割り当てを使用するように書き直すことができます。

a, b, c, d = 0, 0, 0, 0

値よりも多くの変数を指定すると、一部の変数には値が割り当てられません。変数よりも多くの値を指定すると、余分な値は無視されます。より技術的には、値のリストは、割り当てが行われる前に変数のリストの長さに調整されます。つまり、余分な値が削除され、最後に余分なnil値が追加されて、のリストと同じ長さになります。変数値リストの最後に関数呼び出しがある場合、関数呼び出しが括弧で囲まれていない限り、返される値はそのリストの最後に追加されます。

さらに、ほとんどのプログラミング言語とは異なり、Luapermutation (順列)を介して変数の値の再割り当てを可能にします。例えば:

first_variable, second_variable = 54, 87
first_variable, second_variable = second_variable, first_variable
print(first_variable, second_variable) --> 87 54

これが機能するのは、割り当てステートメントが何かを割り当てる前にすべての変数と値を評価するためです。割り当ては、実際に同時であるかのように実行されます。つまり、新しい値が割り当てられる前に、変数とその変数の値でインデックス付けされたテーブルフィールドに同時に値を割り当てることができます。つまり、次のコードは、dictionary[1]を12に設定するのではなくdictionary[2]に設定します。

dictionary = {}
index = 2
index, dictionary[index] = index - 1, 12

Conditional statement

条件文は、式が真であるかどうかをチェックし、真である場合は特定のコードを実行する命令です。式が真でない場合は、そのコードをスキップするだけで、プログラムが続行されます。Luaでは、唯一の条件文がif命令を使用します。Falseとnilは両方ともfalseと見なされ、その他はすべてtrueと見なされます。

local number = 6

if number < 10 then
    print("The number " .. number .. " is smaller than ten.")
end

-- Other code can be here and it will execute regardless of whether the code in the conditional statement executed.

上記のコードでは、変数番号には、代入ステートメントを使用して番号6が割り当てられています。次に、条件ステートメントは、変数番号に格納されている値が10より小さいかどうかをチェックします。これは、ここに当てはまります。そうである場合は、「"The number 6 is smaller than ten." 6は10より小さい」と出力されます。

elseキーワードを使用して式が真でない場合にのみ特定のコードを実行し、elseif条件ステートメントをチェーン化することもできます。

local number = 15

if number < 10 then
    print("The number is smaller than ten.")
elseif number < 100 then
    print("The number is bigger than or equal to ten, but smaller than one hundred.")
elseif number ~= 1000 and number < 3000 then
    print("The number is bigger than or equal to one hundred, smaller than three thousands and is not exactly one thousand.")
else
    print("The number is either 1000 or bigger than 2999.")
end

elseブロックは常に最後のものでなければならないことに注意してください。elseifブロックの後にelseブロックを置くことはできません。elseifブロックは、それらを先行ブロックのいずれも実行されなかった場合にのみ意味があります。

2つの値を比較するために使用される演算子は、上記のコードで使用されているものもあり、関係演算子と呼ばれます。関係がtrueの場合、ブール値trueを返します。それ以外の場合は、ブール値 false を返します。

等しい 等しくない より大きい 未満 以上 以下
数学表記 = > <
Luaオペレーター == ~= > < >= <=
equal to not equal to greater than less than greater than or equal to less than or equal to
Mathematical notation = > <
Lua operator == ~= > < >= <=

上記のコードは、andキーワードを使用して、条件式で多くのブール式を組み合わせる方法も示しています。

Loops

多くの場合、プログラマーは特定のコードまたは同様のコードを何度も実行するか、ユーザー入力に応じて特定のコードを何度も実行する必要があります。ループは、1回指定されますが、連続して複数回実行される可能性のある一連のステートメントです。

Condition-controlled loops

条件制御ループは、条件によって制御されるループです。これらは条件ステートメントに非常に似ていますが、条件がtrueの場合にコードを実行し、それ以外の場合はスキップする代わりに、条件がtrueの間、または条件がfalseになるまでコードを実行し続けます。 Luaには、と条件制御ループの2つのステートメントがあります。whileループと repeat ループです。このようなループはコードを実行し、条件が真であるかどうかを確認します。 trueの場合、コードを再度実行し、条件がfalseになるまで繰り返します。条件がfalseの場合、コードの繰り返しを停止し、プログラムフローが続行されます。コードの各実行は、 iteration(反復)と呼ばれます。whilerepeatループの違いは、repeatループはループの最後に条件をチェックすることです。whileループは、ループの開始時にそれをチェックします。これは、最初の反復でのみ違いがあります。コードが最初に実行されたときに条件がfalseであっても、repeatループは常に少なくとも1回はコードを実行します。これは、条件が実際に true である場合にのみコードを最初に実行するwhileループには当てはまりません。

local number = 0

while number < 10 do
    print(number)
    number = number + 1 -- Increase the value of the number by one.
end

上記のコードは、0、1、2、3のように、9まで出力します。10回目の反復後、数値は10以上になるため、ループの実行は停止します。ループは永久に実行されることを意味する場合があり、その場合、ループは無限ループと呼ばれます。たとえば、レンダラー、つまり画面上に物を描画するソフトウェアプロセスは、ユーザーに表示される画像を更新するために画面を再描画するために絶えずループすることがよくあります。これはビデオゲームでよくあることで、ユーザーに表示されるものを最新の状態に保つために、ゲームビューを常に更新する必要があります。ただし、ループを永久に実行する必要がある場合はまれであり、そのようなループはエラーの結果であることがよくあります。無限ループは多くのコンピュータリソースを消費する可能性がありますが、したがって、ユーザーから予期しない入力を受け取った場合でも、ループが常に終了するようにすることが重要です。

local number = 0

repeat
    print(number)
    number = number + 1
until number >= 10

上記のコードは、上記のwhileループを使用したコードとまったく同じことを行います。主な違いは`whileキーワードとdoキーワードの間に条件が配置されるwhileループとは異なり、条件はループの最後、untilキーワードの後に配置されることです。repeatループは、endキーワードによってブロックが閉じられていないLuaで唯一のステートメントです。

Count-controlled loops

変数をインクリメントすると、その値が段階的に、特に1ステップづつ増加します。前のセクションの2つのループは、変数の数字をインクリメントし、それを使用してコードを特定の回数実行しました。この種のループは非常に一般的であるため、Luaを含むほとんどの言語には組み込みのループ制御構造があります。この制御構造はカウント制御ループと呼ばれ、Luaおよびほとんどの言語では、forステートメントによって定義されます。このようなループで使用される変数は、ループカウンターと呼ばれます。

for number = 0, 9, 1 do
    print(number)
end

上記のコードは、前のセクションで示した2つのループとまったく同じことを行いますが、数値変数はループのローカルであるため、ループ内からのみアクセスできます。変数名と等号記号に続く最初の数字は初期化です。ループカウンタが初期化される値です。 2番目の番号は、ループが停止する番号です。変数をインクリメントし、変数がこの数に達するまでコードを繰り返します。最後に、3番目の数値は増分です。これは、各反復でループカウンターが増加する値です。増分が指定されていない場合、Luaでは1と見なされます。したがって、以下のコードは1、1.1、1.2、1.3、1.4、1.5を出力します。

for n = 1, 2, 0.1 do
    print(n)
    if n >= 1.5 then
        break -- Terminate the loop instantly and do not repeat.
    end
end

上記のコードが2までではなく、1.5までしか上がらない理由は、ループを即座に終了するbreakステートメントのためです。このステートメントは、whileループやrepeatループを含む任意のループで使用できます。ここでは>=演算子が使用されていることに注意してください。ただし、理論的には==演算子も同様に機能します。これは、10進数の精度エラーが原因です。Luaは、倍精度浮動小数点形式で数値を表します、実際の値の近似値をメモリに格納します。場合によっては、近似の値が数値と正確に一致しますが、場合によっては、概算にすぎません。通常、これらの近似値は、違いが生じないように数値に十分に近いものになりますが、このシステムでは、等式演算子==を使用するとエラーが発生する可能性があります。これが、等式演算子の使用を避けて10進数で作業するのが一般的に安全である理由です。この特定のケースでは、等式演算子が使用されていた場合、コードは機能しませんでした[ 1](1.9まで上昇し続けました)が、>= 演算子では機能します。

Blocks

ブロックは、順番に実行されるステートメントのリストです。これらのステートメントには、命令を含まない空のステートメントを含めることができます。空のステートメントを使用して、セミコロンでブロックを開始したり、2つのセミコロンを順番に書き込んだりできます。

関数の呼び出しと割り当ては括弧で始まる場合があり、あいまいさを招く可能性があります。このフラグメントの例です:

a = b + c
(print or io.write)('done')

このコードは、次の2つの方法で解釈できます。

a = b + c(print or io.write)('done')
a = b + c; (print or io.write)('done')

現在のパーサーは、常に最初の方法でそのような構文を認識し、最初の括弧を呼び出しの引数の開始として解釈します。このあいまいさを回避するために、次のように常に括弧で始まるセミコロンステートメントを前に付けることをお勧めします。

;(print or io.write)('done')

Chunks

Luaコンパイル単位はチャンクと呼ばれます。チャンクは、ホストプログラム内のファイルまたは文字列に格納できます。チャンクを実行するために、Luaは最初にチャンクを仮想マシンの命令にプリコンパイルし、次にコンパイルされたコードを仮想マシンインタープリターで実行します。チャンクは、Luaに付属のコンパイルプログラムluac、または指定された関数のバイナリ表現を含む文字列を返すstring.dump 関数を使用して、バイナリ形式(バイトコード)にプリコンパイルすることもできます。

このload関数を使用して、チャンクをロードできます。load関数に指定された最初のパラメーターが文字列の場合、チャンクはその文字列です。この場合、文字列はLuaコードまたはLuaバイトコードのいずれかです。最初のパラメーターが関数の場合、loadチャンクを取得するためにその関数を繰り返し呼び出します。各チャンクは、前の文字列と連結される文字列です。次に、何も返されないか、空の文字列が返されたときに、チャンクが完了したと見なされます。

load関数は構文エラーがない場合は関数としてコンパイルされたチャンクを返します。それ以外の場合は、nilとエラーメッセージが返されます。

load関数の2番目のパラメーターは、チャンクのソースを設定するために使用されます。すべてのチャンクは、適切なエラーメッセージとデバッグ情報を提供できるように、ソースのコピーをチャンク内に保持します。デフォルトでは、それらのソースのコピーはloadに与えられたコードになります(コードが与えられた場合、代わりに関数が与えられた場合、それは「=(load)」になります)。このパラメーターを使用して変更できます。これは、元のソースを取り戻せないようにコードをコンパイルするときに最も役立ちます。次に、バイナリ表現に含まれているソースを削除する必要があります。そうしないと、元のコードを取得できるためです。

load関数の3番目のパラメーターは、生成された関数の環境を設定するために使用でき、4番目のパラメーターは、チャンクをテキストにするかバイナリにするかを制御します。文字列「b」(バイナリチャンクのみ)、「t」(テキストチャンクのみ)、または「bt」(バイナリとテキストの両方)の場合があります。デフォルトは「bt」です。

loadとまったく同じように機能するloadfile関数もありますが、この関数はファイルからコードを取得するものです。 最初のパラメーターは、コードを取得するファイルの名前です。 バイナリ表現に格納されているソースを変更するパラメータはありません。load関数の3番目と4番目のパラメータは、この関数の2番目と3番目のパラメータに対応しています。 loadfile関数を使用して、標準入力からコードをロードすることもできます。これは、ファイル名が指定されていない場合に実行されます。

このdofile関数はloadfile関数に似ていますが、コードを関数としてファイルにロードする代わりに、ソースコードファイルに含まれているコードをLuaチャンクとしてすぐに実行します。その唯一のパラメーターは、コンテンツを実行するファイルの名前を指定するために使用されます。引数が指定されていない場合は、標準入力の内容が実行されます。チャンクが値を返す場合、それらはdofile関数の呼び出しによって提供されます。dofileはプロテクトモードでは実行されないため、dofileで実行されたチャンク内のすべてのエラーが伝播します。

  1. http://codepad.org/kYHPSvqx

Functions

スタックとそのスタックで実行できる操作の図。

An illustration of a stack and of the operations that can be performed on it.

スタックは、後入れ先出しの原則に従って動作する、アイテムを追加(プッシュ)または削除(ポップ)できるアイテムのリストです。つまり、最後に追加されたアイテムが最初に削除されます。このようなリストがスタックと呼ばれるのはこのためです。スタックでは、最初にその上にあるアイテムを削除せずにアイテムを削除することはできません。したがって、すべての操作はスタックの最上位(Top)で行われます。アイテムは、他のアイテムの後に追加された場合は上にあり、他のアイテムの前に追加された場合は下にあります。

関数(サブルーチン、プロシージャ、ルーチン、またはサブプログラムとも呼ばれます)は、特定のタスクを実行する一連の命令であり、その一連の命令を実行する必要があるときはいつでも、プログラムの他の場所から呼び出すことができます。関数は、入力として値を受け取り、入力を操作したり、入力に基づいてタスクを実行したりした後、出力を返すこともできます。関数は、他の関数内を含め、プログラム内のどこからでも定義できます。また、関数にアクセスできるプログラムの任意の部分から呼び出すこともできます。関数は、数値や文字列と同様に値であるため、変数に格納できます。変数に共通するすべてのプロパティがあります。これらの特性により、関数はとてもつかいやすくなります。

関数は他の関数から呼び出すことができるため、Luaインタープリター(Luaコードを読み取って実行するプログラム)は、関数が終了したとき(それ以上実行するコードがないとき)に、現在実行している関数と呼ばれる関数を認識できる必要があります。それによって正しい関数の実行に戻ることができます。これは、コールスタックと呼ばれるスタックを使用して行われます。コールスタック内の各アイテムは、現在実行されている関数で、スタック内のすぐ上にあるアイテムがなくなるまで呼び出す関数です。関数が終了すると、インタープリターはスタックのポップ操作を使用してリスト内の最後の関数を削除し、その後、前の関数に戻ります。

関数には、組み込み関数とユーザー定義関数の2種類があります。組み込み関数はLuaで提供される関数であり、すでに知っているprint関数などの関数が含まれています。print関数のように直接アクセスできるものもあれば、乱数を返すmath.random関数のようにライブラリを介してアクセスする必要があるものもあります。ユーザー定義関数は、ユーザーが定義した関数です。ユーザー定義関数は、関数コンストラクターを使用して定義されます。

local func = function(first_parameter, second_parameter, third_parameter)
    -- function body (a function's body is the code it contains)
end

上記のコードは、3つのパラメーターを持つ関数を作成し、それを変数funcに格納します。次のコードは上記のコードとまったく同じですが、関数を定義するためにシンタックスシュガーを使用しています。

local function func(first_parameter, second_parameter, third_parameter)
    -- function body
end

なお、第2の形式を使用する場合は、内部から関数を参照することができますが、第1の形式を使用する場合は参照できません。これは、local function foo() endlocal foo = function() endではなくlocal foo; foo = function() endに変換されるためです。これは、fooが1番目の形式ではなく2番目の形式の関数の環境の一部であることを意味します。これは、なぜ2番目の形式が関数自体を参照できるかを説明しています。

どちらの場合も、localキーワードを省略して関数をグローバル変数に格納することができます。パラメータは変数のように機能し、関数が値を受け取ることを可能にします。関数が呼び出されると、引数が与えられます。その後、関数はそれらをパラメーターとして受け取ります。パラメータは、関数の先頭で定義されたローカル変数のようなものであり、関数呼び出しで指定された引数の順序に応じて順番に割り当てられます。引数が欠落している場合、パラメーターの値はnilになります。次の例の関数は、2つの数値を加算し、結果を出力します。したがって、コードの実行時に5が出力されます。

local function add(first_number, second_number)
    print(first_number + second_number)
end

add(2, 3)

関数呼び出しは、ほとんどの場合、フォームname(arguments)の下にあります。ただし、引数が1つだけで、それがテーブルまたは文字列であり、変数に含まれていない場合(つまり、関数呼び出しで直接作成され、リテラルとして表される場合)、括弧は省略できます。

print "Hello, world!"
print {4, 5}

前の例のコードの2行目は、テーブルのメモリアドレスを出力します。print関数が自動的に値を文字列に変換すると、複合型(関数、テーブル、ユーザーデータ、スレッド)がそれらのメモリアドレスに変更されます。ただし、ブール値、数値、および nil 値は、対応する文字列に変換されます。

パラメータ引数という用語は、同じ意味で使われることがよくあります。この本では、適切な意味で、パラメータ引数という用語は、それぞれ、パラメータとして割り当てられて関数に渡される値と対応する引数として値が割り当てられるものの名前を意味します。

Returning values

関数は入力を受け取り、それを操作し、出力を返すことができます。入力(パラメーター)を受け取り、それを操作する方法(関数本体)は既に知っています。また、returnステートメントを使用して、任意のタイプの1つまたは複数の値を返すことによって出力することもできます。これが、関数呼び出しがステートメントと式の両方である理由です。それらは実行できますが、評価することもできます。

local function add(first_number, second_number)
    return first_number + second_number
end

print(add(5, 6))

上記の関数のコードは、最初にadd関数を定義しています。次に、5と6を値として呼び出します。add関数はそれらを加算して結果を返し、出力されます。これが、上記のコードが11を出力する理由です。これらの値に評価される式をコンマで区切ることにより、関数が多くの値を返すことも可能です。

Errors

エラーには、構文エラー、静的セマンティックエラー、セマンティックエラーの3種類があります。構文エラーは、コードが明らかに無効な場合に発生します。たとえば、次のコードはLuaによって無効として検出されます。

print(5 ++ 4 return)

上記のコードは意味がありません。それから意味を引き出すことは不可能です。同様に、英語では、「cat(猫) dog(犬) tree(木)」は意味がないため、構文的に有効ではありません。文を作成するための規則に従っていません。

静的セマンティックエラーが起こるのはコードは意味を持っているが、まだ成立しない場合です。例えば、文字列に対して数字を足そうとすると静的セマンティックエラーになります。 これは文字列に数字を加算できないためです。

print("hello" + 5)

上記のコードはLuaの構文規則には従いますが、数値を含む文字列を追加することは不可能であるため、意味が成立しません(文字列が数値を表す場合を除き、その場合は強制的に1つになります)。これは英語で「I are big」という文と比較することができます。英語で文章を作成するための規則に収まっていますが、「I」は単数形で「are」は複数形であるため、それでもやはりおかしいわけです。

最後に、セマンティックエラーは、コードの一部の意味がその作成者が考えているものではない場合に発生するエラーです。これらは見つけるのが非常に難しいため、最悪のエラーです。 Luaは、構文エラーまたは静的セマンティックエラー(これはエラーのスローと呼ばれます)がある場合は常に通知しますが、セマンティックエラーがある場合は、どのような考えでコードが意味づけされていたかわからないため、通知できません。これらのエラーは、思っているよりも頻繁に発生し、エラーを見つけて修正することに、多くのプログラマーがたくさんの時間を費やしています。

エラーを見つけて修正するプロセスは、デバッグと呼ばれます。ほとんどの場合、プログラマーは実際にエラーを修正するよりもエラーを見つけることに多くの時間を費やします。これは、すべてのタイプのエラーに当てはまります。問題が何であるかがわかれば、通常は簡単に修正できますが、プログラマーがコードのどこに問題があるのかを見つけられずに、何時間もコードを見直す場合もあります。

Protected calls

エラーをスローすることは、インタープリター(コードを読み取って実行するプログラム)によって手動で行われたか自動で行われたかにかかわらず、コードに問題があることを示すアクションです。指定されたコードが無効な場合、Luaによって自動的に実行されますが、error関数を使用して手動で実行できます。

local variable = 500
if variable % 5 ~= 0 then
    error("It must be possible to divide the value of the variable by 5 without obtaining a decimal number.")
end

error関数には、エラーがスローされるスタックレベルを示す2番目の引数もありますが、これについては本書では取り上げません。このassert関数はerror関数と同じことを行いますが、最初の引数が nil または false と評価され、エラーをスローするスタックレベルを指定するために使用できる引数がない場合にのみエラーをスローします。assert関数は、スクリプトの開始時に役立ちます。たとえば、スクリプトが機能するために必要なライブラリが使用可能かどうかを確認する場合などです

エラーがスローされるたびにプログラム内のコードの実行が停止するため、なぜ自発的にエラーをスローしたいのか理解するのは難しいかもしれませんが、多くの場合、関数が正しく使用されていないときやプログラムが適切な環境で実行されていないときにエラーをスローし、コードをデバッグしなければならない人が、何が悪いのか気付かずにコードを長時間見つめることなく、速く間違いを見つけるのに役立ちます。

エラーがコードを停止するのを防ぎ、代わりにユーザーにエラーメッセージを表示して、開発者にバグを報告できるようにすることが役立つ場合があります。これは例外処理(またはエラー処理)と呼ばれ、エラーをキャッチして伝播を防ぎ、例外ハンドラーを実行して処理することで実行されます。さまざまなプログラミング言語でこの方法は大きく異なります。Luaでは、プロテクトされた呼び出しを使用して行われます[1]。プロテクトモードで呼び出された関数は、エラーが発生してもプログラムを停止しないため、これらはプロテクト呼び出しと呼ばれます。プロテクトモードで関数を呼び出すために使用できる関数は2つあります。

関数 説明
pcall(function, ...) プロテクトモードで関数を呼び出し、ステータスコード(エラーがスローされたかどうかによって値が異なるブール値)と関数によって返される値、または関数がエラーによって停止された場合はエラーメッセージを返します。引数は、プロテクトモードで呼び出す必要のある関数である最初の引数の後にpcall関数に渡すことで関数に指定できます。
xpcall(function, handler, ...) pcallと同じことを行いますが、関数エラーが発生すると、pcallが返すのと同じ値を返す代わりに、それらをパラメーターとしてハンドラー関数を呼び出します。次に、ハンドラ関数を使用して、たとえば、エラーメッセージを表示できます。pcall関数に関しては、xpcall関数に対して引数として与えることで関数に引数を渡すことができます。

Stack overflow

呼び出しスタック、つまり呼び出された順序で呼び出されたすべての関数を含むスタックについては、前述しました。Luaを含むほとんどの言語でのその呼び出しスタックには、最大サイズがあります。この最大サイズは非常に大きいため、ほとんどの場合心配する必要はありませんが、自分自身を呼び出す関数(これは再帰性と呼ばれ、このような関数は再帰関数と呼ばれます)は、自分自身を呼び出すことを妨げるものがない場合、この制限に達するまで無期限に再帰を続ける可能性があります。これはスタックオーバーフローと呼ばれます。スタックがオーバーフローすると、コードの実行が停止し、エラーがスローされます。

Variadic functions

可変引数関数は、vararg関数とも呼ばれ、可変数の引数を受け入れる関数です。可変個引数関数は、パラメーターリストの最後にある3つのドット( "...")で示されます。パラメータリストのパラメータに収まらない引数は、破棄されるのではなく、vararg式を介して関数で使用できるようになります。これも3つのドットで示されます。 vararg式の値は、値のリスト(テーブルではない)であり、次の式を使用して、より簡単に操作できるようにテーブルに配置できます。

{...}

Lua 5.0では、vararg式を介して使用できる代わりに、「arg」という特別なパラメーターで追加の引数を使用できました。次の関数は、受け取ったすべての引数に最初の引数を追加し、次にそれらすべてを合計して結果を出力する関数の例です。

function add_one(increment, ...)
    local result = 0
    for _, number in next, {...} do
        result = result + number + increment
    end
end

上記のコードは可変個引数関数のデモンストレーションにすぎないため、理解する必要はありません。

このselect関数は、テーブルを使用せずに引数リストを操作するのに役立ちます。引数の数が不定であるため、それ自体がvariadic関数です。最初の引数として指定された番号を使用して、引数の後のすべての引数を返します(指定された番号が負の場合、最後からインデックスを付けます。つまり、-1が最後の引数です)。また、最初の引数が文字列 "#"の場合、最初の引数を除いて、受け取った引数の数も返します。引数リスト内の特定の数より前のすべての引数を破棄すると、より元々は、引数として送信されるnil値と、引数として送信されない値を区別するのに役立ちます。#は最初の引数として、値が無いことから nil 値が指定されるとselectは区別します。引数リスト(および戻りリストも)はタプル(tuples:いくつかの部分からなるデータの構造)のインスタンスであり、テーブルに関する章で説明します。このselect関数はすべてのタプルで機能します。

print((function(...) return select('#', ...) == 1 and "nil" or "no value" end)()) --> no value
print((function(...) return select('#', ...) == 1 and "nil" or "no value" end)(nil)) --> nil
print((function(...) return select('#', ...) == 1 and "nil" or "no value" end)(variable_that_is_not_defined)) --> nil

-- As this code shows, the function is able to detect whether the value nil was passed as an argument or whether there was simply no value passed.
-- In normal circumstances, both are considered as nil, and this is the only way to distinguish them.
  1. 詳細については、Ierusalimschy、Roberto(2003)を参照してください。 "Error Handling in Application Code". Programming in Lua (first ed.). Lua.org. ISBN 8590379817. http://www.lua.org/pil/24.3.1.html. Retrieved June 20, 2014.
  2. For more information, see: Ierusalimschy, Roberto (2003). "Error Handling in Application Code". Programming in Lua (first ed.). Lua.org. ISBN 8590379817. http://www.lua.org/pil/24.3.1.html. Retrieved June 20, 2014.

Standard libraries

Luaは「バッテリーが付属していない」と言われている言語です。これは、そのライブラリがいくつかのことを行うために必要な最小限に保たれていることを意味します。Luaはコミュニティに依存して、より具体的なタスクを実行するために使用できるライブラリを作成しています。Luaには10のライブラリがあります。Luaのリファレンスマニュアルは、すべてのライブラリのドキュメントを提供しています[1]。ここで簡単に説明されています[2]。基本ライブラリとパッケージライブラリを除くすべてのライブラリは、テーブルのフィールドとして関数と値を提供します。

Basic library

基本ライブラリはLuaにコア機能を提供します。そのすべての関数と値はグローバル環境で直接利用可能であり、デフォルトでグローバル環境で直接利用可能なすべての関数と値は基本ライブラリの一部です。

Assertion

アサーションは、開発者が true であると想定する述語です。これらは、プログラムの実行の特定の瞬間に特定の条件が真であることを保証するためにプログラムで使用されます。アサーションは、プログラムが正しく機能することを確認するためのunit testsで使用されますが、プログラムコードでも使用されます。この場合、アサーションが false の場合、プログラムが正しい環境を確認するため、またはプログラムコードでエラーが発生していないことを確認し、適切なエラーメッセージを生成して、予期したとおりに何かが発生しなかったときにコードのバグを見つけやすくします。 Luaでは、条件とメッセージ(デフォルトでは「アサーションに失敗しました!」)をパラメーターとして受け入れるassert関数を使用してアサーションが作成されます。条件が false と評価された場合、assertはメッセージとともにエラーをスローします。true と評価された場合は、assertはすべての引数を返します。

Garbage collection

ガベージコレクションは、Lua や他の多くの言語で実装されている自動メモリ管理の一形態です。プログラムがデータを変数に格納する必要がある場合、プログラムはオペレーティングシステムに、変数の値を格納するためにコンピュータのメモリにスペースを割り当てるように要求します。次に、スペースが不要になると(通常、変数がスコープから外れたため)、別のプログラムがスペースを使用できるように、スペースの割り当てを解除するようにオペレーティングシステムに指示します。 Lua では、実際のプロセスははるかに複雑ですが、基本的な考え方は同じです。プログラムは、変数の値が不要になったときにオペレーティングシステムに通知する必要があります。低水準言語では、割り当ては言語によって処理されますが、割り当て解除は、プログラマーが値を必要としなくなったときに言語が認識できないためではありません。値を参照する変数がスコープから外れたり削除されたりした場合でも、スクリプト内の別の変数またはフィールドがそれを参照している可能性があり、割り当てを解除すると問題が発生します。高水準言語では、割り当て解除は、Luaが使用するシステムであるガベージコレクションなど、さまざまな自動メモリ管理システムによって処理される場合があります。ガベージコレクターは、Lua によって割り当てられたすべての値を定期的に検索して、どこにも参照されていない値を探します。プログラムがアクセスできなくなった値を収集し(参照がないため)、これらの値を安全に割り当て解除できることがわかっているため、割り当てを解除します。これはすべて透過的かつ自動的に行われるため、プログラマーは通常、それについて何もする必要はありません。しかし、時々、開発者は、ガベージコレクターに指示を与えることができます。

Weak references

弱参照は、ガベージコレクターによって無視される参照です。これらの参照は、開発者が mode メタメソッドを使用してガベージコレクターに示します。テーブルの mode メタメソッドは文字列である必要があります。その文字列に文字「k」が含まれている場合、テーブルのフィールドのすべてのキーは弱く、文字「v」が含まれている場合、テーブルのフィールドのすべての値は弱くなります。オブジェクトの配列に弱い値がある場合、ガベージコレクターは、その配列および他の弱い参照でのみ参照されている限り、その配列で参照されている場合でもこれらのオブジェクトを収集します。この動作は便利な場合もありますが、ほとんど使用されません。

Manipulating the garbage collector

ガベージコレクターは、基本ライブラリの一部であり、ガベージコレクターへのインターフェイスとして機能する collectgarbage 関数で操作できます。その最初の引数は、実行するアクションをガベージコレクターに示す文字列です。2番目の引数は、一部のアクションで使用されます。この collectgarbage 関数を使用して、ガベージコレクターを停止し、手動で収集サイクルを実行し、Luaが使用するメモリをカウントできます。

Coroutines

Coroutinesは、サブルーチンを一般化して、特定の場所で実行を一時停止および再開するための複数のエントリポイントを許可するコンピュータプログラムコンポーネントです。コルーチンは、協調タスク例外イベントループイテレータ無限リストパイプ&usg=ALkJrhhdyPCiI1O0UXvWU1Q1dAkZUaEmTg)など、より使い慣れたプログラムコンポーネントの実装に最適です。

ウィキペディアコルーチン

Coroutines are computer program components that generalize subroutines to allow multiple entry points for suspending and resuming execution at certain locations. Coroutines are well-suited for implementing more familiar program components such as cooperative tasks, exceptions, event loop, iterators, infinite lists and pipes).

Wikipedia, Coroutine

コルーチンは、Luaのコルーチンライブラリを使用して作成および操作できるコンポーネントであり、コルーチンを内部から生成する関数またはコルーチンを外部から再開する関数を呼び出すことにより、特定の場所で関数の実行を生成および再開できるようにします 。

例:

  1. メインスレッドの関数は、coroutine.create関数からコルーチンを作成し、coroutine.resumeで再開します。コルーチンには、番号3が渡されます。

  2. コルーチンの関数が実行され、引数として coroutine.resume に渡された数値を取得します。

  3. 関数は、実行の特定の時点に到達しcoroutine.yield、引数として、受け取った引数の合計(3)と2(したがって、3 + 2 = 5)を呼び出します。

  4. coroutine.resumeへの呼び出しはcoroutine.yieldに渡されたため、5を返し、メインスレッドは現在再び実行されており、その数値を変数に格納します。 コードを実行した後、コルーチンを再開し、 coroutine.resumeの呼び出しから受け取った値の2倍をcoroutine.resumeに渡します(つまり、5×2 = 10を渡します)。

  5. コルーチンは、 coroutine.yield の呼び出しの結果として、coroutine.resume に渡された値を取得し、さらにコードを実行した後に終了します。 これは、 coroutine.yield の呼び出しの結果と、最初にパラメーターとして指定された値(つまり、10-3 = 7)との差を返します。

  6. メインスレッドは、 coroutine.resume の呼び出しの結果としてコルーチンによって返される値を取得し、続行します。

この例をコードに入れると、次のようになります。

local co = coroutine.create(function(initial_value)
    local value_obtained = coroutine.yield(initial_value + 2) -- 3+2=5
    return value_obtained - initial_value -- 10-3=7
end)

local _, initial_result = coroutine.resume(co, 3) -- initial_result: 5
local _, final_result = coroutine.resume(co, initial_result * 2) -- 5*2=10
print(final_result) --> 7

coroutine.create関数は、関数からコルーチンを作成します。 コルーチンは「スレッド」タイプの値です。 coroutine.resumeは、コルーチンの実行を開始または継続します。 コルーチンは、エラーが発生した場合、または実行するものが何も残っていない場合(この場合、実行が終了した場合)にデッドと呼ばれます。 コルーチンがデッドの場合、再開することはできません。 coroutine.resume関数は、コルーチンの実行が成功した場合はtrueを返し、コルーチンが終了した場合は返されたすべての値とともに、終了しなかった場合は coroutine.yieldに渡されます。 実行が成功しなかった場合は、エラーメッセージとともに「false」が返されます。 coroutine.resumeは実行中のコルーチンを返し、そのコルーチンがメインスレッドの場合はtrueを返し、それ以外の場合は falseを返します。

このcoroutine.status関数は、コルーチンのステータスを文字列として返します。

  • コルーチンが実行中の場合はrunning。つまり、 coroutine.statusを呼び出したコルーチンである必要があります。
  • コルーチンがyieldの呼び出しで一時停止されている場合、またはコルーチンがまだ実行を開始していない場合は、suspended
  • コルーチンがアクティブであるが実行されていない場合はnormal、つまり別のコルーチンを再開したことを意味します
  • コルーチンの実行が終了した場合、またはエラーが発生した場合はdead

coroutine.wrap関数は、呼び出されるたびにコルーチンを再開する関数を返します。 この関数に指定された追加の引数は、 coroutine.resumeへの追加の引数として機能し、コルーチンによって返される値、またはcoroutine.yieldに渡される値は、関数の呼び出しによって返されます。 coroutine.wrap関数は、coroutine.resumeとは異なり、プロテクトモードでコルーチンを呼び出さず、エラーを伝播します。

コルーチンには多くのユースケースがありますが、それらを説明することはこの本の範囲外です。

String matching

文字列を操作する場合、特定のパターンに従う部分文字列を文字列で検索できると便利なことがよくあります。 Luaには、これを行うための関数と、関数が文字列で検索できるパターンを表現するための表記法を提供する文字列操作ライブラリがあります。 Luaが提供する表記法は、プログラミングの世界のほとんどの言語やツールで使用されるパターンを表現するための正規表現と非常によく似ています。ただし、それはより制限されており、構文がわずかに異なります。

文字列ライブラリのfind関数は、文字列内のパターンの最初の一致を探します。文字列内でパターンが見つかった場合、そのパターンが開始および終了する文字列内のインデックス(最初の文字から始まる文字列内の文字の位置を表す整数)を返します。パターンの出現が見つからない場合は、何も返しません。受け入れる最初のパラメーターは文字列で、2番目はパターン、3番目はfind関数が検索を開始する文字位置を示す整数です。最後に、4番目の引数としてtrue値を指定することにより、パターンなしで単純な一致を実行するようにfind関数に指示できます。次に、最初の文字列で指定された2番目の文字列の出現を検索します。単純一致を実行する場合は、3番目の引数を指定する必要があります。このサンプルコードは、文中の「lazy」という単語を検索し、その単語で見つかった出現箇所の開始位置と終了位置を出力します。

local start_position, end_position = string.find("The quick brown fox jumps over the lazy dog.", "lazy", 1, true)
print("The word \"lazy\" was found starting at position " .. start_position .. " and ending at position " .. end_position .. ".")

このコードでは「lazy」という単語は、位置36で始まり、位置39で終わることがわかりました。これは次と同等です。

local sentence = "The quick brown fox jumps over the lazy dog."
local start_position, end_position = sentence:find("lazy", 1, true)
print("The word \"lazy\" was found starting at position " .. start_position .. " and ending at position " .. end_position .. ".")

これは、文字列の indexメタメソッドが文字列ライブラリの関数を含むテーブルに設定され、 string.a(b, ...)b:a(...)に置き換えることができるために機能します 。

文字の位置を示すインデックスを受け入れる、またはそのようなインデックスを返す文字列ライブラリ内の関数は、最初の文字が位置1にあると見なします。最後の文字が位置-1で、文字列の末尾から逆方向にインデックスを付けます。

パターンは、文字列が一致するかどうかを示す特定の表記法に従う文字列です。この目的のために、パターンには文字クラス、つまり文字のセットを表す組み合わせが含まれています。

文字の組み合わせ 説明
. すべての文字
%a 文字(大文字と小文字)
%c 制御文字
%d 数字
%g 印刷可能な文字(スペース文字を除く)
%l 小文字
%p 句読文字
%s スペース文字
%u 大文字
%w 英数字(数字と文字)
%x 16進数

特殊ではないすべての文字はそれ自体を表し、特殊文字(英数字ではないすべての文字)は、パーセント記号を接頭辞として付けることでエスケープできます。 キャラクタークラスを組み合わせて、セットに入れることで、より大きなキャラクタークラスを作成できます。 セットは、角括弧で囲まれた文字クラスとして示されます(つまり、 [%xp]は、すべての16進文字と文字「p」のセットです)。 文字の範囲は、範囲の終了文字をハイフンで昇順で区切ることで確認できます(つまり、 [0-9%s]は0から9までのすべての数字とスペース文字を表します)。キャレット( ^)文字がセットの先頭(開始角括弧の直後)に配置されている場合、セットには、キャレットがセットの先頭に配置されていなかった場合に含まれていた文字を除くすべての文字が含まれます。

パーセント記号 % の前にある文字で表されるすべてのクラスの補数は、パーセント記号の後に対応する大文字が続くものとして示されます(つまり、 %S はスペース文字を除くすべての文字を表します)。

パターンは、文字列がそれに一致するためにパターン内でどのシーケンスを見つける必要があるかを表すパターンアイテムのシーケンスです。 パターンアイテムは、文字クラスにすることができます。この場合、クラス内の任意の文字に1回一致し、文字クラスの後に「*」文字が続きます。この場合、クラス内の文字の0回以上の繰り返しに一致します(これら 繰り返し項目は常に可能な限り長いシーケンスに一致します)、文字クラスの後に追加( 「+」)文字が続きます。この場合、クラス内の文字の1つ以上の繰り返しに一致します(これらの繰り返し項目も常に可能な限り長いシーケンスに一致します)、文字クラスの後にマイナス( 「-」)文字が続きます。この場合、クラス内の文字の0回以上の繰り返しに一致しますが、最も短いシーケンスまたは文字クラスとそれに続く疑問符に一致します。この場合、クラス内の文字の1つまたは出現なしに一致します。

以前にキャプチャされた部分文字列と同等の部分文字列を一致させることができます。%1は最初にキャプチャされた部分文字列と一致し、 %2は2番目の部分文字列と一致し、以下同様に%9まで続きます。 キャプチャについては、以下で説明します。 リファレンスマニュアルで説明されているように、パターンによって提供される他の2つの機能があります。

%bxy、ここでxとyは2つの異なる文字です。 このような項目は、xで始まり、yで終わり、xとyのバランスが取れている文字列に一致します。 つまり、文字列を左から右に読み、xの場合は + 1、yの場合は-1を数えると、最後のyは、数が0に達する最初のyになります。たとえば、項目 %b()は バランスの取れた括弧で式を照合します。

%f[set]、フロンティアパターン。 このような項目は、次の文字がセットに属し、前の文字がセットに属さないように、任意の位置で空の文字列と一致します。 セットセットは、前述のように解釈されます。 件名の最初と最後は、文字「 '\0'」であるかのように処理されます。

Lua authors, Lua 5.2 Reference Manual

パターンはパターン項目のシーケンスであり、オプションでキャレット^が前に付き、パターンが文字列の先頭でのみ一致できることを示し、オプションでドル記号$が続きます。これは、パターンが文字列の最後でのみ一致できることを示します 。 これらの記号は、文字列の最初または最後に一致を固定すると言われています。 これらの2つの文字は、パターンの最初または最後にある場合にのみ特別な意味を持ちます。

サブパターンは、キャプチャを示すためにパターン内の括弧で囲むことができます。一致が成功すると、キャプチャに一致する文字列の部分文字列は、将来使用するために保存されます。たとえば、gmatchによって返されます。常に左括弧の位置から番号が付けられます。 2つの空の括弧は、現在の文字列位置(数値であり、文字列の一部ではありません)をキャプチャする空のキャプチャを示します。

このgmatch関数を使用して、文字列内のパターンの出現を反復処理できます。find関数とは異なり、検索を開始する初期位置を指定したり、単純なマッチングを実行したりすることはできません。このgmatch関数は、呼び出されると、文字列内の指定されたパターンから次のキャプチャを返すイテレータを返します。パターンにキャプチャが指定されていない場合は、代わりに一致全体が示されます。次の例は、文中の単語を反復処理して1つずつプリントする方法を示しています。

local sentence = "The quick brown fox jumps over the lazy dog."
for word in sentence:gmatch('%a+') do
    print(word)
end

この例では、一致全体は、イテレータであるwordによって返される唯一の値によって与えられます。

gsub関数を使用して、文字列内のパターンのすべての出現箇所を別のものに置き換えることができます。 最初の2つの引数は文字列とパターンで、3番目はオカレンスを置き換える文字列で、4番目は置き換える必要のあるオカレンスの最大数です。 3番目の引数は、文字列ではなく、テーブルまたは関数にすることもできます。

3番目の引数が文字列の場合、それは置換文字列と呼ばれ、文字列内のパターンの出現を置換します。 パターンによって保存されたキャプチャは、置換文字列に埋め込むことができます。 それらは、キャプチャの数を表す数字が続くパーセント記号によって示されます。 一致自体は %0で表すことができます。 置換文字列のパーセント記号は、 %%としてエスケープする必要があります。

3番目の引数がテーブルの場合、最初のキャプチャはそのテーブルにインデックスを付けるためのキーとして使用され、置換文字列はテーブル内のそのキーに対応する値です。 関数の場合、その関数は一致するたびに呼び出され、すべてのキャプチャが引数として渡されます。 どちらの場合も、キャプチャがない場合は、代わりに一致全体が使用されます。 関数またはテーブルの値が falseまたはnilの場合、置換は行われません。

Lua 5.2リファレンスマニュアルから直接引用したいくつかの例を次に示します。

```lua x = string.gsub("hello world", "(%w+)", "%1 %1") --> x="hello hello world world"

x = string.gsub("hello world", "%w+", "%0 %0", 1) --> x="hello hello world"

x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1") --> x="world hello Lua from"

x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv) --> x="home = /home/roberto, user = roberto"

x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s) return load(s)() end) --> x="4+5 = 9"

local t = {name="lua", version="5.2"} x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t) --> x="lua-5.2.tar.gz" ```

Lua authors, Lua 5.2 Reference Manual

Lua は、パターンマッチング以外の文字列操作機能を提供します。これらには、文字の順序を逆にして文字列を返す reverse関数、文字列に相当する小文字を返すlower関数、文字列に相当する大文字を返す upper関数が含まれます。文字列の長さを返す len関数と、引数として指定された2つの文字位置で開始および終了する文字列の部分文字列を返すsub関数。その他についてはLua 5.2リファレンスマニュアルに記載があります。

  1. Ierusalimschy, Roberto; Celes, Waldemar; Henrique de Figueiredo, Luiz. Lua 5.2 Reference Manual. http://www.lua.org/manual/5.2. Retrieved 30 November 2013.
  2. Functions that were already described elsewhere will not be described in this chapter.

Appendix:Software testing

ソフトウェアテストという用語は、コンピュータソフトウェアのバグやプログラミングの間違いを発見するために使用されるいくつかの方法とプロセスを指します。 ソフトウェアテストは静的に実行できます。静的テストと呼ばれ、コンピュータソフトウェアを実行せずに実行されます。動的な場合は、動的テストと呼ばれ、テスト対象のコンピュータプログラムの実行中に実行されます。

Type checking

プログラミング言語では、type systemは、type と呼ばれるプロパティを、コンピュータープログラムで構成されるさまざまな構成要素(変数、式、関数、モジュールなど)に割り当てるルールの集まりです。 型システムの主な目的は、コンピュータープログラムのさまざまな部分の間のインターフェイスを定義し、それらの部分が一貫した方法で接続されていることを確認することによって、コンピュータープログラムのバグを減らすことです。このチェックは、静的(コンパイル時)、動的(実行時)、または静的チェックと動的チェックの組み合わせとして実行できます。 型システムには、特定のコンパイラの最適化の有効化、複数のディスパッチの許可、ドキュメントの形式の提供など、他の目的もあります。

Wikipedia, Type system

ウィキペディアからの抜粋が示すように、型チェックは実行時またはコンパイル時に実行できます。 コンパイル時に実行される場合、コンパイラソースコードコンパイルするときに、プログラムの型安全性を検証し、プログラムが特定の型安全性プロパティを満たしていることを保証します。通常、静的型チェッカーは、変数の値が常に 同じ型であり、関数に渡される引数は正しい型になります。

静的なアプローチにより、開発サイクルの早い段階でバグを発見できます。対照的に、動的アプローチは、プログラムの実行時にプログラムが型制約に従っていることを確認することで構成されます。 これは、動的型チェッカーがより多くの制約を検証できる必要があることを意味しますが、ほとんどの動的型付き言語には多くの型制約がありません。 Luaは動的に型付けされた言語です。Luaでは、値には型がありますが、変数にはありません。 つまり、変数の値は、プログラムの実行のある時点では数値になり、別の時点では文字列になる可能性があります。

Luaの型システムは、他のほとんどの言語と比較して非常に単純です。 演算子が使用されている場合(たとえば、少なくとも1つが数値ではなく、1に強制できない2つの値を追加しようとすると、型エラーが発生します)、および標準ライブラリの関数が呼び出された場合(関数 標準ライブラリのは、正しい型を持たない引数を拒否し、適切なエラーを発生させます)。

Luaには関数パラメーターの型を指定する機能がないため、type関数は、関数に渡される引数が適切な型であることを確認するのに役立ちます。これは、プログラムの実行中にユーザーから提供された引数が渡される関数(たとえば、事前定義されたLua関数を呼び出すための対話型環境)で最も役立ちます。関数に型チェックのコードを追加すると、関数がより冗長になり、メンテナンスのオーバーヘッドが増えるためです。

White-box testing

ホワイトボックステストという用語は、ソフトウェアの内部動作に関する知識を使用して、その機能を検証するためのテストケースを作成する方法を指します。これはソフトウェアテストの3つのレベルに関連していますが、Luaプログラムは通常、統合とシステムテストが行われるより大きなアプリケーションの一部であるため、Luaプログラムにとって最も興味深いのはユニットレベルです。

Luaでのユニットテストに利用できるフレームワークは複数あります。ユニットレベルでのテストは、通常、関数に特定の引数を渡し、関数が予期しない値を返したときに警告を提供するテストケースを作成することで構成されるため、ライブラリに最も適しています。これには、新しい機能のテストケースを作成する必要がありますが、テストに合格しなくなるような方法で関数の動作を変更したときに、コードに導入されたエラーに気づきやすくなるという利点があります。

Luaには複数のユニットテストフレームワークがあります。 そのうちの1つは、バストされ、標準のLua仮想マシンと LuaJIT をサポートし、MoonScript と Terra でも使用できます。前者はLuaコンパイルされる言語で、後者は Lua と相互運用可能な低レベル言語です。 Lua の別のユニットテストフレームワークである Luaunit は、完全にLuaで記述されており、依存関係はありません。 Shake は、当初は Kepler Project の一部であった、より単純なテストフレームワークであり、assert および print 関数を使用しますが、現在は積極的に開発されていません。

Further reading

Lua に関する情報を見つけるための優れたリソースである lua-users wiki は、ソフトウェアテストに関連する資料を提供します。これらのページの一部は、他のページやまたはさまざまなタスクに役立つプロジェクトへのリンクで構成されています。

Glossary

これは、Lua のコンテキストでのプログラミングに関連する用語を含む用語集です。理解できない単語の意味を見つけるために、その使用をお勧めします。

  • abstract class

    抽象クラスは、インスタンスを直接作成できないクラスです。抽象クラスはabstract typesです。

  • abstract data type

    抽象データ型は、データ構造の同様の動作をするクラスを表すモデルです。 抽象データ型は、実装やコンピューターのメモリへのデータの格納方法ではなく、それらに対して実行できる操作と、これらの操作の数学的制約によって定義されます。

    An abstract data type is a model to represent a class of data structures that have similar behavior. Abstract data types are defined by the operations that can be performed on them and by mathematical constraints of these operations rather than by the implementation and the way the data is stored in the memory of the computer.

  • abstract type

    An abstract type is a type of data of which instances cannot be created directly.

  • actual parameter

    See argument.

  • additive inverse

    The additive inverse of a number is the number that, when added to that number, yields zero. For example, the additive inverse of 42 is -42.

  • arithmetic negation

    Arithmetic negation is the operation that produces the additive inverse of a number.

  • arithmetic operation

    An arithmetic operation is an operation whose operands are numbers.

  • arity

    The arity of an operation or of a function is the number of operands or arguments the operation or function accepts.

  • argument

    An argument) is a value passed to a function.

  • array

    An array is a data structure consisting of a collection of values, each identified by at least one array index or key.

  • associative array

    An associative array is an abstract data type composed of a collection of pairs of keys and values, such that each possible key appears at most once in the collection.

  • augmented assignment

    Augmented assignment is a type of assignment that gives a variable a value that is relative to its prior value.

  • binary operation

    A binary operation is an operation of which the arity is two.

  • boolean

    See logical data.

  • boolean negation

    See logical negation.

  • chained assignment

    Chained assignment is a type of assignment that gives a single value to many variables. Example: a = b = c = d = 0.

  • chunk

    A chunk is a sequence of statements.

  • compound assignment

    See augmented assignment.

  • concatenation

    String concatenation is the operation of joining two strings of characters. For example, the concatenation of "snow" and "ball" is "snowball".

  • concrete class

    A concrete class is a class of which instances can be created directly. Concrete classes are concrete types.

  • concrete type

    A concrete type is a type of which instances can be created directly.

  • condition

    A condition is a predicate that is used in a conditional statement or as an operand to the conditional operator. Conditions, in Lua, are considered as true when their expression evaluates to a value other than nil or false, and are considered as false otherwise.

  • conditional operator

    A conditional operator is an operator that returns a value if a condition is true and another if it isn't.

  • conditional statement

    A conditional statement) is a statement that executes a piece of code if a condition is true.

  • data structure

    A data structure is a particular way of storing and organizing data in the memory of a computer. It is the implementation of an abstract data type.

  • data type

    A data type is a model for representing the storage of data in the memory of a computer.

  • dictionary

    See associative array.

  • exclusive disjunction

    imgVenn diagram of {\displaystyle \scriptstyle a\veebar b}\scriptstyle a\veebar bThe exclusive disjunction operation is a binary operation that produces the value true when one of its operands is true but the other is not. The exclusive disjunction of a and b is expressed mathematically as {\displaystyle \scriptstyle a\veebar b}\scriptstyle a\veebar b. There is no operator corresponding to exclusive disjunction in Lua, but {\displaystyle \scriptstyle a\veebar b}\scriptstyle a\veebar b can be represented as (a or b) and not (a and b).

  • formal parameter

    See parameter.

  • function

    A function is a sequence of statements (instructions) that perform a specific task. Functions can be used in a program wherever that particular task needs to be performed. Functions are usually defined in the program that will use them, but are sometimes defined in libraries that can be used by other programs.

  • hash map

    See hash table.

  • hash table

    A hash table is an implementation as a data structure of the associative array. A hash table uses a hash function to compute an index into an array of buckets or slots, from which the value corresponding to the index can be found.

  • inline if

    See conditional operator.

  • integer

    An integer is a number that can be written without a fractional or decimal component. Integers are implemented in Lua in the same way as other numbers.

  • length operation

    The length operation is the operation that produces the number of values in an array.

  • literal

    A literal is a notation for representing a fixed value in source code. All values can be represented as literals in Lua except threads and userdata.

  • logical complement

    The logical complement of a boolean value is the boolean value that is not that value. This means the logical complement of true is false and vice versa.

  • logical conjunction

    imgVenn diagram of {\displaystyle \scriptstyle a\land b}{\displaystyle \scriptstyle a\land b}The logical conjunction operation is a binary operation that produces the value true when both of its operands are true and false in all other cases. It is implemented as the and operator in Lua and it returns its first operand if it is false or nil and the second operand otherwise. The logical conjunction of a and b is expressed mathematically as {\displaystyle \scriptstyle a\land b}{\displaystyle \scriptstyle a\land b}.

  • logical data

    The logical data type, which is generally called the boolean type, is the type of the values false and true.

  • logical disjunction

    imgVenn diagram of {\displaystyle \scriptstyle a\lor b}{\displaystyle \scriptstyle a\lor b}The logical disjunction operation is a binary operation that produces the value false when both of its operands are false and true in all other cases. It is implemented as the or operator in Lua and it returns the first operand if it is neither false nor nil and the second otherwise. The logical disjunction of a and b is expressed mathematically as {\displaystyle \scriptstyle a\lor b}{\displaystyle \scriptstyle a\lor b}.

  • logical negation

    Logical negation, implemented in Lua by the not operator, is the operation that produces the logical complement of a boolean value.

  • map

    See associative array.

  • method

    A method) is a function that is a member of an object and generally operates on that object.

  • modulo

    See modulo operation.

  • modulo operation

    The modulo operation, implemented in Lua by the % operator, is the operation that produces the remainder of the division of a number by another.

  • modulus

    See modulo operation.

  • multiple assignment

    See parallel assignment.

  • nil

    The type nil is the type of the value nil, whose main property is to be different from any other value; it usually represents the absence of a useful value.

  • not operator

    See logical negation.

  • number

    The number type represents real (double-precision floating-point) numbers. It is possible to build Lua interpreters that use other internal representations for numbers, such as single-precision float or long integers.

  • operator

    An operator) is a token that generates a value from one or many operands.

  • parallel assignment

    Parallel assignment is a type of assignment that simultaneously assigns values to different variables.

  • parameter

    A parameter) is a variable in a function definition to which the argument that corresponds to it in a call to that function is assigned.

  • predicate

    A predicate is an expression that evaluates to a piece of logical data.

  • procedure

    See function.

  • relational operator

    A relational operator is an operator that is used to compare values.

  • routine

    See function.

  • sign change

    See arithmetic negation.

  • simultaneous assignment

    See parallel assignment.

  • string

    The type string represents arrays of characters. Lua is 8-bit clean: strings can contain any 8-bit character, including embedded zeros.

  • string literal

    A string literal is the representation of a string value within the source code of a computer program. With respect to syntax, a string literal is an expression that evaluates to a string.

  • subprogram

    See function.

  • subroutine

    See function.

  • symbol

    See token.

  • symbol table

    A symbol table is an implementation as a data structure of the associative array. They are commonly implemented as hash tables.

  • token

    A token is an atomic piece of data, such as a word in a human language or such as a keyword in a programming language, for which a meaning may be inferred during parsing.

  • variable

    A variable) is a label associated to a location in the memory. The data in that location can be changed and the variable will point to the new data.

  • variadic function

    A variadic function is a function of indefinite arity.