Procedimentos: passando argumentos por valor e por referência
Uma dúvida muito comum entre usuários do VBA é com relação a
alguns termos encontrados em alguns eventos com parâmetros:
ByRef e ByVal. O que significam isso e qual o seu
resultado? ByRef e ByVal indicam se o parâmetro será
passado por referência ou por valor,
respectivamente.
alguns termos encontrados em alguns eventos com parâmetros:
ByRef e ByVal. O que significam isso e qual o seu
resultado? ByRef e ByVal indicam se o parâmetro será
passado por referência ou por valor,
respectivamente.
Explicando melhor: se o parâmetro for passado com ByRef, o
VBA usará a referência original da variável no processamento, ou
seja, se o valor for alterado na sub-rotina ou função, a variável
original passada como argumento também terá seu valor alterado.
Caso o parâmetro for passado com ByVal, a sub-rotina ou
função receberá uma cópia do valor e quaisquer alterações não
terão impacto na variável original.
VBA usará a referência original da variável no processamento, ou
seja, se o valor for alterado na sub-rotina ou função, a variável
original passada como argumento também terá seu valor alterado.
Caso o parâmetro for passado com ByVal, a sub-rotina ou
função receberá uma cópia do valor e quaisquer alterações não
terão impacto na variável original.
Para entender isso de uma maneira mais prática, vejamos um código
simples de exemplo:
simples de exemplo:
Sub Teste()
Dim X As Integer
X = 10
Debug.Print “Valor de X = ” & X
Debug.Print “Resultado de Dobro = ” &
Dobro(X)
Dobro(X)
Debug.Print “Valor de X = ” & X
End Sub
Function Dobro(ByRef Valor As Integer) As Integer
Valor = Valor * 2
Dobro = Valor
End Function
A sub-rotina Teste associa um valor à variável X,
mostra seu resultado, mostra o resultado da função Dobro e
depois mostra o resultado de X novamente após a função
Dobro ter sido executada. Note que o parâmetro
Valor na função Dobro foi passada como referência
(ByRef), ou seja, qualquer alteração feita em
Valor irá refletir na variável original. Executando o
código temos o seguinte resultado na área de
Verificação imediata:
mostra seu resultado, mostra o resultado da função Dobro e
depois mostra o resultado de X novamente após a função
Dobro ter sido executada. Note que o parâmetro
Valor na função Dobro foi passada como referência
(ByRef), ou seja, qualquer alteração feita em
Valor irá refletir na variável original. Executando o
código temos o seguinte resultado na área de
Verificação imediata:
Valor de X = 10
Resultado de Dobro = 20
Valor de X = 20
Como podemos ver, a variável X mudou de valor após ter sido
referenciada na função Dobro. Altere a função para ByVal
conforme abaixo:
referenciada na função Dobro. Altere a função para ByVal
conforme abaixo:
Function Dobro(ByVal Valor As Integer) As Integer
Agora execute novamente a sub-rotina Teste e veja o
resultado:
resultado:
Valor de X = 10
Resultado de Dobro = 20
Valor de X = 10
Agora o valor de X não sofreu alterações e se manteve
intacto, pois foi usada uma cópia do valor de X, não a
referência original da variável.
intacto, pois foi usada uma cópia do valor de X, não a
referência original da variável.
E se não for informado ByRef ou ByVal, qual é a
forma padrão que o Excel utiliza? Simples de descobrir: retire da
função Dobro, deixando sem especificação se é ByRef ou
ByVal e veja o resultado:
forma padrão que o Excel utiliza? Simples de descobrir: retire da
função Dobro, deixando sem especificação se é ByRef ou
ByVal e veja o resultado:
Valor de X = 10
Resultado de Dobro = 20
Valor de X = 20
O padrão no VBA é ByRef, ou seja, utilizará a variável
original passada como argumento. Isto não é um problema se você
não edita o valor do parâmetro na função ou na sub-rotina, mas
pode causar problemas se você altera o valor desse parâmetro.
original passada como argumento. Isto não é um problema se você
não edita o valor do parâmetro na função ou na sub-rotina, mas
pode causar problemas se você altera o valor desse parâmetro.
E como funciona com objetos? Será que é do mesmo jeito? Antes de
conferir isso, precisamos de entender que objetos são tratados de
forma diferente. Por exemplo, quando vamos associar uma célula a
uma variável do tipo Range precisamos usar Set antes
da associação, como abaixo:
conferir isso, precisamos de entender que objetos são tratados de
forma diferente. Por exemplo, quando vamos associar uma célula a
uma variável do tipo Range precisamos usar Set antes
da associação, como abaixo:
Set Celula = Range(“A1”)
Da mesma forma, uma sub-rotina ou função que usa um objeto como
parâmetro é escrita de forma distinta. Há três maneiras de fazer a
chamada: usando Call, omitindo os parênteses ou ainda
especificando os parâmetros. Vejamos as três formas abaixo:
parâmetro é escrita de forma distinta. Há três maneiras de fazer a
chamada: usando Call, omitindo os parênteses ou ainda
especificando os parâmetros. Vejamos as três formas abaixo:
Call Dobro(Celula)
Dobro Celula
Dobro Intervalo:=Celula
As três formas funcionam da mesma maneira, utilize aquela que
achar melhor.
achar melhor.
Agora vejamos o código para ver como funciona ByRef e ByVal com
objetos:
objetos:
Sub Teste()
Dim Celula As Range
Set Celula = Range(“A1”)
Debug.Print “Valor da célula A1 = ” &
Celula.Value
Celula.Value
Dobro Celula
Debug.Print “Valor da célula A1 = ” &
Celula.Value
Celula.Value
End Sub
Function Dobro(ByRef Intervalo As Range) As Range
Debug.Print “Valor do intervalo recebido = ”
& Intervalo.Value
& Intervalo.Value
Intervalo.Value = Intervalo.Value * 2
Debug.Print “Valor do intervalo após o
processamento = ” & Intervalo.Value
processamento = ” & Intervalo.Value
End Function
Coloque na célula A1 o valor 10 e efetue o teste. A saída será a
seguinte:
seguinte:
Valor da célula A1 = 10
Valor do intervalo recebido = 10
Valor do intervalo após o processamento = 20
Valor da célula A1 = 20
O valor da célula A1 passou a ser 20. Como vimos,
ByRef passa a referência e por isso tudo funcionou como
esperado. Altere a função para tratar o parâmetro por valor,
substituído ByRef por ByVal, coloque o valor 10
novamente na célula A1 e teste. Vejamos o resultado:
ByRef passa a referência e por isso tudo funcionou como
esperado. Altere a função para tratar o parâmetro por valor,
substituído ByRef por ByVal, coloque o valor 10
novamente na célula A1 e teste. Vejamos o resultado:
Valor da célula A1 = 10
Valor do intervalo recebido = 10
Valor do intervalo após o processamento = 20
Valor da célula A1 = 20
O resultado foi exatamente o mesmo. Por que isso acontece? No VBA
(e em outras linguagens de programação) os objetos são sempre
passados como referência, ou seja, qualquer alteração feita irá
refletir no objeto usado como parâmetro. Portanto, não importa se
o objeto está acompanhado de ByVal, o resultado será como
ByRef.
(e em outras linguagens de programação) os objetos são sempre
passados como referência, ou seja, qualquer alteração feita irá
refletir no objeto usado como parâmetro. Portanto, não importa se
o objeto está acompanhado de ByVal, o resultado será como
ByRef.
Particularmente não costumo alterar o valor das variáveis usadas
como parâmetro, por isso nem uso ByRef ou ByVal no
VBA. Somente nos objetos é que costumo alterar e o efeito desejado
é justamente alterar o objeto passado como parâmetro. O importante
é sempre testar bem a sub-rotina ou função para saber se está tudo
funcionando bem e está com o efeito desejado.
como parâmetro, por isso nem uso ByRef ou ByVal no
VBA. Somente nos objetos é que costumo alterar e o efeito desejado
é justamente alterar o objeto passado como parâmetro. O importante
é sempre testar bem a sub-rotina ou função para saber se está tudo
funcionando bem e está com o efeito desejado.
Quaisquer dúvidas, comentários ou sugestões, use a seção de
comentários abaixo. Até o próximo artigo.
comentários abaixo. Até o próximo artigo.
Pedro Martins
Formado em Tecnologia em Eletrônica Digital, já trabalhou como
artefinalista, eletrotécnico, programador de CLP (para máquinas
industriais) e analista de sistemas em sistema bancário, programando
em COBOL.
Mexe com computadores e programação desde a segunda metade dos
anos 1980, quando teve um MSX e aprendeu a programar em BASIC. É a
favor da disseminação do conhecimento.
artefinalista, eletrotécnico, programador de CLP (para máquinas
industriais) e analista de sistemas em sistema bancário, programando
em COBOL.
Mexe com computadores e programação desde a segunda metade dos
anos 1980, quando teve um MSX e aprendeu a programar em BASIC. É a
favor da disseminação do conhecimento.
Catálogo de aulas (NOVIDADE)
Criei um catálogo de aulas para ajudar você em seus estudos. Acesse clicando na imagem abaixo ou clique aqui.