Страницы: 1
RSS
О важности обозначения типа переменной
 
Здравствуйте, недавно начал читать книжку по Excel VBA, и как новичек, не понимал зачем же нужно писать Dim ..., эксель ведь не глупый, разберется. Пока не увидил в книжке отличный пример кода.
Код
Sub TimeTest()
Dim x As Long, y As Long
Dim A As Double, B As Double, C As Double
Dim i As Long, j As Long
Dim StartTime As Date, EndTime As Date
' Sohranenie vremeni nachala vichislenij
StartTime = Timer
' Vipolnenie vichislenij
x = 0
y = 0
For i = 1 To 10000
    x = x + 1
    y = x + 1
    For j = 1 To 10000
        A = x + y + i
        B = y - x - i
        C = x / y * i
    Next j
Next i
' Poluchenie vremeni okonchanija vichislenij
    EndTime = Timer
' Otobrazhenie obshego vremeni v sekundah
    MsgBox Format(EndTime - StartTime, "0.0")
End Sub
Попробуйте запустить сначала такой код, а потом под комментарий добавить начиная со 2 строчки по 5.
Просто назначаем тип переменной, а разница обработки по времени в 3 раза. 6,5 сек по сравнению с 17.  :)

В качестве эксперемента изменил переменные на String.
Эксель думал 311 секунд.
Код
Dim x As String, y As String
Dim A As String, B As String, C As String
Мораль сей басни такова, чем больше знате, тем быстрее считаете.  :D
Изменено: alessandro2981 - 10.06.2015 19:59:27
 
Я тут статью давно уже написал...
Variable not defined или что такое Option Explicit и зачем оно нужно?

ознакомьтесь - тогда откроется еще одна тайна: почему принудительное объявление переменных лучше взять в привычку.

По поводу объявления As String: здесь играет роль не столько отсутствие объявления, сколько неверное объявление. При каждой математической операции VBE пытается преобразовать тип данных к числовому, что отнимает время. А т.к. у Вас все переменные текстовые - то и преобразование будет происходить каждый раз. Время обработки, естественно, увеличивается.
Поэтому важно не только объявить переменную, но и объявить правильно(назначить нужный тип данных).
Что такое переменная и как правильно её объявить?
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Молодцы!
Цитата
alessandro2981 написал: а потом под комментарий добавить начиная со 2 строчки по 5
Когда закомментировал, то макрос перестал работать. Вам вопрос - почему?
There is no knowledge that is not power
 
Цитата
The_Prist написал: Что такое переменная и как правильно её объявить?
Прочитал статью. Внесу и свои пять копеек.
Переменные в VB передаются "по ссылке" (ByRef) и "по значению" (ByVal). Что это значит?

Например, у нас есть две процедуры. В первой мы объявляем переменную "x" и передаём её во вторую процедуру, где прибавляем к "x" единичку.
Код
Sub Test1()
    Dim X As Integer
    X = 5
    Debug.Print "X до изменений: " & X
    Call ChangeVar1(X)
    Debug.Print "X после до изменений: " & X
End Sub

Sub ChangeVar1(X2 As Integer)
    X2 = X2 + 1
End Sub
После запуска Test1 мы увидим, что значение X после передачи в ChangeVar стало 6. Почему? Потому что по умолчанию в VB переменные передаются по ссылке. То есть ChangeVar мы можем переписать на эквивалентную процедуру:
Код
Sub ChangeVar(ByRef X As Integer)
Если мы поменяем "ByRef" на "ByVal":
Код
Sub ChangeVar(ByVal X As Integer)
то переменная X будет по-прежным равным 5.
Но... как же так получается? В случае с ByRef мы передаём не саму переменную X, а её адрес. Это называется shallow copy.
В случае же с ByVal создаётся новая область в памяти, куда копируется значение "5", и её адрес сохраняется в переменную X2 (deep copy).

Другими словами, переменная - это указатель на адрес в памяти, который хранит значение, а не само значение.
Чтобы более наглядно показать это, запуститие у себя процедуру Test:
Код
Sub Test()
    Dim X As Integer
    X = 5
    Debug.Print "адрес X: " & VarPtr(X)
    Debug.Print "значение X до изменения: " & X
    Call ChangeVar(X)
    Debug.Print "значение X после изменения: " & X
    Debug.Print "адрес X после изменения: " & VarPtr(X)
End Sub

Sub ChangeVar(ByRef X2 As Integer)
    Debug.Print "адрес X2: " & VarPtr(X2)
    Debug.Print "значение X2: " & X2
    X2 = 7
End Sub

' Результат на моём компьютере (у вас будет другой адрес):
' адрес X: 622373453280
' значение X до изменения: 5
' адрес X2: 622373453280
' значение X2: 5
' значение X после изменения: 7
' адрес X после изменения: 622373453280
Давайте на минуту представим, что переменная хранит значение, а не адрес на значение. Тогда как же так получается, что адреса X и X2 равны??? Две переменные по одному адресу не могут находиться одновременно.
VarPtr позволяет нам узнать адрес, который хранится в переменной (также ObjPtr и StrPtr). Как мы видим из результата работы процедуры, переменные X и X2 ссылаются на один и тот же адрес в памяти. Просто VBA скрывает от нас такие подробности. Зная более детально такие механизмы, вы будете лучше понимать, что творится "под капотом".

В C/C++ выражение
Код
Dim x As Integer
x = 2
идентично
Код
int x;
*(&x) = 2;

// "&" берёт адрес, который хранится в x
// "*" ссылка на значение по этому адресу и присваивает значение "2"

А концепция ByRef более понятна:
Код
#include <cwchar>
#include <clocale>

void ChangeByRef(int* y) // "y" - указатель на адрес
{
    wprintf(L"размер указателя y: %d байта\n", sizeof(y)); // 4 байта - для x86; 8 байт - для x64
    wprintf(L"адрес указателя y: %d, значение y: %d\n", &y, *y);
    wprintf(L"адрес, который содержится в указателе: %d\n", y);
    *y += 1; // Прибавляем 1 к 5
}

int main()
{
    setlocale(LC_ALL, "");
    int x;
    x = 5;
    wprintf(L"адрес переменной x: %d, значение x: %d\n", &x, x);
    wprintf(L"вызываем ChangeByRef...\n");
    ChangeByRef(&x); // Передаём адрес значения, который содержится в "x"
    wprintf(L"адрес переменной x: %d, значение x: %d\n", &x, x);
}

// Вывод программы:
//
// адрес переменной x: 15990336, значение x: 5
// вызываем ChangeByRef...
// размер указателя y: 4 байта
// адрес указателя y: 15990124, значение y: 5
// адрес, который содержится в указателе: 15990336
// адрес переменной x: 15990336, значение x: 6
There is no knowledge that is not power
 
Цитата
Johny написал: есть две процедуры. В первой мы объявляем переменную "x" и передаём её во вторую процедуру
тысяча извинений! Тут нет ошибки? Передаем переменую Х вторую процедуру, а там обозначает её как Х2!  
 
Нет, никаких ошибок. Для другой процедуры имя переменной не важно - можно назвать как угодно. Важен тип передачи и тип самой переменной.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
The_Prist написал: Важен тип передачи и тип самой переменной.
Ещё важно знать тип Variant, который может принимать любой тип (например, Integer, Range, Worksheet, Object). То есть если я точно ожидаю объект Range, то лучше использовать Range. Ну а если я ожидаю разные типы переменных, то тогда Variant (или если будут только объекты, то Object):
Код
Sub Test1()
    Const x As Integer = 1
    Dim b As MSForms.CommandButton
    Call Sub1(b)
    Call Sub1(x)
End Sub

Sub Sub1(v As Variant)
End Sub
There is no knowledge that is not power
 
Ну, Variant это понятно. Главное, не применять его в обратную сторону, надеясь, что при передачи в другую процедуру все преобразуется само собой:
Код
Sub test()
    Dim s As Variant
    s = "12"
    Call sub_test(s)
End Sub
Sub sub_test(ss As String)
    Dim f As String
    f = Trim(ss)
End Sub
обязательно получим ошибку "ByRef argument type missmatch", если принудительно не приведем s к типу String:
Код
call sub_test(Cstr(s))
'или
Call sub_test(s & "")
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
The_Prist написал:
обязательно получим ошибку "ByRef argument type missmatch"
Можно и не получить, если принудительно передать Variant "по значению":
Код
Call sub_test((s))
или изменить тип передачи в принимаемой процедуре:
Код
Sub sub_test(ByVal ss As String)
There is no knowledge that is not power
 
Заключение в скобки является принудительным преобразованием, ты-то должен знать. И речь у нас все же про ByRef :)
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Так а я и написал:
Код
если принудительно передать
:D
There is no knowledge that is not power
Страницы: 1
Читают тему
Наверх