文字列のフォーマット
CoddyのLuaジャーニー「Object Oriented Programming」セクションの一部 — レッスン 16/70。
オブジェクトを直接出力すると、Luaはtable: 0x55a...のような、あまり役に立たない情報(単なるメモリアドレス)を表示します。__tostringメタメソッドを使用すると、オブジェクトが出力されたりテキストに変換されたりする際に、そのオブジェクトをどの文字列で表現するかを正確に定義できます。
クラスパターンでは、クラステーブルに関数として __tostring を追加します。クラス自体がインスタンスのメタテーブルとして機能するため、Lua は自動的にこの関数を見つけて使用します:
local Player = {}
Player.__index = Player
function Player:new(name, level)
local instance = {}
setmetatable(instance, self)
instance.name = name
instance.level = level
return instance
end
function Player:__tostring()
return "Player: " .. self.name .. " (Level " .. self.level .. ")"
endこれで、Player インスタンスを print すると、Lua は自動的に __tostring メソッドを呼び出します:
local hero = Player:new("Luna", 5)
print(hero) -- 出力: Player: Luna (Level 5)__tostring はコロン構文を使用し、self を受け取ることに注意してください。これにより、すべてのインスタンスデータにアクセスできるようになります。この関数は文字列を返す必要があります。オブジェクトに合わせて、任意の属性を読みやすい表現に組み合わせて、自由にフォーマットできます。
チャレンジ
簡単自己紹介ができる Book クラスを作成しましょう!本を直接プリントしたときに、Lua が謎めいたメモリ番地ではなく、きれいにフォーマットされた文字列を表示するようにします。これはすべて __tostring メタメソッドのおかげです。
コードは2つのファイルに分けて構成します:
Book.lua: 標準的なプロトタイプパターンを使用してBookクラスを定義します。各本にはtitleとauthorを保存する必要があります。:new(title, author)コンストラクタを含め、本をプリントしたときに読みやすい形式で情報が表示されるように__tostringメタメソッドを実装してください。main.lua: Book モジュールをrequireし、本のインスタンスを作成して、カスタム文字列フォーマットが動作することを確認するためにそれらを直接プリントします。
__tostring メソッドは、以下の正確な形式で文字列を返す必要があります:
"[title]" by [author]出力文字列の中で、タイトルが二重引用符(ダブルクォーテーション)で囲まれていることに注意してください。
4つの入力を受け取ります:
- 1冊目の本のタイトル
- 1冊目の本の著者
- 2冊目の本のタイトル
- 2冊目の本の著者
メインファイルで、提供された入力を使用して2つの本を作成し、各本を直接プリントしてください(メソッドを呼び出すのではなく、単に print(book) とします)。各本はそれぞれの行に表示される必要があります。
例えば、入力が The Hobbit、J.R.R. Tolkien、1984、George Orwell の場合、出力は以下のようになります:
"The Hobbit" by J.R.R. Tolkien
"1984" by George Orwell__tostring は文字列を返す必要があること、そしてクラステーブルがインスタンスのメタテーブルとして機能するため、本をプリントするときに Lua が自動的に __tostring 関数を見つけて使用することを忘れないでください。
チートシート
__tostring メタメソッドは、オブジェクトがプリントされたりテキストに変換されたりする際に、どのように文字列として表現されるかを定義します。
__tostring がない場合、オブジェクトをプリントするとそのメモリアドレスのみが表示されます。
print(someObject) -- Output: table: 0x55a...クラスのメソッドとして __tostring を追加し、文字列表現をカスタマイズします。
local Player = {}
Player.__index = Player
function Player:new(name, level)
local instance = {}
setmetatable(instance, self)
instance.name = name
instance.level = level
return instance
end
function Player:__tostring()
return "Player: " .. self.name .. " (Level " .. self.level .. ")"
endインスタンスをプリントすると、Lua は自動的に __tostring を呼び出します。
local hero = Player:new("Luna", 5)
print(hero) -- Output: Player: Luna (Level 5)主なポイント:
- メソッドが
selfを受け取れるように、コロン構文 (:) を使用します - 必ず文字列を返す必要があります
selfを通じてインスタンスのデータにアクセスします- クラステーブルがメタテーブルとして機能するため、Lua は自動的に
__tostringを見つけます
自分で試してみよう
-- Bookモジュールを読み込む
local Book = require('Book')
-- 入力を読み込む
local title1 = io.read()
local author1 = io.read()
local title2 = io.read()
local author2 = io.read()
-- TODO: Book:new()を使用して2つのブックインスタンスを作成する
-- TODO: 各ブックを直接出力する(print(book)を使用するだけ)
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。