使用 setter 进行验证
本课属于 Coddy GDScript 学习旅程的“面向对象编程”单元。第 27 课,共 65 课。
每次给属性赋值时,setter 都会运行,因此这里适合检查新值。Python 会因无效值而引发错误。GDScript 没有异常,因此 setter 会采用以下做法之一:将值限制在有效范围内,或者保留旧值并记录出错原因。
# 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) # Name too short
hero.nickname = "Alice"
print(hero.nickname) # Alice在类内部进行赋值时,设置器也会运行,包括在 _init() 中以及每个方法中。通过属性赋值构造函数的参数,这些参数也会经过检查:
func _init(start_hp: int) -> void:
hp = start_hp # 会运行 setter:Character.new(500) 的初始值为 100在 setter 本身中,赋值给 hp 会存储该值,而不会再次调用 setter。唯一会跳过 setter 的赋值是声明中的初始值(= 100),所以这个值本身必须有效。
挑战
简单为 thermostat.gd 中的 Thermostat 类添加带设置器的验证:
target(初始值为20)只接受从10到30的值。对于其他任何值,它都会保留旧的 target,并将last_error设置为Target must be between 10 and 30。mode(初始值为off)只接受heat、cool和off。对于其他任何文本,它都会保留旧的 mode,并将last_error设置为Unknown mode:,后面接上该文本。- 有效赋值会将
last_error重置为空字符串。 _init(start_target)会将start_target赋给target,因此会对它进行设置器检查。
给定的代码会读取起始目标值,然后读取命令数量,接着每行读取一条命令(target 25 或 mode cool)。创建 thermostat 后以及每条命令执行后,如果 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 在线编译器