# 连接检查
连接检查用于限制哪些连接(也就是哪些块)可以互相连接。
连接检查非常适合表达“类型”约束。
例如下面三个块代表的返回类型不同,本不应该互相连接:

使用连接检查后,可以阻止这类连接,给用户即时反馈,并避免很多基础错误。
# 如何工作
每个连接都可以关联一个“连接检查”,其值是“可为空的字符串数组”。
两个连接可连接,需同时满足:
- 连接类型兼容(例如输出连接到值输入)。
- 两者连接检查中至少有一个相同字符串。
例如下面两组检查可连接,因为都包含 'apple':
['apple', 'ball', 'cat']
['apple', 'bear', 'caterpillar']
而下面两组不可连接,因为没有交集:
['apple', 'ball', 'cat']
['ape', 'bear', 'caterpillar']
还有一个特殊情况:如果任意一方为 null,则两者也可连接。
这可以表达“可连接任意类型”:
null
['ape', 'bear', 'caterpillar']
重要
连接检查里的字符串本身没有内置语义。
例如写 'Number' 并不代表它一定是数字,只是用于匹配同名字符串。
重要
块类型字符串(例如 'math_number')与连接检查字符串是两套独立体系。
把块类型写进连接检查,不会让该类型的块自动可连接。
# 示例
更多使用方式可参考连接检查实践手册。
# 设置检查
默认所有连接的连接检查都是 null,即“可连接任意内容”。
你需要手动为连接设置检查值。
设置方式取决于你使用的是 JSON 块定义还是 JavaScript 块定义。
# JSON
对顶层连接,直接在连接属性上设置检查。
值可以是 null、字符串(单项检查)或字符串数组。
{
'type': 'custom_value_block',
'output': 'a connection check entry',
},
{
'type': 'custom_statement_block',
'nextStatement': null, // null 检查
'previousStatement': ['four', 'connection', 'check', 'entries']
}
对输入连接,在输入定义的 check 属性中设置。
如果没有 check 属性,则视为 null。
值可为字符串或字符串数组。
{
'type': 'custom_block',
'message0': '%1 %2',
'args0': [
{
'type': 'input_value',
'check': 'a connection check entry' // 接受 custom_value_block
},
{
'type': 'input_statement',
'check': ['two', 'entries'] // 接受 custom_statement_block
}
]
}
# JavaScript
对顶层连接,可把检查值直接传给定义连接的方法。
不传值时默认为 null。
值可为字符串(单项检查)或字符串数组。
Blockly.Blocks['custom_value_block'] = {
init: function() {
this.setOutput(true, 'a connection check entry');
}
};
Blockly.Blocks['custom_statement_block'] = {
init: function() {
this.setNextStatement(true); // null 检查
this.setPreviousStatement(true, ['four', 'connection', 'check', 'entries']);
}
};
对输入连接,先创建输入,再调用 setCheck。
如果不调用 setCheck,则视为 null。
值可为字符串或字符串数组。
Blockly.Blocks['custom_block'] = {
init: function() {
this.appendValueInput('NAME')
.setCheck('a connection check entry'); // 接受 custom_value_block
this.appendStatementInput('NAME')
.setCheck(['two', 'entries']); // 接受 custom_statement_block
}
};
# 内置检查字符串
内置块常用的连接检查值有:'Array'、'Boolean'、'Colour'、'Number'、'String'。
如果你希望自定义块与内置块互通,可以使用这些值建立兼容。
# 局限性
这个系统已足够覆盖很多场景,但仍有一些局限。
# 限制更大上下文
连接检查默认只看“当前要连接的这两个连接”,不看更大上下文。
例如它无法直接表达“break 块只能在循环块内部”。
可通过事件系统监听块移动事件,再主动检查并断开非法位置:
Blockly.Blocks['custom_block'] = {
init: function() { },
onchange: function(e) {
if (this.workspace.isDragging()) return;
if (e.type !== Blockly.Events.BlockMove) return;
if (!this.getSurroundLoop()) this.outputConnection.disconnect();
},
loopTypes: new Set(), // 合法的块类型(不是连接检查字符串)。
getSurroundLoop: function() {
let block = this.getSurroundParent();
while (block) {
if (this.loopTypes.has(block.type)) return block;
block = block.getSurroundParent();
}
return null;
},
};
# 泛型类型
这个系统本身也不直接支持“泛型”。
例如很难直接做一个“输入什么类型就输出什么类型”的恒等块。
可以部分通过事件系统在块移动时动态改写输出连接检查来实现:
Blockly.Blocks['custom_block'] = {
init: function() { },
onchange: function(e) {
if (e.type !== Blockly.Events.BlockMove) return;
this.setOutput(
true, this.getInputTargetBlock()?.outputConnection.getCheck());
}
};
但如果连接上的块本身也是泛型块,这种方法依然不能完全正确处理。
# 连接检查器
如果默认连接检查系统不满足需求,你可以创建自定义连接检查器,改写连接检查的比较方式。
例如你想支持更复杂的类型系统,或处理上述局限性,就可以走自定义连接检查器方案。