Vinculando com __index
Parte da seção Object Oriented Programming do Journey de Lua da Coddy — lição 7 de 70.
Você tem uma tabela de protótipo com propriedades e métodos, mas como você faz um novo objeto realmente usá-la? A resposta está no metamétodo __index.
Quando você acessa uma chave que não existe em uma tabela, o Lua normalmente retorna nil. No entanto, se a tabela tiver uma metatabela com um campo __index, o Lua procurará lá em vez disso. Ao configurar o __index para apontar para o seu protótipo, quaisquer chaves ausentes são encontradas automaticamente no protótipo:
local Dog = {
species = "Canis familiaris",
legs = 4
}
function Dog:bark()
print("Woof!")
end
-- Cria uma instância vazia
local myDog = {}
-- Vincula-a ao protótipo
setmetatable(myDog, { __index = Dog })
print(myDog.species) -- Saída: Canis familiaris
myDog:bark() -- Saída: Woof!A tabela myDog está completamente vazia, mas acessar myDog.species funciona. Quando o Lua não encontra species em myDog, ele verifica o __index da metatabela e o encontra em Dog.
Esta é a base da programação orientada a objetos em Lua. A instância pode ter seus próprios dados exclusivos, enquanto o comportamento compartilhado reside no protótipo. Na próxima lição, você aprenderá como envolver esse padrão em uma função construtora limpa.
Desafio
FácilAgora vamos colocar o metamétodo __index em prática! Você criará um protótipo e vinculará uma instância a ele, permitindo que a instância acesse propriedades e métodos que ela não possui diretamente.
Você organizará seu código em dois arquivos:
Robot.lua: Defina uma tabela de protótipoRobotcom:- Um campo
modeldefinido como"RX-100" - Um campo
batteryLeveldefinido como100 - Um método
:status()que imprime o estado atual do robô
- Um campo
main.lua: Requeira o módulo Robot, então crie uma tabela de instância vazia e vincule-a ao protótipo Robot usandosetmetatablecom__index. Isso permite que sua instância vazia acesse tudo do protótipo.
Você receberá uma entrada: um nome para atribuir à sua instância de robô.
Após vincular a instância ao protótipo:
- Atribua o nome de entrada ao campo
nameda sua instância (isso se torna exclusivo da instância) - Chame o método
:status()na sua instância
Seu método :status() deve imprimir exatamente neste formato:
[name] ([model]) - Battery: [batteryLevel]%Por exemplo, se a entrada for Sparky, a saída deve ser:
Sparky (RX-100) - Battery: 100%Observe como a instância tem seu próprio name, mas acessa model e batteryLevel do protótipo através do link __index.
Folha de consulta
O metamétodo __index permite que objetos herdem propriedades e métodos de uma tabela protótipo.
Quando você acessa uma chave que não existe em uma tabela, o Lua verifica se a tabela possui uma metatabela com um campo __index. Se possuir, o Lua procura a chave na tabela especificada por __index.
Para vincular uma instância a um protótipo:
local Prototype = {
property = "value"
}
function Prototype:method()
print("Method called")
end
-- Criar uma instância
local instance = {}
-- Vincular ao protótipo usando __index
setmetatable(instance, { __index = Prototype })
-- Acessar propriedades e métodos do protótipo
print(instance.property) -- Saída: value
instance:method() -- Saída: Method calledA tabela da instância pode estar vazia, mas ainda assim pode acessar todas as propriedades e métodos do protótipo. A instância também pode ter suas próprias propriedades exclusivas que substituem ou estendem o protótipo.
Este padrão é a base da programação orientada a objetos em Lua, onde as instâncias compartilham o comportamento de um protótipo enquanto mantêm seus próprios dados exclusivos.
Experimente você mesmo
-- Ler entrada
local name = io.read()
-- Requerer o módulo Robot
local Robot = require('Robot')
-- TODO: Criar uma tabela de instância vazia
-- TODO: Vincular a instância ao protótipo Robot usando setmetatable com __index
-- TODO: Atribuir o nome de entrada ao campo name da sua instância
-- TODO: Chamar o método :status() na sua instância
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Object Oriented Programming
1O Conceito 'Self'
Tabelas com Funções'self' ExplícitoA Sintaxe de Dois-pontosPonto vs Dois-pontosRecapitulação - Movendo o Ponto4Projeto: Banco Digital
Configuração do ProjetoMétodo de Depósito7Polimorfismo e Sobrescrita
Sobrescrita de MétodosChamando Métodos da Classe PaiDuck TypingInterface ComumVerificando o TipoRecapitulação - Papéis de Funcionários10Projeto: Gerenciador de Formas
Configuração do ProjetoClasse Retângulo2Padrão de Protótipo de Classe
O Conceito de ProtótipoVinculando com __indexO Construtor :new()Inicializando AtributosInstâncias IndependentesRecapitulação - Fábrica de Carros5Sobrecarga de Operadores em POO
Somando ObjetosSubtraindo ObjetosConcatenando ObjetosComparando Objetos (<, >)Recapitulação - Matemática de Carteira8Encapsulamento
Convenções de NomenclaturaClosures para PrivacidadeAcesso via ClosuresTabelas Somente LeituraLógica de ValidaçãoRecapitulação - Cofre Seguro11Padrões de Projeto (Lite)
Funções FactoryTabela SingletonPadrão IteratorObserver (Listener)Recapitulação - Logger Factory3Estado e Comportamento do Objeto
Variáveis de InstânciaMétodos GetterMétodos SetterPropriedades CalculadasFormatação de StringsVerificações de IgualdadeRecapitulação - Nota do Aluno6Fundamentos de Herança
Configurando a HerançaHerdando MétodosEstendendo o ConstrutorAdicionando Métodos FilhosCompartilhado vs ÚnicoRecapitulação - Hierarquia de Formas