字典
字典是一个关联容器,包含值(Value)和唯一的键(Key)的引用。
添加新条目时,字典会保持插入顺序。在其他编程语言中,这种数据结构有时也称为哈希表(Hash Table)或关联数组(Associative Array)
同一个值可能对应不同的键,但同一个键只会有一个对应的值,在字典中键是唯一的不允许重复的,这种键值对应的一个条目,我们称之为键值对(Key-Value Pair)
像是数组中的值,我们将其称之为“元素(element)”
而字典中的键值对,我们除了称之为“元素(element)”,也可以将其称之为“条目(entry)”
因此,也可以借助字典实现令函数返回多个值
func try_parse_to_int(s:String) -> Dictionary[String, Variant]:
return {
"success" : s.is_valid_float(),
"result" : s.to_int()
}特别的是,!=和==运算符并非比较字典的引用,而是比较的内容。当字典条目和大小相同时==返回true,!=返回false,即使条目的顺序并不相同
创建
字典使用大括号{}创建,在创建时在大括号内放置用逗号分割的一对对键值(键 : 值)列表就可以添加初始键值对
var my_dict = {} # 创建空字典。
var dict_variable_key = "Another key name"
var dict_variable_value = "value2"
var another_dict = {
"Some key name": "value1",
dict_variable_key: dict_variable_value,
}
var points_dict = {"White": 50, "Yellow": 75, "Orange": 100}字典可以使用任意类型的数据常量或变量用作键值对的键或值,但最常用的还是使用字符串、唯一字符串、整数来作为字典的键,因为这样便于访问和数据交换
除了常规的语法,GDScript还支持使用Lua风格的Table语法来创建字典。
使用=而非:,且字符串键不使用引号
需要注意的是,这种形式编写的键和GDScript标识符一样不能以数字开头,并且无法使用已有的变量的值作为键,每一个键都是一个字符串字面量
var d = {
test22 = "value",
some_key = 2,
other_key = [2, 3, 4],
more_key = "Hello"
}字典允许包含不同类型的键和值,也允许嵌套结构
var d = {4: 5, "A key": "A value", 28: [1, 2, 3]}
var my_dict = {
"String Key": 5,
4: [1, 2, 3],
7: "Hello",
"sub_dict": {"sub_key": "Nested value"},
}访问
可以通过键来访问字典中对应的值
var d = {4: 5, "A key": "A value", 28: [1, 2, 3]}
print(d[4]) # 输出 5
print(d["A key"]) # 输出 "A value"
print(d[28]) # 输出 [1, 2, 3]访问不存在的键时将引发错误!
你还可以在访问时,取出对应的值
这方面同数组一样,键值对的值都是传递的副本,修改其值不会影响到原始键值对,如果值是对象,修改属性会影响键值对中的对象,但为其赋予一个新的实例不会影响键值对中的对象
var value = d["A Key"]
value = "New value"
print(value) # 输出 "New value"
print(d["A Key"]) # 输出 "A value"除此之外,如果字典的键是标准的标识符,并且类型为字符串,你也可以使用点语法来访问,否则只能使用方括号来访问
除了在方括号中填入字面量,你也可以使用变量或表达式;同样地,使用变量访问时,也无法使用点语法
不要混用点语法和方括号语法,这样会降低代码可读性
@export_enum("White", "Yellow", "Orange") var my_color: String
var points_dict = {"White": 50, "Yellow": 75, "Orange": 100, "Alice Blue" : 120}
print(points_dict.White) # 输出 50
print(points_dict.Yellow) # 输出 75
print(points_dict.Orange) # 输出 100
print(points_dict[my_color]) # 不能使用点语法,因为`my_color`是变量
print(points_dict["Alice Blue"]) # 该条目不能使用点语法,因为键不是合法标识符赋值
如果字典不是只读的,向字典添加条目时,像已有键一样访问并赋值即可
字典不允许存在重复的键,因此,如果键存在于字典中则会修改其值,如果不存在则会新建条目
新的条目会追加到字典最末尾
var points_dict = {"White": 50, "Yellow": 75, "Orange": 100}
points_dict["Blue"] = 150 # 将 "Blue" 添加为键,并将 150 赋为它的值。
print(points_dict) # 输出 { "White": 50, "Yellow": 75, "Orange": 100, "Blue": 150 }也可以使用点语法进行赋值,不过点语法赋值新增的键其类型是唯一字符串(&"")
points_dict.Red = 120
print(points_dict) # { "White": 50, "Yellow": 75, "Orange": 100, "Blue": 150, &"Red": 100 }不写赋值号就是访问键,如果键不存在会报错;写赋值号并跟上一个表达式就是修改或添加键,如果键不存在不会报错
遍历
字典同样可以使用for语句进行遍历,需要注意的是,迭代变量的值是字典的键,而非字典的值,也不是整个键值对
var groceries = {"Orange": 20, "Apple": 2, "Banana": 4}
for fruit in groceries:
var amount = groceries[fruit]不要在遍历时修改元素数量,可能会造成无法预知的行为!
传递字典(按引用)
和数组一样,字典同样按引用传递,其规则与其一致,此处不再重复赘述
为了避免“连带修改”的情况,必要时,可以使用Dictionary.duplicate方法来复制一份新的字典
嵌套结构
字典也允许嵌套结构,和数组一致,嵌套的数组和字典也是按引用传递
必要时可以使用深拷贝Dictionary.duplicate(true)来避免连带修改嵌套的字典和数组
类型化字典
仅限Godot4.4或更高版本
与数组相同,字典也支持类型化,在开发时为开发者提供类型安全,其规则与类型化数组一致,通过Dictionary[KeyType, ValueType]指定
var my_dict : Dictionary[String, int] = {"Apple" : 10, "Orange" : 12}同样,不能直接将类型化字典赋值给不同类型的类型化字典,即使该类型是字典所接收类型的子类型
必要情况下可以使用Dictionary.assign方法赋值并进行类型转换
无类型的字典Dictionary等效于Dictionary[Variant, Variant]
类型化字典无法嵌套类型化集合:如Dictionary[String, Array[int]]是不被允许的
练习
创建一个字典,保存三种水果的价格,并打印“Apple”的价格
gdscript# 示例结构: # { # "Apple": 10, # "Banana": 5, # "Orange": 8 # }判断字典中是否有键
"Pineapple",如果有,就什么也不做,如果没有,就添加它并设定价格为12有一个库存字典如下,请遍历这个字典,并将每种物品的数量加1。
gdscriptvar stock = { "Potion": 3, "Elixir": 1, "Ether": 5 }创建一个函数
filter_expensive(dict, price_limit)它接收一个价格字典和一个价格上限,返回一个只包含价格高于上限的物品的新字典。示例输入:
gdscriptvar shop_items = { "Wooden Sword": 50, "Silver Sword": 150, "Potion": 20, "Shield": 100 }调用
filter_expensive(shop_items, 100)应该返回:gdscript{ "Silver Sword": 150 }有一个 RPG 游戏玩家背包结构如下,编写一段代码,将金币加50,药水数量+1,并将最大生命值调成120。
gdscriptvar player_inventory = { "items": {"Potion": 2, "Ether": 1}, "gold": 150, "stats": {"hp": 100, "mp": 30} }创建一个函数
deep_copy_and_upgrade(dict)实现以下逻辑深拷贝原始字典(不影响原字典)
为每一项 stats 增加 10
并返回这个新字典
gdscriptvar stats = { "hp": 100, "mp": 50, "str": 20 }