Godot 4中Array添加元素覆盖旧值问题及原理、优化疑问
Godot 4数组append元素被覆盖问题解析
问题场景
我解决了Godot 4中的一个问题,但不理解原理:向Array执行append操作时,最后添加的值会覆盖数组中所有已有元素。
原代码
var myBus=BusinessType.new() func _on_load(): for i in businesses_json.get_data(): myBus.name=i.name print ("showint previous array after name:") for j in Global.businesses: print (j.name) myBus.location=i.location print ("adding "+myBus.name) Global.businesses.append(myBus) print ("now the global array is:") for j in Global.businesses: print (j.name)
原代码运行输出
showint previous array after name: adding first now the global array is: first showint previous array after name: second adding second now the global array is: second second showint previous array after name: third third adding third now the global array is: third third third number business = 3
修改后的代码(将实例化移到循环内)
func _on_load(): for i in businesses_json.get_data(): var myBus=BusinessType.new() myBus.name=i.name print ("showint previous array after name:") for j in Global.businesses: print (j.name) myBus.location=i.location print ("adding "+myBus.name) Global.businesses.append(myBus) print ("now the global array is:") for j in Global.businesses: print (j.name)
修改后运行输出
showint previous array after name: adding first now the global array is: first showint previous array after name: first adding second now the global array is: first second showint previous array after name: first second adding third now the global array is: first second third number business = 3
疑问
- 为何在每次循环中重新定义变量能解决问题?
- 这是不是类似指针的引用机制?
- 每次循环实例化对象会不会消耗更多内存?
- 有没有更优的实现方式?
问题解析与解答
1. 为什么移到循环内就能解决问题?
因为Godot中的自定义类实例属于引用类型。循环外创建的myBus是同一个对象,每次循环只是修改这个对象的name和location属性,然后将该对象的引用添加到数组中。数组里所有元素指向的都是同一个对象,所以最后所有元素显示的都是最后一次修改的属性值。
把实例化代码移到循环内后,每次循环都会创建一个全新的BusinessType对象,修改新对象的属性后再添加到数组,数组里的每个元素都指向不同的独立对象,自然不会互相覆盖。
2. 是不是类似指针的引用机制?
没错。Godot的引用类型变量存储的是对象在内存中的引用(逻辑和指针类似),而非对象本身的副本。当你把myBus添加到数组时,数组存储的是这个引用,而不是对象的克隆体。因此修改原对象的属性,数组中引用指向的对象也会同步变化。
3. 每次循环实例化会不会消耗更多内存?
正常业务场景下完全无需担心这点内存消耗。你本来就需要创建对应数量的BusinessType对象来存储不同的业务数据,这些内存占用是合理且必要的。只有当需要创建上万级甚至更多的对象时,才需要考虑用对象池复用实例,但这种场景在普通Godot项目中极少出现。
4. 更优的实现方式
可以给BusinessType添加带参数的构造函数,简化循环内的代码逻辑:
# 在BusinessType类中添加构造函数 func _init(new_name: String, new_location: String): name = new_name location = new_location # 循环中直接实例化并赋值 func _on_load(): for i in businesses_json.get_data(): var myBus = BusinessType.new(i.name, i.location) Global.businesses.append(myBus)
这样代码更简洁,逻辑更清晰。另外如果不需要调试打印,建议删除循环内的print语句,提升运行效率。
内容的提问来源于stack exchange,提问作者Easy Cap
相关产品推荐
相关产品推荐

