Подтвердить что ты не робот

ByRef и ByVal в VBScript

В 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, независимо от того, как вызывается процедура?

4b9b3361

Ответ 1

Эрик Липперт имеет отличную статью об использовании круглых скобок в VBScript: Что значит "не может использовать круглые скобки?" Ваш пример иллюстрирует один из пунктов, которые он упоминает, а именно: включение аргумента ByRef в круглые скобки передает его как ByVal.

Короче говоря, круглые скобки в вызовах подпрограмм VBScript могут быть помещены не только вокруг списка аргументов, но и вокруг отдельных аргументов (в этом случае они принудительно ByVal). И VBScript ожидает, что список аргументов будет заключен в круглые скобки, если используется ключевое слово Call. Поскольку вызов IncrementByRef(Num) не использует ключевое слово Call, VBScript рассматривает круглые скобки как применяемые к аргументу подпрограммы и таким образом передает его ByVal вместо ByRef.

Сбивает с толку, но так, как это работает.

Ответ 2

Это особенность, а не ошибка:
http://msdn.microsoft.com/en-us/library/ee478101.aspx

Параметр ByRef передается по значению, если аргумент заключен в круглые скобки, а круглые скобки не применяются к списку аргументов.

Скобки применяются к списку аргументов, если выполняется одно из следующих условий:

  • Оператор представляет собой вызов функции, который имеет присваивание возвращаемому значению.

  • В заявлении используется ключевое слово Call. (Ключевое слово Call может быть дополнительно использовано для вызова подпрограммы или для вызова функции без назначения.)

Поэтому попробуйте использовать ключевое слово Call или вернуть его значение.

Ответ 3

Быть ясным. Скобки имеют три разных цели.

  • Используется для включения списка аргументов при определении или вызове процедуры
  • Для указания индексатора на массив.
  • Как оператор в выражении.

Существует два способа вызова процедуры либо в виде инструкции, либо как выражение.

Выражение -

x = func(y)

Заявление: -

func y

Обратите внимание, что ключевое слово Call вызывает процедуру, как если бы оно было частью выражения, поэтому список аргументов должен содержаться в скобках.

В вышесказанном, что y сам представляет собой очень простой отступ. Мы могли бы использовать y + z на этом этапе. На самом деле мы можем использовать любое допустимое выражение в этой точке, включая тот, который использует оператор круглых скобок. Например: -

 x = (y)

является допустимым выражением. Следовательно, когда вы делаете: -

 func(y)

VBScript видит вызов func, которому передается результат выражения (y). Теперь, даже если func определяет этот параметр как ByRef, значение в y не будет затронуто, потому что y фактически не передается как параметр. То, что было принято, было результатом выражения (y), которое будет храниться где-то временным. Даже если это временное хранилище изменено на func, оно будет отброшено впоследствии и, следовательно, будет иметь такое же поведение, если бы этот параметр был отмечен ByVal.

Ответ 4

IncrementByRef Num

вызовы и приращения с использованием ссылки на Num

IncrementByRef (47 + 3)

вызовы и приращения с использованием ссылки на "50". Отбрасывается при выходе.

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

Все юридические лица на Бейсике, как и в FORTRAN. Известно, что в одном раннем FORTRAN, проходящем через ref, вы могли изменить значение выражений типа

5

Это было довольно запутанно, что только очень маленькие ранние компиляторы FORTRAN имели такое поведение.

Ответ 5

Я не уверен, что буду отвечать на вопрос или ответы, но я поделюсь этим.

Независимо от того, есть ли у вас подпрограмма функции, определение параметров, переданных в 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

Ответ 6

Это просто. Когда вы создаете функцию или sub, и вы можете вызвать их следующим образом:

Без возвращаемого значения:

myFunction "This is a reference"

Для возвращаемого значения:

myValue = myFunction ("This is a reference")