Escopo de Variáveis

Esta página explica como procedimentos conseguem acessar uma variável de acordo como ela é declarada.

Introdução

O escopo de uma variável se refere à sua acessibilidade, isto é, de quais procedimentos ela pode ser acessada e/ou alterada. Existem variáveis de nível de procedimento, nível de módulo e de nível global.

Estou pressupondo que você trabalhe com a opção Option Explicit em todos os módulos do seu projeto. Sem isso, esta página não faz sentido. Se não entendeu o que isso significa, a leitura da página a seguir é obrigatória: Variáveis e Constantes.
Não confunda escopo de variáveis com escopo de procedimentos. Para ver a página sobre escopo de procedimentos, clique aqui.

Nível de Procedimento

Variáveis de nível de procedimento também são conhecidas como variáveis locais. Elas recebem esse nome porque só podem ser acessadas por instruções do procedimento que a declarou. Como o próprio nome indica, elas são declaradas dentro de um procedimento:

Sub Local1()
  Dim FirstName As String
  
  FirstName = "Felipe"
  
  MsgBox FirstName
  
  Local2
End Sub
 
Sub Local2()
  MsgBox FirstName
End Sub

Ao compilar esse código, você obterá o erro de compilação a seguir:

Isso acontece porque como FirstName é externo ao procedimento Local2.

Se você também declarasse FirstName em Local2, como mostrado a seguir:

Sub Local2()
  Dim FistName As String
  
  MsgBox FirstName
End Sub

O código executaria, mas a caixa de mensagem ficaria em branco porque o valor dessa variável não terá nenhuma relação com seu homônimo de Local1, a não ser de coincidirem o mesmo nome, e como o valor inicial de uma variável String é “” (vazio), a caixa de mensagem em branco é mostrada.

Variáveis Estáticas

Variáveis estáticas, assim como variáveis de procedimento, são declaradas dentro de um procedimento. Seu comportamento é idêntico ao de uma variável de procedimento, exceto que ela conserva seu valor quando o procedimento é chamado novamente.

Para declarar uma variável estática, use a palavra chave Static ao invés de Dim. O código abaixo declara uma variável String estática:

Sub Main()
  Static ContadorEstático As Long
  
  '...
End Sub

O código a seguir ilustra a particularidade de variáveis estáticas em manter seu valor a cada nova chamada de procedimento:

Private Sub Main()
  Debug.Print "Primeira execução de 'IncrementarValores':"
  IncrementarValores
  
  Debug.Print "Segunda execução de 'IncrementarValores':"
  IncrementarValores
  
  Debug.Print "Terceira execução de 'IncrementarValores':"
  IncrementarValores
End Sub
 
Private Sub IncrementarValores()
  Dim ContadorNormal As Long
  Static ContadorEstático As Long
  
  ContadorNormal = ContadorNormal + 1
  ContadorEstático = ContadorEstático + 1
  
  Debug.Print "Valor de variável normal: " & ContadorNormal
  Debug.Print "Valor de variável estática: " & ContadorEstático
  Debug.Print
End Sub

A saída do programa é mostrada a seguir:

Primeira execução de 'IncrementarValores':
Valor de variável normal: 1
Valor de variável estática: 1
 
Segunda execução de 'IncrementarValores':
Valor de variável normal: 1
Valor de variável estática: 2
 
Terceira execução de 'IncrementarValores':
Valor de variável normal: 1
Valor de variável estática: 3

Observe que variável ContadorNormal tem seu valor reiniciado a cada chamada de IncrementarValores, enquanto ContadorEstático mantém seu valor.

Procedimentos Estáticos

Se você quiser que todas as variáveis de um módulo sejam estáticas, utilize a palavra chave Static antes de declarar um procedimento. Logo, a instrução a seguir:

Sub MostrarContadores()
    Static FirstName As String
    Static FelipeCount As Long
    Static RenataCount As Long
    
    FirstName = "Felipe"
    FelipeCount = FelipeCount + 1
    RenataCount = RenataCount + 5
End Sub

É equivalente a:

Static MostrarContadores()
    Dim FirstName As String
    Dim FelipeCount As Long
    Dim RenataCount As Long
    
    FirstName = "Felipe"
    FelipeCount = FelipeCount + 1
    RenataCount = RenataCount + 5
End Sub

Em ambos os casos, todas as variáveis serão estáticas.

Nível de Módulo

Variáveis de nível de módulo podem ser acessadas de qualquer procedimento de um módulo, mas não por outros módulos. Elas devem ser declaradas na seção de declaração do módulo, antes de todos os procedimentos. Tomando como base o exemplo anterior, veja o código abaixo:

Option Explicit
 
Dim FirstName As String
 
Sub Exemplo1()
  FirstName = "Felipe"
  
  MsgBox FirstName
  
  Exemplo2
End Sub
 
Sub Exemplo2()
  MsgBox FirstName
End Sub

Exemplo2 é capaz de acessar a variável FirstName porque ela é de nível de módulo.

Algumas pessoas que utilizam a técnica de nomeação por prefixos adicionam a letra m. para representar que o escopo de uma variável é de nível de módulo. No exemplo acima, a variável se chamaria então msFirstName. m de nível de módulo, e s de String.

Se você declarar uma variável local com o mesmo nome de uma variável de módulo desse módulo, o VBA dará prioridade de acesso à variável local.

Nível Global

Variáveis globais (ou públicas) podem ser acessadas por qualquer procedimento de um projeto. Variáveis públicas são declaradas com a instrução Public e sua declaração deve estar na seção de declaração.

A figura a seguir mostra a declaração de uma variável pública e o subprocedimento Main atribui um valor a ela. Em seguida, chama-se um subprocedimento de outro módulo para exibir o valor dessa variável.

Observe que quando a variável é global, adiciona-se o prefixo de seu tipo a letra g (de Global). Use essa técnica se você pratica a nomeação de variáveis por prefixo.

Se você tiver uma variável de módulo e uma de global com o mesmo nome, o VBA dará prioridade à de nível de módulo. Logo, o VBA dá prioridade a acessar variáveis de mesmo nome na seguinte ordem: locais, de módulo e globais.

Tome cuidado com variáveis públicas. Use-as o mínimo possível. Se puder, declare todas elas num único módulo chamado, por exemplo, PublicVariables. Dessa forma, você manterá seu projeto organizado.

Preservação de Estado de Variáveis

Você deve ficar atento porque, com exceção de variáveis locais, o VBA preserva o valor de uma variável ao terminar a execução de um programa. Então, se você executar o programa novamente, essas variáveis terão um valor inicial igual ao que tinham quando o programa terminou pela última vez.

Observe o código a seguir:

Public Pública As Long
Dim Módulo As Long
 
Private Sub Main()
  Static Estática As Long
  Dim ProcedimentoLocal As Long
  
  Pública = Pública + 1
  Módulo = Módulo + 1
  Estática = Estática + 1
  ProcedimentoLocal = ProcedimentoLocal + 1
  
    Debug.Print "Pública: " & Pública
  Debug.Print "Módulo: " & Módulo
  Debug.Print "Estática: " & Estática
  Debug.Print "Procedimento/Local: " & ProcedimentoLocal
End Sub

Se executa-lo pela primeira vez, você obterá na Janela de Verificação Imediata:

Pública: 1
Módulo: 1
Estática: 1
Local: 1

Executando o mesmo subprocedimento novamente, obterá:

Pública: 2
Módulo: 2
Estática: 2
Local: 1

Mais uma vez:

Pública: 3
Módulo: 3
Estática: 3
Local: 1

É fácil ver que com exceção da variável local, todas as outras preservaram seu valor na execução.

Perda de Estado de Variáveis

A propriedade de manter o estado das variáveis só é verdadeira se você não fizer “grandes” alterações no seu código entre uma execução e outra de macros. Por exemplo, se você executar a macro anterior algumas vezes, seleciona-la por completo no VBE, apagá-la (tendo copiado antes) e colar o mesmo código novamente no mesmo lugar, a saída do programa será:

Pública: 1
Módulo: 1
Estática: 1
Local: 1

Todas as variáveis – não só locais – foram reiniciadas. O nome desse fenômeno é Perda de Estado.

Note que utilizei o termo “grandes” alterações, mas não é bem isso. O VBE perde o estado das variáveis, normalmente, quando você exclui um procedimento ou declarações de variáveis. Se você fizer algumas alterações no código que não envolva declarações, não obterá esse efeito.

É possível habilitar um alerta para que você seja notificado toda vez que fizer uma alteração que implicará na perda de estado das variáveis. Para tal, clique no menu Ferramentas >> Opções >> guia Geral >> caixa de seleção Notificar antes de perda de estado:

Reiniciar Valores de Variáveis

Você deve ficar atento que enquanto estiver tempo de design trabalhando no seu projeto, não fazer premissas que todas as variáveis são reiniciadas ou já possuem determinado valor, conforme subseção anterior.

Tenho o hábito de reiniciar os valores de todas variáveis que não sejam locais. O exemplo a seguir mostra um pouco disso:

Public glLastRow As Long
Dim msName As String
 
Sub Main()
  Dim dtBirth As Date
 
  glLastRow = 0
  msName = ""
 
  '...continuação do programa
End Sub

Note que não há necessidade de reiniciar o valor de dtBirth, porque ela é uma variável local e já perde seu estado naturalmente a cada nova execução do procedimento em que se encontra.

Em programas grandes, para evitar confusão, costumo criar um procedimento só para reiniciar variáveis que tem a propriedade de manter seu estado, como mostra o exemplo a seguir:

Public Global1 As Long
Public Global2 As Long
Dim Módulo1 As String
 
Private Sub Main()
  ReiniciarVariáveis
  
  '...código do programa
  
End Sub
 
Sub ReiniciarVariáveis()
  Global1 = 0
  Global2 = 0
  Módulo1 = ""
End Sub

 

Sobre Felipe Gualberto

Microsoft Most Valuable Professional (MVP) de Excel.
Esta entrada foi publicada em Tutoriais e marcada com a tag , , , , , . Adicione o link permanente aos seus favoritos.
  • André

    Felipe …

    Saberia dizer se é possível acessar o valor de uma variável contida em um projeto de um arquivo .accdb, a partir de um projeto de um segundo arquivo (.xlsm) ?

    Detalhe: os dois estão abertos simultaneamente.

    • Sim, siga os passos abaixo.

      ‘O código abaixo deve estar no Access

      Dim SharedVariable As String

      ‘Execute este procedimento uma vez.

      Sub SetInitialValue

      SharedVariable = “Felipe”

      End Sub

      Function ReturnSharedVariable() As String

      ReturnSharedVariable = SharedVariable

      End Function

      Então,

      ‘O código abaixo deve estar no Excel

      Sub ShowAccessVariable()

      Dim appExternal As Object ‘Access.Application

      Dim ExternalVariable As String

      Set appExternal = GetObject(“C:tempDatabase1.accdb”)

      ExternalVariable = appExternal.Run(“ReturnSharedVariable”)

      MsgBox ExternalVariable

      Set appExternal = Nothing

      End Sub

      • André

        Excelente.. vou testar e retorno

        Obrigado !!!