2012-03-20 10 views
3

コール時に評価されるTclプロシージャにどのようにデフォルトの引数を提供しますか?Tcl:呼び出し時にデフォルトのargsを埋めるためのステートメントを評価する方法

は、ここで私が試したものの一例です:

> tclsh 
% proc test { {def [expr 4 + 3]} } { puts $def } 
too many fields in argument specifier "def [expr 4 + 3]" 
% proc test { {def {[expr 4 + 3]}} } {puts $def} 
% test 
[expr 4 + 3] 
% test 5 
5 
% proc test { {def {[expr 4 + 3]}} } {puts [$def]} 
% test 
invalid command name "[expr 4 + 3]" 
% proc test { {def {[expr 4 + 3]}} } {puts [eval $def]} 
% test 
invalid command name "7" 

例は、単にコードを簡素化することです。もちろん、この単純な例では、{def 7}を使ってprocのデフォルト値を設定するだけです。

しかし、目標は、testプロシージャが呼び出されているときはいつでも良いデフォルト値を提供するより複雑な関数を呼び出すことができるようにすることです。したがって、デフォルトはさまざまです。

% proc test { {def {}} } { if {$def == {}} { set def [expr 4 + 3] } ; puts $def } 
% test 
7 
% test 5 
5 

は、しかし、私は十分にこのエレガントではない考えてみます:

私の現在のソリューションは、空の文字列をデフォルトとそれをチェックすることですヘッダーで:そこは、彼らが所属する宣言を置くための方法であるべきです。

また、空の文字列は、デフォルトの呼び出しで置き換えられない呼び出し元によって与えられる完全に細かい値である可能性があります。

もう1つの回避策は、パラメータとしてargsを使用して、それを検査することです。しかし、それはあまり明示的な宣言スタイルを提供しません。

私は宣言的なprocヘッダーにevalをどのように組み込むことができますか?

(私があるため、市販のツール環境での使用をアップグレードする方法はありませんとTcl8.4に思います。しかし、このサイトのために、私はまた、より近代的なTCLバージョンの答えを奨励するだろう)

+0

8のためのソリューションを。4は、それ以降のバージョンと同様に有効です。過去20年近くのこの特定の分野に大きな変更はありませんでした(ただし、ベストプラクティスはその間に変更されました)。 –

+1

最近、このトピックについていくつか質問がありました。この質問を参照してください:http://stackoverflow.com/q/9736524/7552 –

+0

@Donald:1週間前にtcl 8.5での展開について議論しましたので、宣言的な構文がさらに変更されている可能性を疑っていました。 。 – cfi

答えて

2

何(あなたの試行からわずかに異なっている)この1について:あなたが唯一のこれまでの番号を渡すことでしょうを知っ場合

% proc test {{def {[expr 4+3]}}} {eval puts "$def"} 
% test 
7 
% test 5 
5 
+0

シンプルでエレガントな作品。それは私が明らかに考えなかった順列でした。感謝します!答えとしてチェックする前に、他の方法があるかどうかを確認するために1日待つでしょう。 – cfi

+0

私のもっと複雑な実際のケースでは、今度は 'eval set def"を引数として(procの最初の文として)$ def "' – cfi

2

は、あなたがこれを行うことができます。

proc test {{def {4+3}}} { 
    puts [expr $def] 
} 

一般的な引数を扱っている場合、これは安全でないです。 (誰かが "[exit]"に合格すると、あなたは気づくでしょう!)を安全に処理するは、より精巧な処理が必要です。あなたは、空の文字列のようなセンチネル値を使用することができた場合:

proc test {{def ""}} { 
    if {[string equal $def ""]} {set def [expr 4+3]} 
    puts $def 
} 

あなたは可能そのようなセンチネルを持っていない場合、あなたは特別なargsを使用して自分自身やあなたがの長さを見ているすべての作業を行うためにどちらか持っていますリストはinfo level 0によって返されます。

お客様ラップprocは、このコードをすべて簡単にするために使用します。

proc xproc {name arguments body} { 
    for {set n [llength $arguments]} {[incr n -1] >= 0} {} { 
     if {[llength [lindex $arguments $n]] > 1} { 
      foreach {v def} [lindex $arguments $n] break 
      set body "if {\[llength \[info level 0\]\] <= $n+1} {set $v \[expr $def\]};$body" 
     } 
    } 
    proc $name $arguments $body 
} 

その後、あなたはこれを書くことができます:

xproc test {{def {4+3}}} { 
    puts $def 
} 
+0

を使う前に明示的な評価を行います。ええ、私は任意の議論に固執しています。優れた点、セキュリティ上の問題を引き起こす。私は安全な環境にあるので、人々がツールのデータベースを誤って破棄したり破損したりするのを防ぐための追加機能になります – cfi

+0

@cfi:毎回そのような '[expr]'の実行を避ける方が良いそれは毎回式の再コンパイルを強制し、それは(比較的)遅いからです。 –

+0

あなたが聞く前に、 'proc'自体はデフォルトの値(つまり定数)しか使用できません。プロシージャの定義時に値を計算できますが、その時点では定数です(プロシージャを変更するたびにプロシージャを再定義しないかぎり、パフォーマンスに重大なコードでは使用されていないトリックがあります)。これは、Tclの値が意味的に不変であるという事実に由来します。彼らは変わらない。これは非常に微妙な点です。 –

関連する問題