web-dev-qa-db-ja.com

VBScriptのByRefおよびByVal

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に渡されるようにする方法はありますか?

31
Jérôme

Eric Lippert VBScriptでの括弧の使用に関する素晴らしい記事があります: 「括弧を使用できない」とはどういう意味ですか? この例は、彼が言及している点の1つを示しています。括弧内のByRef引数は、ByValとして渡します。

要するに、VBScriptサブルーチン呼び出しの括弧は、引数リストの周りだけでなく、個々の引数の周りにも置くことができます(その場合、それらは強制的にByValになります)。また、VBScriptでは、Callキーワードが使用されている場合にのみ、引数リストが括弧で囲まれていると想定しています。 IncrementByRef(Num)呼び出しはCallキーワードを使用しないため、VBScriptは括弧をサブルーチン引数に適用されるものとして扱い、ByValではなくByRefを渡します。

混乱しますが、それはそれが機能する方法です。

40
Helen

これはバグではなく機能です。
http://msdn.Microsoft.com/en-us/library/ee478101.aspx

引数が括弧で囲まれ、括弧が引数リストに適用されない場合、ByRefパラメーターは値によって渡されます。

次のいずれかに該当する場合、括弧は引数リストに適用されます。

  • ステートメントは、戻り値への割り当てを持つ関数呼び出しです。

  • ステートメントはCallキーワードを使用します。 (Callキーワードは、オプションでサブルーチン呼び出し、または割り当てのない関数呼び出しに使用できます。)

したがって、Callキーワードを使用するか、値を返すようにしてください。

19
Joel Coehoorn

明確にするために。括弧には3つの異なる目的があります。

  1. プロシージャの定義または呼び出し時に引数リストを囲むために使用されます
  2. 配列のインデクサーを示すため。
  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のマークが付けられている場合と同じ動作になります。

7
AnthonyWJones
IncrementByRef Num

numへの参照を使用した呼び出しと増分

IncrementByRef (47 + 3)

「50」への参照を使用した呼び出しと増分。これは出口で破棄されます。

IncrementByRef (Num)
IncrementByRef (Num + 18)*5
IncrementByRef Cint("32")

FORTRANと同様に、すべてBASICで合法です。悪名高いことに、初期のFORTRANでは、refを渡すことで次のような式の値を変更できました

5

これは、非常に小さく、初期のFORTRANコンパイラだけがそのような動作をしていたことを十分に混乱させました。

3
david

質問に従うかどうかはわかりませんが、共有します。

関数のサブルーチンがあるかどうかに関係なく、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