Menu
Coddy logo textTech

クロージャを介したアクセス

CoddyのLuaジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 45/70。

Private local variables は、それらと決してやり取りできないのであれば役に立ちません。解決策は、closure のスコープにアクセスできる constructor の内部で getter および setter methods を定義することです。

これらのmethodsは:new()の内部で作成されるため、local variablesを「見る」ことができます。それらをobjectにdirectly割り当てます:

local Counter = {}
Counter.__index = Counter

function Counter:new()
    local count = 0  -- プライベート変数
    
    local obj = {}
    
    -- コンストラクタ内でメソッドを定義する
    function obj:getCount()
        return count
    end
    
    function obj:increment()
        count = count + 1
    end
    
    setmetatable(obj, Counter)
    return obj
end

これで、プライベートな count 変数にアクセスできますが、アクセスできるのはあなたが提供するメソッドを通じてのみです。

local c = Counter:new()
print(c:getCount())  -- 0
c:increment()
c:increment()
print(c:getCount())  -- 2
print(c.count)       -- nil(まだ隠されている!)

:getCount():increment()はクラステーブルではなく、obj上に直接定義されていることに注意してください。各instanceはこれらの関数を独自にコピーして持ち、それぞれが自身のprivateなcountにアクセスできます。これがトレードオフです。真のプライバシーには少し多くのメモリが必要になります。これは、methodsがプロトタイプを通じて共有されないためです。

challenge icon

チャレンジ

簡単

Celsius で温度値を保存するために closure-based privacy を使用し、制御されたアクセスを提供する getter と setter methods を constructor 内で定義する Temperature class を作成しましょう!

コードを 2 つのファイルに分けて整理します。

  • Temperature.lua:温度値を constructor 内の local variable に保存する class を作成します。外部からのアクセスから完全に hidden になります。constructor :new(initialCelsius) は温度を local variable に保存し、その後、次の methods を直接 object instance 上に Define します。
    • :getCelsius():現在の温度を Celsius で返します
    • :setCelsius(value):温度を新しい値に更新します
    • :getFahrenheit():次の Formula を使用して、温度を Fahrenheit に converted して返します:(celsius * 9/5) + 32
  • main.lua:Temperature module を Require し、input から 2 つの値、つまり initial temperature と設定する new temperature を read します。initial value で Temperature instance を Create し、Celsius と Fahrenheit の readings を Print します。その後 setter を使用して温度を change し、両方の readings をもう一度 Print します。

次の 2 つの input を受け取ります。

  1. Celsius での initial temperature(数値)
  2. 設定する new temperature(数値)

output は、change 前後の temperature readings を示す 4 行にしてください。

Celsius: {initialValue}
Fahrenheit: {convertedInitial}
Celsius: {newValue}
Fahrenheit: {convertedNew}

たとえば、input が 0100 の場合、output は次のようになります。

Celsius: 0
Fahrenheit: 32
Celsius: 100
Fahrenheit: 212

temperature value は :new() 内の local variable に保存し、self 上には保存しないでください。getter と setter methods は constructor 内で Define され、closure を通じてこの private variable にアクセスできます。temp.celsius または temp._celsius に直接アクセスしようとすると、nil が返されるはずです。

自分で試してみよう

-- Temperatureモジュールを読み込む
local Temperature = require('Temperature')

-- 入力値を読み取る
local initialTemp = tonumber(io.read())
local newTemp = tonumber(io.read())

-- TODO: 初期値でTemperatureインスタンスを作成する

-- TODO: 初期の摂氏と華氏の測定値を出力する

-- TODO: セッターを使って温度をnewTempに変更する

-- TODO: 更新後の摂氏と華氏の測定値を出力する
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Luaオンラインコンパイラ