2013-07-02 9 views
0

大家好,我需要一些關於tcl數組的幫助。我在TCL的東西兩個程序象下面這樣:在tcl中創建和添加現有陣列

proc A {} { 
     set lst_A [list]; 
     if {true} { 
     lappend lst_A [::B $file1]; 
     } else { 
     foreach id $allId { 
      lappend lst_A [::B $id]; 
     } 
     } 
     return $lst_A; 
    } 

    proc B {fileID} { 
     set fileName [::getFileName $fileID]; # getFileName returns filename from fileid 
     set tcName "[set ItemName]_[set ItemId]"; 
     array set tcArrayName {$fileName $tcSpec}; 
     return $tcArrayName; 
    } 

現在我想創建一個數組,這將是一個鍵值對,其中關鍵的是某種文件ID和值與該ID相關聯的一些名字。現在事情是在proc中如果條件爲真我只想創建一個具有一個鍵值對的數組,然後將該數組附加到lst_A,在這種情況下,它只包含一個項目,即數組返回。但是,如果條件是錯誤的,比我循環通過一些ID和每個ID我調用PROC B和創建數組,然後將其附加到lst_A,在這種情況下,將包含多個鍵值成對數組。

所以我寫了上述兩個程序,並在閱讀了關於tcl教程中的數組之後創建了數組。但不知道這是否是正確的方式或最優化的方式。

我的最終目標是創建一個lst_A,或者我會說應該是一個數組,如果條件爲真,它將包含只有一個鍵值對,否則將是一個具有多個鍵值對的數組。由於我在proc B中創建數組,我只能想到將proc B中的鍵值對作爲數組返回,然後將該數組附加到列表中,即proc A中的lst_A。

任何建議?

回答

5

你在這裏混淆了數組與列表。

在tcl中,您不能將數組傳遞或從函數返回。另外,tcl使用術語「數組」來表示C++調用「映射」或Perl和Ruby調用「哈希」或Javascript調用「對象」的內容。這個術語來源於這樣一個事實,即所有這些東西在計算機科學中統稱爲「關聯陣列」。所以tcl中的「數組」是鍵值對,而不是數據序列。

數組通常不會退化爲值(或經驗豐富的tcl程序員稱爲「字符串」)。因此這樣的:

array set tcArrayName {$fileName $tcSpec}; 
return $tcArrayName; 

生成語法錯誤:

can't read "tcArrayName": variable is array 

實際上,你可以變質的數組的內容到一個值,你就可以回來。但是你必須通過[array get]命令手動:

return [array get tcArrayName] 

上面的命令將返回tcArrayName陣列的內容在兩個元素的列表的形式:

"$fileName $tcSpec" 

這也恰好是一個字符串。這就是實際的字符串:字符'$'後面跟着字符'f','i','l','e','N','a','m','e'等等。文件名和連接的項目名稱和項目標識。文字字符串「$ fileName $ tcSpec」。

那是因爲你使用了{}分組在這行代碼:

array set tcArrayName {$fileName $tcSpec} 

在TCL,{xxx}的工作方式'xxx'確實在Perl。基本上它是一個不被替換的文字字符串。如果你想TCL做$替代,那麼你需要使用""分組:

array set tcArrayName "$fileName $tcSpec" 

但這是脆弱的,因爲如果fileName包含空格,那麼它會破壞代碼。更健壯的方式來做到這一點是:

array set tcArrayName [list $fileName $tcSpec] 

但在這種情況下使用array是有點多餘,因爲你正在做的是有一個鍵值列表(也稱爲dict更初始化它現代版本的tcl.BTW,你使用的是什麼版本的tcl),然後立即丟棄它,並將它的內容作爲鍵值列表返回。

爲什麼不直接返回鍵值列表:

proc B {fileID} { 
    set fileName [::getFileName $fileID]; # getFileName returns filename from fileid 
    set tcName "[set ItemName]_[set ItemId]" 
    return [list $fileName $tcSpec] 
} 

但我們仍然不明確。如果您嘗試執行B你會看到這樣的錯誤:

can't read "ItemName": no such variable 

這是因爲TCL默認不導入全局變量到功能。因此,B中不存在變量ItemNameItemId。您可能需要通過global命令明確導入:

proc B {fileID} { 
    global ItemName 
    global ItemId 

    # ... 
} 

或使用完全限定的變量名通過全局命名空間訪問它:

set tcName "[set ::ItemName]_[set ::ItemId]" 

所以B應該是這樣的:

proc B {fileID} { 
    set fileName [::getFileName $fileID]; # getFileName returns filename from fileid 
    set tcName "[set ::ItemName]_[set ::ItemId]" 
    return [list $fileName $tcSpec] 
} 

這就是B照顧但A也有一些問題:

can't read "file1": no such variable 

我們需要稍作修改,以訪問變量file1

proc A {} { 
    set lst_A [list]; 
    if {true} { ;# assuming that there will be a valid condition here 
    lappend lst_A [::B $::file1]; 
    } else { 
    foreach id $allId { 
     lappend lst_A [::B $id]; 
    } 
    } 
    return $lst_A; 
} 

像您期望這應該工作。

如果您希望在使用鍵值列表時加快速度,那麼您應該真正閱讀dicts。因爲,字典不會影響上面給出的代碼,但它確實會影響調用A的代碼。如果您打算使用dicts,則可以用dict append替換上面的lappend調用。但舊版本的tcl沒有字典。

+0

只是一個建議:如果你使用8.6,那麼你可以寫它爲'if {1} {return [list [B $ :: file1]]} else else {return [lmap id $ :: allId {B $ id }]}}' –

+0

是的,但如果你有8.6代替使用'dict append'而不是lmap的foreach會更好,因爲它避免了字典列表閃爍。 – slebetman

+0

感謝您澄清上述問題。儘管我找到了解決我的實際問題的不同方法,但您的答案是使用數組的一個很好的解釋。再次感謝Slebetman。 :) –