Страницы: 1
RSS
Изменение переменных в функции
 
Как разрешить изменение передаваемого в функцию параметра в ее теле?
 
А файл-пример слабо?
 
Не понял? Зачем? Я то и пытаюсь написать макрос, но неоходимо чтобы одна из моих функций в себе изменяла несколько значений, а не только возвращаемое значение.
 
человек, будь Человеком - выложи хоть пару строк кода. Ведь неясно что и где должна в себе изменять функция. Я могу представить себе, что нужно внутри функции изменять какую-то константу (f, например). Тогда в чем вопроос? f=f+1. Или по условию If a > 0 Then f=f+1. Вот и изменили константу внутри самой функции.
 
Объявите переменную как Public, она станет доступна всем процедурам и функциям.  
Или объявите функцию как свой тип данных, Например:  
Type Rec  
 St As Integer  
 Bl As Integer  
 Val(1 To 24) As Double  
End Type  
 
Function r (St As Integer, Bl As Integer) As Rec  
 Dim i As Integer  
 r.St = St  
 r.Bl = Bl  
 For i = LBound(r.Val) To UBound(r.Val)  
   r.Val(i) = 0  
 Next  
End Function
 
{quote}{login=человек}{date=24.04.2008 11:36}{thema=Изменение переменных в функции}{post}Как разрешить изменение передаваемого в функцию параметра в ее теле?{/post}{/quote}  
---  
Нормальный человеческий вопрос.  
 
По умолчанию все параметры функции передаются как ссылки, т.е. ByRef. Это означает, что если внутри функций они будут изменены, то автоматически они будут изменены и снаружи, т.е. там где вызывалась функции с передачей этих параметров.  
 
Например:  
 
Function x(a) ' или Function x(ByRef a)  
a = a + 1  
End Function  
 
' Тогда  
Sub y()  
b = 1  
Call x(b)  
MsgBox b  ' покажет 2  
End Sub  
 
Если же перед параметром в функции поставить ByVal, то в эту функцию передается копия параметра.  
 
Function x(ByVal a)  
a = a + 1  
End Function  
 
' Тогда  
Sub y()  
b = 1  
Call x(b)  
MsgBox b  ' покажет 1  
End Sub  
 
---  
ZVI
 
ZVI, я с этими ByRef и ByVal до конца не понял. Бывает пишу вызов и вба от меня ничего не требует, т.е. берет по умолчанию. Но  бывает и ругается, что необходимо указать явно ByRef или ByVal. Никак не могу понять в каких случаях это происходит.  
ЗЫ. А вопрос темы я тоже не так понял. :)
 
{quote}{login=Лузер™}{date=25.04.2008 09:12}{thema=}{post}ZVI, я с этими ByRef и ByVal до конца не понял. Бывает пишу вызов и вба от меня ничего не требует, т.е. берет по умолчанию. Но  бывает и ругается, что необходимо указать явно ByRef или ByVal. Никак не могу понять в каких случаях это происходит.  
ЗЫ. А вопрос темы я тоже не так понял. :){/post}{/quote}  
---  
Воспользуюсь вопросом и выходным для длинной писанины.  
 
1. Декларация ByRef означает передачу ссылки на переменную.    
Отсутствие деклараций также означает ByRef.    
На языках С и С++ такая ссылка называется указателем.  
По сути, передается лишь 4-байтный long-адрес, по которому в памяти размещена переменная.  
Передача указателя - очень быстрая операция. Это и понятно: сама переменная может быть многобайтной сложной структурой, массивом, числом double, строкой  и т.п., занимающей относительно много места в памяти. Гораздо  быстрее указать на начальный long-адрес (4 байта), по которому можно достучаться до этой переменной, чем создавать копию такой многобайтной переменной (копию создает ByVal).    
Иногда, обычно при обработке больших массивов данных, приходится учитывать экономию такого времени.  
Но все, что сотворит функция с переданной ей ByRef переменной, автоматически отразится и на оригинале, так как это и есть оригинал (одна и та же область памяти) – см. 1-й пример в посте выше.  
 
2. Декларация ByVal означает создание и работу с временной копией переданной в функции переменной.    
С одной стороны, это добавляет время на создание копии, но, с другой стороны, не нужно беспокоиться о том, что переданная в функцию переменная изменит и оригинальную переменную – см. 2-й пример в посте выше.  
 
3.  Конфликт  деклараций параметров процедур/функций.  
 
== 3.1 Ошибка может возникнуть, например, при таком вызове:  
 
' Вызывающая процедура/функция - передаем ссылку  
Sub X()  
Dim a  
Call Y(ByVal a) ' неправильная передача копии  
' Ошибка: "Type mismatch"  
End Sub  
 
' Вызываемая функция  
Function Y(b)  
'...  
End Function  
 
== 3.2 Правильно так:  
 
' Вызывающая процедура/функция - передаем ссылку  
Sub X()  
Dim a  
'...  
Call Y(a) 'передача ссылки (указателя)  
'...  
End Sub  
 
' Вызываемая функция – создает копию переменной  
Function Y(ByVal b)  
'...  
End Function  
 
== 3.3 Конфликт передаваемых типов переменных  
‘ Наиболее типичная ошибка, сообщение VBE мало о чем говорит.  
 
' Вызывающая процедура/функция  
Sub X()  
'...  
Call Y(a)  ' тип переменной 'a' Variant, а нужен double, т.к./Y(b As Double)  
' Ошибка: "ByRef argument type mismatch"  
'...  
End Sub  
 
' Вызываемая функция  
Function Y(b As Double)  
'...  
End Function  
 
В процедуре Sub X() нужно было определить:  
Dim a As Double  
и никак иначе.  
 
4. Как избежать конфликтов.  
При вызове функций не использовать декларации ByVal и ByRef для передаваемых переменных.  
Использовать эти декларации в объявлении параметров функции (в заголовке функции).  
Следить за совпадением типов передаваемых в функцию переменных и декларируемых типов параметров этой функции.  
Не ругаться, что так много пришлось прочитать здесь ради таких элементарных советов :)  
 
---  
ZVI
 
ZVI, оргомное спасибо за ликбез!  
Читать было ничуть не напряжно.  
У меня возникали ошибки по п. 3.3  
Теперь, надеюсь, не будут
 
спасибо, ZVI, именно это я и имел в виду. Но вот только я думал что в ВБА как в Делфи по умолчанию по значению передается, а по ссылке дописывать што-нть надо. Просто ситуация какая возникла, я передаю в свою процедуру массив элементов типа Workbook, там его пытаюсь перебрать циклом For Each, а ВБА пишет, мол для использования этого цикла массив должен быть изменяемым. Я и решил, что он как const передался. А если вы говорите, что он по умолчанию изменяемый, то свою ошибку я так и не пойму... Я правда без него уже обошелся, но вопрос остался
 
{quote}{login=человек}{date=28.04.2008 06:40}{thema=}{post}спасибо, ZVI, именно это я и имел в виду. Но вот только я думал что в ВБА как в Делфи по умолчанию по значению передается, а по ссылке дописывать што-нть надо. Просто ситуация какая возникла, я передаю в свою процедуру массив элементов типа Workbook, там его пытаюсь перебрать циклом For Each, а ВБА пишет, мол для использования этого цикла массив должен быть изменяемым. Я и решил, что он как const передался. А если вы говорите, что он по умолчанию изменяемый, то свою ошибку я так и не пойму... Я правда без него уже обошелся, но вопрос остался{/post}{/quote}  
---  
Не видя кода, трудно понять конкретную причину  проблемы. Нужно, наверное, учитывать, что Workbooks - это не массив, а коллекция. Но с ней For Each Nixt тоже работает:  
 
Sub ВсеКнигиВсеЛисты()  
For Each Wb In Workbooks  
s = s & "Книга:" & Wb.Name & vbLf  
For Each Sh In Wb.Sheets  
s = s & "Лист: " & Sh.Name & vbLf  
Next  
Next  
MsgBox s  
End Sub  
 
Если есть желание разобраться с Вашим случаем, приложите фрагмент кода или файл - посмотрим.  
---  
ZVI
Страницы: 1
Читают тему
Наверх