ByRef и ByVal в VBScript - PullRequest
       50

ByRef и ByVal в VBScript

31 голосов
/ 08 октября 2009

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

Ответы [ 6 ]

40 голосов
/ 08 октября 2009

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

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

Смущает, но так оно и работает.

19 голосов
/ 08 октября 2009

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

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

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

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

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

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

7 голосов
/ 08 октября 2009

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

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

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

Выражение: -

x = func(y)

Заявление: -

func y

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

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

 x = (y)

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

 func(y)

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

3 голосов
/ 14 августа 2013
IncrementByRef Num

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

IncrementByRef (47 + 3)

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

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

Законны ли все в бейсике, как в фортране. Общеизвестно, что в одном раннем FORTRAN передача по ref позволяла вам изменять значение выражений вроде

5

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

0 голосов
/ 12 декабря 2014

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

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

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

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

myFunction "This is a reference"

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

myValue = myFunction ("This is a reference")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...