連線檢查

連線檢查會限制哪些連線 (以及區塊) 可以彼此連線。

連線檢查適用於模擬類型。舉例來說,以下三個區塊並未連結任何商家,因為這些區塊代表會傳回不同類型的程式碼:

連線至正方形根區塊的空白清單區塊,且連接至大寫區塊

連線檢查可以用來防止這類封鎖限制進行連線。如此一來,使用者就能立即取得意見回饋,避免許多簡單錯誤。

運作方式

每個連線都能與「連線檢查」建立關聯,連線檢查是可為空值的字串陣列。

如果發生下列情況,可連接兩個連線:

  1. 它們是相容的「類型」 (例如,連接到輸入的輸出)。
  2. 而且連線檢查中至少有一個字串。

例如,以下兩個檢查可以連線,因為它們共用 'apple' 字串:

['apple', 'ball', 'cat']
['apple', 'bear', 'caterpillar']

不過,以下兩個檢查無法連接,因為兩者之間未共用任何字串:

['apple', 'ball', 'cat']
['ape', 'bear', 'caterpillar']

還有一個特殊情況。如果其中一個陣列是 null,則兩個連線也可以連線。這樣做可讓您定義可以連線至任何項目的連線。

null
['ape', 'bear', 'caterpillar]

設定檢查

根據預設,所有連線都有 null 連線檢查,因此可以連線至任何項目。連線檢查必須手動指派。

連線檢查指派方式會因您使用 JSON 區塊定義或 JavaScript 區塊定義而異。

JSON

對於頂層連線,您可以直接將檢查指派給定義連線的屬性。您指派的值可以是 null、字串 (也就是連線檢查中唯一的項目),或是字串陣列。

{
  'type': 'custom_block',

  'output': null,
  'nextStatement': 'a connection check entry',
  'previousStatement': ['four', 'connection', 'check', 'entries']
}

對於輸入內容,您可以將檢查指派給輸入定義的 check 屬性。如果 check 屬性不存在,系統會將檢查視為 null。您指派的值可以是字串或字串陣列。

{
  'type': 'custom_block',
  'message0': '%1 %2',

  'args0': [
    {
      'type': 'input_value',
      'check': 'a connection check entry'
    },
    {
      'type': 'input_statement',
      'check': ['four', 'connection', 'check', 'entries']
    }
  ]
}

JavaScript

如果是頂層連線,您可以將檢查直接傳遞至定義連線的方法。如未傳遞值,系統會將檢查視為 null。您傳遞的值可以是字串 (變成連線檢查中唯一的項目) 或字串陣列。

Blockly.Blocks['custom_block'] = {
  init: function() {
    this.setOutput(true); // null check
    this.setNextStatement(true, 'a connection check entry');
    this.setPreviousStatement(true, ['four', 'connection', 'check', 'entries']);
  }
}

針對輸入內容,您可以在定義輸入內容後將檢查傳送至 setCheck 方法。如未呼叫 setCheck 方法,系統會將檢查視為 null。您傳遞的值可以是字串或字串陣列。

Blockly.Blocks['custom_block'] = {
  init: function() {
    this.appendValueInput('NAME')
        .setCheck('a connection check entry');
    this.appendStatementInput('NAME')
        .setCheck(['four', 'connection', 'check', 'entries']);
  }
}

內建檢查字串

內建區塊會使用 'Array''Boolean''Colour''Number''String' 值進行連線檢查。如果您希望區塊與內建區塊互通,可以使用這些值使區塊相容。

值範例

定義輸入和輸出的連線檢查時,通常您應將檢查視為代表類型。

輸入內容的檢查應包含其接受的每個「類型」,而輸出的檢查應包含「完全」這些「傳回」的內容。

接受單一類型

在最基本的情況下,如要建立「接受」或「傳回」一種類型的區塊,您必須在連線的連線檢查中加入該類型。

接受單一類型的值區塊

接受多種類型

如要建立「接受」多種類型的區塊,您需要在輸入的連線檢查中納入所有可接受的類型。

接受多種類型的值區塊

依照慣例,如果輸出「有時」可以於多個情況下接受 (例如,如果您允許有時將數字做為字串使用),輸出的限制應更嚴格,輸入的值也應較為寬鬆。這項慣例可確保輸出不會連接不受支援的輸出。

接受任何類型

如要建立「接受」任何類型的區塊,您必須將輸入的連線檢查設為 null

接受任何類型的值區塊

傳回子類型

如要建立可「傳回」子類型的區塊,您必須在輸出的連線檢查中一併包含類型和超級類型。

值區塊,會傳回其類型及其超級類型

如果是子類型,輸出檢查可以進行多次檢查,因為區塊「一律」會「傳回」這兩種類型。

傳回參數化類型

如要建立「傳回」參數化類型的區塊,您需要在輸出的連線檢查中同時加入參數化版本和未參數化版本。

視所需的區塊語言嚴格程度而定,建議您也加入類型的變異數

值區塊會傳回參數化類型及其未經參數化的類型

和子類型一樣,在這個範例中,輸出檢查可以進行多次檢查,因為區塊「一律」會「傳回」這兩種類型。

堆疊或陳述式範例

開發人員有幾種常見的方式,可以定義先前和下一個連線的檢查項目。您通常可以想成是限制區塊的排序方式,

下一個連線應包含哪些區塊應遵循目前的區塊,先前的連線則包含目前區塊「是」。

依序保留區塊

如要建立一組按照已定義順序連線的區塊,您需要在下一次連線檢查中納入哪些區塊應遵循目前區塊,以及上次連線檢查中的目前區塊「是」。

包含強制順序的陳述式區塊

允許許多中間區塊

如要建立允許大量中間區塊的已排序區塊,您必須在中間區塊的下一個連線檢查中,納入至少一個中間區塊的連線檢查項目。這樣就能讓區塊跟其本身有更多路徑。

容許許多中間區塊的陳述式

不允許中間區塊

如要建立一組已排序的區塊,且中間區塊為選用項目,您必須加入至少一個中間區塊的先前連線檢查項目,以及在第一個區塊的下一個連線檢查中,加入最後一個區塊的上一個連線檢查項目。如此一來,第一個區塊後面會接著一個中間區塊或最後一個區塊。

允許沒有中間區塊的陳述區塊

任一或堆疊

如要建立只能從某個群組後面接續的區塊,或封鎖另一個群組中的區塊 (而非兩者),您必須執行兩項操作:

  1. 在第一個區塊的下一個連線檢查中,您需要在第一個區塊的下一個連線檢查中,納入至少一個先前連線檢查項目的項目。

  2. 您需要定義群組的下一次連線檢查,僅納入先前連線檢查中的值 (因此這些值只能後面接有相同群組的區塊)。

陳述式區塊,可能後面可以接著屬於一種或多種區塊,但不能同時是兩者

限制

這個系統相當強大,可以解決許多用途,但有一些限制。

限制更多背景資訊

這個系統本身不支援限制可連線的「更完整的背景資訊」。例如,您無法說 break 區塊只能在 loop 區塊內存在。連線檢查系統僅會將兩個連線列入考量。

如要支援這項功能,您「可以」使用事件系統監聽區塊移動事件,並檢查區塊位置是否有誤。

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(); // Your valid *block types* (not connection checks).

  getSurroundLoop: function () {
    let block = this.getSurroundParent();
    do {
      if (loopTypes.has(block.type)) return block;
      block = block.getSurroundParent();
    } while (block);
    return null;
  },
}

一般類型

這個系統本身不支援定義一般類型。例如,您無法建立「Identity」區塊,該區塊會「傳回」的任何輸入內容。

您可以藉由主動變更區塊輸出連線檢查,使其與其輸入內容相符,藉此支援這種情況。您可以使用事件系統監聽封鎖移動事件。

Blockly.Blocks['custom_block'] = {
  init: function() { }

  onchange: function(e) {
    if (e.type !== Blockly.Events.BlockMove) return;
    this.setOutput(
        true, this.getInputTargetBlock()?.outputConnection.getCheck());
  }
}

但如果連結區塊「也」一般,則無法正常運作。無法解決這個問題。

連線檢查工具

如果這個系統不適用於您的使用情境,您也可以建立自訂連線檢查工具,以變更連線檢查的比較方式。

舉例來說,如果您想要建立更進階的系統,以便處理這種系統的部分限制,可以建立自訂連線檢查工具。