泛型和变参
泛型和变参
泛型节点
很多情况下数据处理的逻辑并不依赖于数据本身的类型。我们可以用 if-else
这个内置节点作为例子说明。
这个节点接受一个 Boolean 类型的输入 COND
的结果来决定输出 T
端口还是 F
端口的值到输出端口 R
。显然的,这个过程跟 T
、F
和 R
的数据类型并没有什么关系,唯一的要求是他们的类型应该一致,比如都是数值或者都是字符串。
理解泛型
我们可以通过端口的颜色来判断这个节点是否为泛型节点。泛型节点的输入端口是灰色的。另外还可以通过选中该节点并按 H 打开帮助窗格,泛型节点的输入端口数据类型通常会是类似于 t1
,t2
这样的,而不是具体的 Number
或者 String
。
如果某个输入端口的类型为 t1
,即表示这个端口可以接受任何数据类型。
大多数情况下我们使用泛型节点时可以就当一个普通的节点,无需考虑其背后的实现机理,但是有些时候我们也需要在处理一些极限情况时理解一下泛型节点的相关知识。
泛型特化
系统会试图将泛型节点替换为相应的泛型特化节点。这个特化的过程依赖于对输入端口的数值类型的判断。
我们仍然用 gate
节点作为例子。事实上 gate
只是个抽象节点,在编译时系统会将这个抽象节点按照输入端口数据类型推导为某个特化版本的节点,比如 gate(number)
或 gate(string)
。
可以看到泛型特化节点的名称为一个常规的节点名称后带由括号包围着的特化类型名称。如果这个节点包含不止一个泛型类型,则由逗号分隔,如 foo(number, string)
。
开发者也可以通过如下任一方法来进行手动特化:
像使用普通节点直接使用特化版本的节点,比如直接使用
gate(number)
;在搜索一个泛型节点时在名称后输入左括号
(
可以列出所有该节点的特化版本,比如输入gate(
会列出gate(number)
,gate(boolean)
等;在添加一个泛型节点后,左侧观察者窗格节点名称下会用下拉框方式列出所有的特化版本,选择其中一个即可;
系统在编译时需要替换将泛型节点都替换为特化版本,这个过程将在项目和所有安装到本地的节点库中按特化的名称查找,比如 gate(number
。加入找到不止一个(即使库名称不同,比如 ticos/core/gate(number)
和 somewhere/gate(number)
,系统都会报错。
这种情况下开发者必须通过手动指定特化版本来避免类型推导问题。
如果要尝试创建自己的泛型节点,请查看文档进阶话题-创建泛型节点。
可变参数
我们在传统开发时代就经常遇到函数不确定应该接受几个参数的情况,通常是一些集合的管理场景,比如对一系列数值求和或者取平均数。一般的解决方法是直接传一个集合到这个函数里,由这个函数来便利传入的集合并进行处理。这种用法无可厚非,但是如果到了可视化开发的场景,就会导致可表达性的问题。
这个时候,已经存在了多年的可变参数功能就可以发挥非常大的作用。
在 Ticos Studio 中,可变参节点看起来大概如下所示:
可以看到,这种节点的特征是右侧有一个小把手。当把鼠标指针悬浮到这个把手上时,可变参端口上会出现一个省略号图标。如果向右侧拖动这个把手,将会看到输入参数的数量会持续增加。
一个节点的可变参数的最大可达数量被称为元数。一般节点的元数为 1,如果添加了一个端口,则元数会变成 2。如此类推。
标记节点
为了使某个节点支持变参,我们需要在这个节点里放置一个特殊的标记节点。
在系统内置的节点库 ticos/flow-nodes
中,我们可以找到需要的标记节点 variadic-1
,variadic-2
和 variadic-3
。节点末尾的数字表示了参数复制时的分组规则。比如 variadic-3
表示将按照从末尾倒数的 3 个参数为一组进行复制。
提示
这些标记节点本身并不带任何其他功能,且在代码编译的时候会被去除掉。因此对于系统性能不会带来任何负担。
端口含义
一旦在节点中放置了标记节点,每一个输入端口就需要按可变参节点的规则进行定义。比如如下的一个放置了 variadic-2
标记节点的自定义节点:
所包含的 8 个输入端口会被分为三组设置不同的角色:
可变端口。右侧最末尾的两个端口将被当做可变端口(为什么是两个?因为放置了
variadic-2
标记)。在这个例子里,就是V1
和V2
这两个端口。累加端口。本例中的
A1
,A2
,A3
,A4
这中间的四个端口都是累加端口,数量跟输出端口的数量相等。共享端口。除了以上两种端口外,靠左侧的剩余其他端口都被称为共享端口,也就是这个例子里的
S1
和S2
。
提示
要完整的理解上述三种端口的划分原因,需要深入了解可变参节点的实现机理。
节点开发规则
为了让 IDE 能够准确理解和处理我们创建的可变参节点,这些节点的设计必须符合如下几个规则:
一个可变参节点内只能放置一个
variadic-*
标记节点;一个可变参节点需要有至少一个输出端口;
输入端口的数量必须不小于输出端口数量加上元数;
累加端口的数据类型必须输出端口的数据类型严格匹配,即使使用一些可隐式转换的类型也不允许;
在界面上我们有时会发现 variadic-*
节点会被渲染为红色边框或者名称会带波浪形红色下划线。这表示系统认为这个节点没有完全符合以上的原则。
以上的错误就是因为在可变参节点里放置了不止一个 variadic-*
标记节点,这违反了上面的第一条规则。
隐藏实现细节
我们可能不想展示所有的端口给终端用户,这个时候可以使用 variadic-pass
节点来将相关的实现细节隐藏。