セッターによる検証
CoddyのGDScriptジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 27/65。
セッターはプロパティが代入されるたびに実行されるため、新しい値を確認する場所として適しています。不正な値に対してPythonはエラーを発生させます。GDScriptには例外がないため、セッターでは代わりに次のいずれかを行います。値を範囲内に収めるか、古い値を保持して問題の内容を記録します。
# character.gd
class_name Character
extends RefCounted
var last_error: String = ""
var hp: int = 100:
set(value):
hp = clampi(value, 0, 100)
var nickname: String = "Player":
set(value):
if value.length() < 3:
last_error = "Name too short"
return
last_error = ""
nickname = valueclampi(value, 0, 100)は、valueを0から100までの範囲に収めて返します。nicknameのセッターでは、returnによって代入の前に処理が終了するため、古い名前がそのまま残り、last_errorでその理由がわかります。
# main.gd
var hero := Character.new()
hero.hp = 250
print(hero.hp) # 100
hero.nickname = "Al"
print(hero.nickname) # Player
print(hero.last_error) # 名前が短すぎます
hero.nickname = "Alice"
print(hero.nickname) # Aliceセッターは、クラス内での代入、_init()内やすべてのメソッド内での代入でも実行されます。コンストラクターの引数をプロパティに代入すると、それらもチェックされます。
func _init(start_hp: int) -> void:
hp = start_hp # セッターが実行される: Character.new(500) の初期値は 100 になるセッター自体の中でhpに代入すると、セッターを再度呼び出さずに値が保存されます。セッターを通らない代入は、宣言時の初期値(= 100)だけなので、その値は単独で有効でなければなりません。
チャレンジ
簡単セッターを使って、thermostat.gd の Thermostat クラスに検証を追加します。
target(初期値は20)は、10から30までの値のみを受け付けます。それ以外の値の場合は、以前の目標値を保持し、last_errorにTarget must be between 10 and 30を設定します。mode(初期値はoff)は、heat、cool、offのみを受け付けます。それ以外のテキストの場合は、以前のモードを保持し、last_errorにUnknown mode:の後にそのテキストを続けた値を設定します。- 有効な値が代入された場合、
last_errorを空文字列に戻します。 _init(start_target)はstart_targetをtargetに代入するため、セッターによる検証が行われます。
用意されたコードは、開始時の目標値、コマンドの数、そして各行に1つずつコマンド(target 25 または mode cool)を読み込みます。サーモスタットの作成後と各コマンドの実行後に、last_error が空でなければ Rejected: とエラーを出力し、その後に状態を出力します。開始値が 22 で、コマンドが target 35 と mode cool の場合、次のように出力されます。
Target 22, mode off
Rejected: Target must be between 10 and 30
Target 22, mode off
Target 22, mode coolコードは thermostat.gd に記述します。main.gd には用意された入出力コードが含まれており、編集できません。
自分で試してみよう
extends Node
func _ready():
# 提供された入出力コード: そのままにしてください
var thermostat := Thermostat.new(int(OS.read_string_from_stdin()))
report(thermostat)
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ")
if parts[0] == "target":
thermostat.target = int(parts[1])
else:
thermostat.mode = parts[1]
report(thermostat)
func report(thermostat: Thermostat) -> void:
if thermostat.last_error != "":
print("Rejected: " + thermostat.last_error)
print("Target %d, mode %s" % [thermostat.target, thermostat.mode])
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: GDScriptオンラインコンパイラ