Menu
CoddyTech

セッターによる検証

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 = value

clampi(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)だけなので、その値は単独で有効でなければなりません。

challenge icon

チャレンジ

簡単

セッターを使って、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])
quiz icon腕試し

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

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

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