VBScriptで奇妙な問題に直面しています。パラメータを参照渡しするプロシージャを記述する場合、このプロシージャを呼び出す方法によって、パラメータの受け渡し方法が変わります。
次に例を示します。
Sub IncrementByRef(ByRef Value)
Value = Value + 1
End Sub
Sub IncrementByVal(ByVal Value)
Value = Value + 1
End Sub
Dim Num
Num = 10
WScript.Echo "Num : " & Num
IncrementByRef(Num) : WScript.Echo "IncrementByRef(Num) : " & Num
IncrementByRef Num : WScript.Echo "IncrementByRef Num : " & Num
IncrementByVal(Num) : WScript.Echo "IncrementByVal(Num) : " & Num
IncrementByVal Num : WScript.Echo "IncrementByVal Num : " & Num
そしてここに出力があります:
U:\>cscript //nologo byrefbyval.vbs
Num : 10
IncrementByRef(Num) : 10
IncrementByRef Num : 11
IncrementByVal(Num) : 11
IncrementByVal Num : 11
U:\>
パラメータを指定すると、ByValが渡され、プロシージャの呼び出し方法に関係なく、期待どおりに機能します。しかし、パラメーターを指定するときにByRefを渡すと、プロシージャを次のように呼び出すと、期待どおりに動作します。
IncrementByRef Num
しかし、この方法ではありません:
IncrementByRef(Num)
これは私には奇妙なようです。プロシージャがどのように呼び出されても、パラメータが確実にByRefに渡されるようにする方法はありますか?
Eric Lippert VBScriptでの括弧の使用に関する素晴らしい記事があります: 「括弧を使用できない」とはどういう意味ですか? この例は、彼が言及している点の1つを示しています。括弧内のByRef
引数は、ByVal
として渡します。
要するに、VBScriptサブルーチン呼び出しの括弧は、引数リストの周りだけでなく、個々の引数の周りにも置くことができます(その場合、それらは強制的にByVal
になります)。また、VBScriptでは、Call
キーワードが使用されている場合にのみ、引数リストが括弧で囲まれていると想定しています。 IncrementByRef(Num)
呼び出しはCall
キーワードを使用しないため、VBScriptは括弧をサブルーチン引数に適用されるものとして扱い、ByVal
ではなくByRef
を渡します。
混乱しますが、それはそれが機能する方法です。
これはバグではなく機能です。
http://msdn.Microsoft.com/en-us/library/ee478101.aspx
引数が括弧で囲まれ、括弧が引数リストに適用されない場合、ByRefパラメーターは値によって渡されます。
次のいずれかに該当する場合、括弧は引数リストに適用されます。
ステートメントは、戻り値への割り当てを持つ関数呼び出しです。
ステートメントはCallキーワードを使用します。 (Callキーワードは、オプションでサブルーチン呼び出し、または割り当てのない関数呼び出しに使用できます。)
したがって、Callキーワードを使用するか、値を返すようにしてください。
明確にするために。括弧には3つの異なる目的があります。
プロシージャをステートメントまたは式として呼び出す方法は2つあります。
式:-
x = func(y)
ステートメント:-
func y
Call
キーワードは、式の一部であるかのようにプロシージャを呼び出すため、引数リストは括弧内に含まれている必要があります。
上記では、y
自体が非常に単純な表現を表しています。この時点では、y + z
を使用することもできました。実際、この時点では、括弧演算子を使用する式を含め、有効な式を使用できます。例えば:-
x = (y)
有効な式です。したがって、あなたが行うとき:-
func(y)
VBScriptは、式(y)
の結果が渡されるfunc
の呼び出しを認識します。これで、func
がこのパラメーターをByRef
として定義した場合でも、y
がパラメーターとして実際に渡されなかったため、y
の値は影響を受けません。渡されたのは、一時的な場所に格納される(y)
という式の結果です。この一時ストアがfunc
によって変更されても、後で破棄されるため、パラメーターにByVal
のマークが付けられている場合と同じ動作になります。
IncrementByRef Num
numへの参照を使用した呼び出しと増分
IncrementByRef (47 + 3)
「50」への参照を使用した呼び出しと増分。これは出口で破棄されます。
IncrementByRef (Num)
IncrementByRef (Num + 18)*5
IncrementByRef Cint("32")
FORTRANと同様に、すべてBASICで合法です。悪名高いことに、初期のFORTRANでは、refを渡すことで次のような式の値を変更できました
5
これは、非常に小さく、初期のFORTRANコンパイラだけがそのような動作をしていたことを十分に混乱させました。
質問に従うかどうかはわかりませんが、共有します。
関数のサブルーチンがあるかどうかに関係なく、ByVal
またはByRef
で渡されるパラメーターを定義すると、パラメーターの値がサブルーチンまたは関数呼び出しの外側でその値を保持するかどうかが決まります。次の機能がある場合:
Function ThisFByRef(ByRef MyValue)
End Function
関数(またはサブルーチン)内のパラメーターに対して行うことはすべて、関数が完了した後もその値を保持します。 ByVal
およびByRef
は、サブルーチンまたは関数のスコープに関連付けられています。 ByVal
が渡されるパラメーターは、呼び出されたサブルーチンまたは関数内で発生した変更を保持しません。あるいは、ByRef
が渡されたパラメーターは、サブルーチンまたは関数内で変更された値を保持します。値を返すことは、関数でのみ行うことができ、サブルーチンでは実行できません。パラメータがByRef
で渡され、関数内で変更されない限り、渡されたパラメータの値には影響しません。例えば:
Dim x
Dim ThisFValue
x = 0
ThisFValue = ThisFByRef(x)
At this point the values would be:
ThisFValue = 2
x = 1
x = 0
ThisFValue = ThisFByVal(x)
At this point the values would be:
ThisFValue = 2
x = 0
Function ThisFByRef(ByRef x)
x = x + 1
ThisFByRef = x + 1
End Function
Function ThisFByVal(ByVal x)
x = x + 1
ThisFByVal = x + 1
End Function