内置类型(Built-in types)

所谓的“内置类型”或简称“内置”(builtins)是 Godot 提供的基本类型。值得注意的是,这些并不是 classes)。 另请参见 Godot 中的基本内置类型

目录

类列清单

以下是按类别列出的所有内置类型的完整清单。我们使用 GDScript 中的名称;在下面,我们将解释它们如何映射到 Rust。

简单类型

  • 布尔: bool
  • 数值: int, float

复合类型

  • Variant (能够容纳任何东西): Variant
  • String 类型: String, StringName, NodePath
  • 引用计数容器: Array (Array[T]), Dictionary
  • Packed arrays: Packed*Array 对于以下元素类型:
    Byte, Int32, Int64, Float32, Float64, Vector2, Vector3, Vector41, Color, String
  • Functional: Callable, Signal

几何类型

  • Vectors: Vector2, Vector2i, Vector3, Vector3i, Vector4, Vector4i
  • Bounding boxes: Rect2, Rect2i, AABB
  • Matrices: Transform2D, Transform3D, Basis, Projection
  • Rotation: Quaternion
  • 几何对象: Plane

杂项

  • 颜色: Color
  • Resource ID: RID

Rust 映射

gdext API 中的 Rust 类型尽可能以最接近的方式表示相应的 Godot 类型。例如,它们被用作 API 函数的参数和返回类型。它们可以通过 godot::builtin 访问,且大多数符号也包含在 prelude 中。

大多数内置类型都有 1:1 的对应关系(例如:Vector2fColor 等)。以下列表显示了一些值得注意的映射:

GDScript 类型Rust 类型Rust 示例表达
inti642-12345
floatf6423.14159
realreal (either f32 or f64)real!(3.14159)
StringGString"Some string" 3
StringNameStringName"MyClass" 3
NodePathNodePath"Nodes/MyNode" 3
Array[T]Array<T>array![1, 2, 3]
ArrayVariantArray
Array<Variant>
varray![1, "two", true]
DictionaryDictionarydict!{"key": "value"}
AABBAabbAabb::new(pos, size)
ObjectGd<Object>Object::new_alloc()
SomeClassGd<SomeClass>Resource::new_gd()
SomeClass (nullable)Option<Gd<SomeClass>>None
Variant (also implicit)VariantVariant::nil()

请注意,Godot 的类 API 目前尚未提供空值信息。这意味着我们必须保守地假设对象可能为 null,因此在对象返回类型上使用 Option<Gd<T>> 而不是 Gd<T>。这通常会导致不必要的解包操作。

可空类型(nullable types)正在 Godot 方面进行研究 关于 Godot 端的空值问题。如果上游暂时没有解决方案,我们可能会考虑自己的变通方法,但这可能需要对许多 API 进行手动注解。

String 类型

Godot 提供 三种 string 类型: String (在 Rust 中是GString), StringName, 和 NodePathGString 用作通用字符串,而 StringName 通常用于标识符,例如类名或动作名称。StringName 的特点是构造和比较非常高效。4

在使用 Godot API 时,你可以将参数类型的引用传递给函数(例如 &GString),以及 Rust 字符串 &str&String。 要在参数上下文中转换不同的字符串类型(例如 StringName -> GString),你可以调用 arg()

#![allow(unused)]
fn main() {
// Label::set_text() takes impl AsArg<GString>.
label.set_text("my text");
label.set_text(&string);           // Rust String
label.set_text(&gstring);          // GString
label.set_text(string_name.arg()); // StringName
}

在参数上下文之外,From trait 用于字符串转换:GString::From("my string"),或者使用 "my_string".into()

特别是,StringName提供了从C字符串字面量(如c"string")的直接转换,该特性在Rust 1.77中引入。 这可以用于 静态 C字符串,即那些在整个程序生命周期内保持分配的字符串。不要将其用于短生命周期的字符串。

数组和字典

Godot的线性集合类型是 Array<T>. 它是对元素类型T的泛型,可以是任何支持的Godot类型(通常是可以由Variant表示的任何类型)。 提供了一个特殊类型VariantArray,作为Array<Variant>的别名,当元素类型是动态类型时使用。

Dictionary 是一个键值对存储,其中键和值都是Variant。Godot目前不支持泛型字典,尽管这个特性正在讨论中.

数组和字典可以使用三个宏来构建:

#![allow(unused)]
fn main() {
let a = array![1, 2, 3];          // Array<i64>
let b = varray![1, "two", true];  // Array<Variant>
let c = dict!{"key": "value"};    // Dictionary
}

它们的API类似,但与Rust的标准类型VecHashMap并不完全相同。一个重要的区别是,ArrayDictionary是引用计数的,这意味着clone()不会创建一个独立的副本,而是另一个对同一实例的引用。 此外,由于内部元素以variant存储,它们不能通过引用访问。这就是为什么缺少[]操作符(Index/IndexMuttraits,而是提供了at()方法,它返回的是值。

#![allow(unused)]
fn main() {
let a = array![0, 11, 22];

assert_eq!(a.len(), 3);
assert_eq!(a.at(1), 11);         // 超出边界会panic。
assert_eq!(a.get(1), Some(11));  // 也返回值,而不是Some(&11)。

let mut b = a.clone();   // 增加 reference-count.
b.set(2, 33);            // 修改新引用。
assert_eq!(a.at(2), 33); // 原始 array 已经改变。

b.clear();
assert!(b.is_empty());
assert_eq!(b, Array::new()); // new() 创建一个空 array.
}
#![allow(unused)]
fn main() {
let c = dict! {
    "str": "hello",
    "int": 42,
    "bool": true,
};

assert_eq!(c.len(), 3);
assert_eq!(c.at("str"), "hello".to_variant());    // 没找到键会panic。
assert_eq!(c.get("int"), Some(42.to_variant()));  // Option<Variant>,同样是值。

let mut d = c.clone();            // 增加 reference-count.
d.insert("float", 3.14);          // 修改新引用。
assert!(c.contains_key("float")); // 原始字典已经改变。
}

要进行迭代,可以使用iter_shared()。这个方法的工作方式几乎与Rust集合的iter()相似,但其名称强调了在迭代期间你并没有对集合的唯一访问权,因为可能存在对集合的其他引用。 这也意味着你有责任确保在迭代过程中,数组或字典没有被不必要地修改(虽然应该是安全的,但可能会导致数据不一致)。

#![allow(unused)]
fn main() {
let a = array!["one", "two", "three"];
let d = dict!{"one": 1, "two": 2.0, "three": Vector3::ZERO};

for elem in a.iter_shared() {
    // elem 的类型是 GString.
    println!("Element: {elem}");
}

for (key, value) in d.iter_shared() {
    // key 和 value 的类型都是 Variant.
    println!("Key: {key}, value: {value}");
}
}

Packed arrays

Packed*Array 类型用于在连续的内存中高效地存储元素(“打包”)。 * 代表元素类型,例如 PackedByteArrayPackedVector3Array.

#![allow(unused)]
fn main() {
// 从切片创建
let bytes = PackedByteArray::from(&[0x0A, 0x0B, 0x0C]);
let ints = PackedInt32Array::from(&[1, 2, 3]);

// 使用Index和IndexMut操作符来获取/设置单个元素。
ints[1] = 5;
assert_eq!(ints[1], 5);

//  作为Rust shared/mutable slices访问。
let bytes_slice: &[u8] = b.as_slice();
let ints_slice: &mut [i32] = i.as_mut_slice();

// 使用相同类型访问数组的子范围。
let part: PackedByteArray = bytes.subarray(1, 3); // 1..3, 或 1..=2
assert_eq!(part.as_slice(), &[0x0B, 0x0C]);
}

Array不同,Packed*Array使用写时复制(copy-on-write),而不是引用计数。当你克隆一个Packed*Array时,你会得到一个新的独立实例。只要不修改任何实例,克隆是便宜的。

一旦使用写操作(任何带有&mut self的操作),Packed*Array会分配自己的内存并复制数据。



脚注

1

PackedVector4Array 仅在Godot 4.3版本中可用;在 PR #85474中添加。.

2

Godot的intfloat类型在Rust中通常映射为i64f64。然而,某些Godot API更加具体地指定了这些类型的域,因此可能会遇到i8u64f32等类型。

3

字符串类型GStringStringNameNodePath可以作为字符串字面量传递给Godot API,因此在这个示例中使用了"string"语法。要为自己的值赋值,例如类型为GString,可以使用GString::from("string")"string".

4

当从&strString构造StringName时,转换相当昂贵,因为UTF-8会被重新编码为UTF-32。由于Rust最近引入了C字符串字面量(c"hello"),如果是ASCII字符串,现在我们可以直接从它们构造StringName。这种方式会更高效,但是会使内存在程序关闭之前一直保持分配,因此不要将其用于生命周期短暂的临时字符串。有关更多信息,请参阅API文档issue #531