Types and Variables(类型与变量)
Types and Variables(类型与变量)
Overview(概述)
ProtoGraph 与 ProtoFlux 一样,拥有强类型、静态类型系统。这意味着程序中的每个值/节点都有一个定义良好的类型,无需运行代码即可确定。ProtoGraph 在编译时会检查类型不匹配,并将其作为错误记录下来,供程序员解决。ProtoGraph 会尝试推断程序中各值的类型,从而减少显式类型注解的需求;但为了提高可读性,建议对重要的值定义进行类型注解。
虽然 ProtoGraph/ProtoFlux 是强类型的,但 ProtoFlux 的序列化形式(.brson Resonite 记录)是弱类型的。任何节点上的任何输入/输出都可以连接到任何其他节点的输入/输出、节点甚至非 Flux 组件。当加载到 Resonite 中时,这些连接会被检查,如果连接无效,则不会在节点之间创建相应的连线(输入/输出字段变为 null)。
为了方便开发和故障排除,ProtoGraph 编译器会尝试将任意节点和值“连接”在一起,即使类型不兼容。编译时会记录错误,但仍会尽力生成 Resonite 记录。然后可以将这个部分正确的记录加载到 Resonite 中,以便进行调试或在结构正确的独立代码段上工作。
Annotations(注解)
类型注解也为代码行为提供了额外的测试:如果注解类型与推导类型不匹配,编译器将产生错误。
模块头部(输入/输出/全局)中的值始终需要类型注解。
module TypeAnnotations
// 头部值必须带有注解
in InputInteger: int
out Times2: int
out Times3: int
where {
// Times2 的类型被推断为 int
Times2 = ValueAdd(InputInteger, InputInteger);
// 但为了清晰,你也可以手动添加类型注解
Times3: int =
ValueAdd<int>(InputInteger, InputInteger)
->ValueAdd<int>(InputInteger);
}
Literals(字面量)
ProtoGraph 能够指定字面量值并将其作为参数传递给节点。每个字面量都有自己的语法,以避免类型检查器产生歧义。编译器不会隐式强制转换字面量类型。
| 类型 (Type) | 描述 (Description) | 语法 (Syntax) | 示例 (Examples) |
|---|---|---|---|
| bool | true 或 false | true / false | true, false |
| char | 单个字符 | 单引号 | 'A' |
| string | 字符串 | 双引号 | "My String" |
| int | 32 位整数 | 数字 或 i | 1, 1i |
| float | 32 位浮点数 | 带小数点、指数或 f | 3.14, 1e10, 5f |
| double | 64 位浮点数 | d | 42d, -1.8e-8 |
| long | 64 位整数 | L | 100000L |
| uint | 无符号 32 位整数 | ui | 42ui |
| ulong | 无符号 64 位整数 | uL | 99999uL |
| short | 16 位整数 | s | 500s |
| ushort | 无符号 16 位整数 | us | 500us |
| byte | 无符号 8 位整数 | uy | 91uy |
| sbyte | 有符号 8 位整数 | y | 1y |
| decimal | 有符号 128 位定点十进制数 | m | 1111m |
Value & Object Types(值类型与对象类型)
ProtoGraph 中的类型分为两类:值类型和对象类型。在 ProtoGraph 中,这决定了类型的默认值:对象的默认值是 null,而值类型的默认值是“零”值(如 0、0.0 和 false)。
Generic Types(泛型)
以另一个类型为参数的类型称为泛型。你可以把它想象成一个接受类型并返回具体类型的函数。
信息:泛型是一种多态形式,它使你能够在多个使用场景中共享通用功能。泛型被称为参数化多态(其他形式的多态包括特设多态和子类型多态)。
Lists(列表)
多个相同类型的值可以组合成一个列表。列表是泛型的,但所有元素必须是相同的类型。列表的类型通过在包含类型名称后放置 [] 来表示,例如 string[]、bool[] 或 Slot[]。
IntList: int[] = [1, 2, 3];
StringList: string[] = ["Word", "Word2"];
InvalidList: ???[] = [false, 0.2, "A String"];
Variables(变量)
与 ProtoGraph 中的普通值不同,变量是可变的:可以通过写入来改变它们。写入操作可以使用 <- 作为脉冲将新值赋给变量。ProtoGraph 中有 3 种变量,涵盖不同的作用域:
Sync(同步变量)
sync SynchronizedInteger: int;
使用 sync 声明的同步变量,利用数据模型自动与其他用户同步其值。
Store(存储变量)
store StoredInteger: int;
使用 store 声明的存储变量是持久化的,但不会与其他用户同步。
Local(局部变量)
local LocalInteger: int;
使用 local 声明的局部变量是临时的,作用域为脉冲上下文。每个脉冲上下文都有自己的局部变量,一旦脉冲链结束,局部变量将被丢弃。
Casting(类型转换)
使用 as<T> 关键字节点将一种类型强制转换为另一种类型。目标类型作为显式类型参数指定。as<T> 节点接受一个参数:要转换的值。
as<object>("my string");
->as<object>; // 使用管道运算符可使代码更易读
// 转换对象类型
ActuallySlot: object = RootSlot->as<object>;
TheSlot = ActuallySlot->as<Slot>;
// 将值类型转换为其他兼容类型
LargerNumbersAsObject = as<object>(100->as<long> * 100L);
Globals(全局变量)
类型可以附加 global 修饰符。这些类型与普通值分开存在,没有显式转换,不能相互使用。普通值可以使用 asDrivenGlobal 转换为全局变量,并且可以使用 WriteValueToGlobal / WriteObjectToGlobal 写入全局变量。
UserValue = LocalUser;
TrueValue = true;
SecondsTimer(
1.0,
UpdatingUser=UserValue->asDrivenGlobal,
SkipIfNull=asDrivenGlobal(TrueValue),
OnUpdate=ImpulseDisplay);
Null Values(空值)
对象类型和引用类型的默认值是 null(表示没有值)。使用 null<T> 关键字为没有任何内容的类型创建一个值。不能混用不同类型的 null:如果创建了 null<string>,就不能将其用于需要 Asset 的地方。
// 定义空值 Null
NullString = null<string>;
NullSlot = null<Slot>;
// 你可以将它们用作名义类型,但不同节点对空值的处理方式不同
NullString->ConcatenateString("RealString")->display; // displays null
display(NullSlot == RootSlot) // displays false
警告:ProtoFlux 中的所有对象/引用都是可为空的/可选的(它们可能没有具体的值)。ProtoFlux 运行时会自动为你检查这一点,并通过代码传播默认值。虽然你不会像在其他编程语言中那样遇到因 null 引发的异常,但如果一个你期望存在的值实际上是 null,则很容易出现逻辑错误。
Binary, Hexadecimal, & Octal(二进制、十六进制和八进制)
可以使用二进制、八进制和十六进制字符创建字面量数字值。这通过为数字添加前缀 0b(二进制)、0o(八进制)或 0x(十六进制)来实现。默认情况下,它们将被解释为 int(32 位有符号整数),并且可以通过提供后缀(如普通十进制数字那样)来更改数字类型。
DecimalNumber = 1234;
BinaryNumberUnsigned = 0b110011u;
OctalNumber = 0o1662;
HexNumber = 0xab12ef;
No comments to display
No comments to display