2017-10-18 50 views
1

以下是用於recursively walk a source file's abstract syntax tree (AST)的兩個Typescript函數。我已經設法識別導致我的程序只訪問部分樹的問題,但我不明白爲什麼解決方案有效。遞歸函數中的Typescript break與return行爲

walkTree1函數是遍歷整個樹的有效解決方案。 walkTree2函數只訪問樹的一部分。這兩個功能只有一行不同(標有註釋),顯然return的行爲與此有關,但我沒有在網上找到任何有用的東西。

function walkTree1(firstNode: ts.SourceFile, visitor: (node: ts.Node) => void): void { 
    visitInterfacesRecursive(firstNode); 

    function visitInterfacesRecursive(node: ts.Node): void { 
    switch (node.kind) { 
     case ts.SyntaxKind.InterfaceDeclaration: 
     visitor(node); break; // correct 
     default: 
     ts.forEachChild(node, visitInterfacesRecursive); 
    } 
    } 
} 

function walkTree2(firstNode: ts.SourceFile, visitor: (node: ts.Node) => void): void { 
    visitInterfacesRecursive(firstNode); 

    function visitInterfacesRecursive(node: ts.Node): void { 
    switch (node.kind) { 
     case ts.SyntaxKind.InterfaceDeclaration: 
     return visitor(node); // offending change 
     default: 
     ts.forEachChild(node, visitInterfacesRecursive); 
    } 
    } 
} 

終於,我被難住了。我覺得我在這裏錯過了一些明顯的東西。我已經檢查了生成的源代碼,並且在那裏似乎沒有任何意外(除了類型擦除之外沒有真正的區別)。現在我發佈原始代碼;如果有必要的話,我會在稍後回家的時候將更加可重複的東西放在一起。

其他細節:

+0

請使用Stack Snippets('[<>]'工具欄按鈕)使用** runnable ** [mcve]更新您的問題。 (這需要刪除類型註釋,但這僅僅是所有內容。) –

回答

2

這是因爲ts.forEachChild()實際上並沒有在所有情況下超過每個孩子。從鏈接source

 
// Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes 
// stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise, 
// embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns 
// a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. 

那麼既然你是返回visitor(node),它有時必須truthy。即使您宣稱visitor()void返回函數,我猜可能會發生這種情況。 (您遺漏了您使用的特定visitor(),所以我不確定)因爲您不在意visitor()的返回值,所以最好不要從visitInterfacesRecursive()返回。

希望有幫助;祝你好運!

+0

謝謝,我根本沒有想到這個行爲來自一個名爲'forEach *'(而不是'forSome *')的函數。 – apk

2

這種變化使得唯一的區別是使visitInterfacesRecursive返回結果調用visitor(node)(在walkTree2),而在walkTree1visitInterfacesRecursive可靠地返回undefined。*

不管叫什麼visitInterfacesRecursive都清楚地看着它的返回值。在walkTree1中,返回值可靠undefined。在walkTree2中,有時undefined和其他時間visitor(node)返回。看起來visitor(node)會返回undefined以外的東西(至少有時候),並且看到返回值visitInterfacesRecursive的任何內容都會將該非返回值解釋爲「停止」。


*「可靠返回undefined」 - 從技術上講,ECMAScript的規範使得不都使用return的功能和使用returnreturn undefined一之間的區別,但這種區別是不是在觀察到我們的代碼。在這三種情況下調用該函數都會得到相同的結果。

+1

@apk:不,唯一的調用不在'walkTree'中:您將'visitInterfacesRecursive'傳遞給'forEachChild'。顯然,'forEachChild'使用'visitInterfacesRecursive'的返回值。 –