2015-01-15 73 views
2

Upvar創建指向different stack frame中變量的鏈接,有時稱爲call stackdifferent scopeTCL命名空間和堆棧幀有什麼區別?

Upvar還用於爲全局(或名稱空間)變量2創建別名。但是命名空間僅由namespace eval命令創建。一個新的堆棧框架由proc命令創建。

命名空間和調用堆棧似乎是TCL naming context可以更改的兩種方式。 Upvar和Uplevel可以在名稱空間和調用堆棧上工作。

我說得對嗎?我還沒有看到調用堆棧和命名空間之間的直接比較,因此我的問題。

回答

8

不,不是。命名空間和調用框架是非常不同的概念。命名空間是可以消除同義詞歧義的名稱的層次結構。程序中可能有三個名爲foo的變量,但如果將它們放在不同的名稱空間中,它們不會發生衝突。命名空間可以用於變量名和命令名。一旦使用namespace eval創建,名稱空間的內容將始終可用,直到您致電namespace delete

調用堆棧是一系列堆棧幀。第一個堆棧幀#0始終存在。無論何時調用命令,都會創建其他堆棧框架(這主要適用於用戶定義過程的命令,「內置」命令遵循其自己的規則)。命令返回時,它們會再次被銷燬。所以,如果你命令A和A調用命令B和B調用命令C,你有一個調用堆棧看起來像這樣:

#3 : <C's variables> 
#2 : <B's variables> 
#1 : <A's variables> 
#0 : <global and namespace variables> 

每個堆棧幀是在意義上的範圍,只有變量在那裏創建或導入到它可以訪問,除非你使用upvar。其他一切都是隱藏的。在大多數編程語言中,可以從內部作用域自動訪問外部作用域的名稱,例如全局作用域。在Tcl中不是這樣。

使用upvar您可以讓命令查看自己堆棧框外的事情。 C可以使用upvar #0 foo bar爲全局變量foo創建別名(bar),或者使用upvar 1 baz qux(不帶#的註釋)爲B的堆棧幀中的變量baz創建別名(qux)。

uplevel命令可以沿着相同的行使用在另一個棧幀中執行腳本,包括全局腳本。在執行期間,腳本可以訪問堆棧幀中的所有內容,但沒有其他內容,包括從中調用的堆棧幀中的變量。

C也可以使用upvar #0 ::abc::def ghi爲名稱空間變量::abc::def創建別名,但不要這樣做,請改用namespace upvar ::abc def ghi

而不是upvar #0 foo foo你可以使用global foo導入一個全局變量。在名稱空間中定義的命令內,variable命令可以導入在同一名稱空間中定義的變量。

將#upvaruplevel分爲#0(全局幀)或1(呼叫者的幀)通常是有用的。使用其他幀編號很容易出錯,通常表示設計不佳。調用upvar 0 foo bar在同一個堆棧幀中爲變量(foo)創建一個別名(bar),這可能會非常有用。

由正在處理的事件調用的命令在調用堆棧外部使用全局級別執行。他們無法到達活動的堆棧幀並訪問駐留在其中的變量。

一個簡單的示範:

namespace eval ::abc { 
    variable def 42 

    proc xyz {} { 
     variable def 
    } 
} 

set foo 1138 

proc A {} { 
    B 
} 

proc B {} { 
    set baz 1337 
    C 
} 

proc C {} { 
    upvar #0 foo bar 
    puts $bar 
    upvar 1 baz qux 
    puts $qux 
    namespace upvar ::abc def ghi 
    puts $ghi 
} 
+0

只有一些命令推堆棧幀。每個人都知道的是程序調用和'命名空間評估'。 (還有其他幾個,特別是TclOO ...) – 2015-01-15 19:43:06

+0

謝謝,@Hoodiecrow,你填寫了一些細節。很多使用Google的人向我透露,名稱空間與調用框架不同。而且這些命名空間是可選的,也許最好在小腳本中避免(但對代碼重用有用)。調用過程被調用時也會創建調用框架。進一步澄清:在我的問題中,我是否說過任何不真實的東西? – 2015-01-16 00:10:42

+1

@ user901750:有一些有問題的陳述。你在說棧架有時被稱爲調用堆棧。這是錯誤的,但我認爲這是一個錯誤? 'proc'命令不會創建棧幀(但它創建的命令在被調用時會執行)。命名空間不會改變Tcl的命名上下文,但是'namespace eval'會(通過創建一個新的堆棧幀)。 'upvar'和'uplevel'不能用於(操作)名稱空間,但可以像處理變量的其他任何命令一樣訪問名稱空間變量。 – 2015-01-16 08:50:56