Menu
Coddy logo textTech

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.

challenge icon

Desafio

Fácil

Agora 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ótipo Robot com:
    • Um campo model definido como "RX-100"
    • Um campo batteryLevel definido como 100
    • Um método :status() que imprime o estado atual do robô
    Retorne a tabela ao final do arquivo.
  • main.lua: Requeira o módulo Robot, então crie uma tabela de instância vazia e vincule-a ao protótipo Robot usando setmetatable com __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:

  1. Atribua o nome de entrada ao campo name da sua instância (isso se torna exclusivo da instância)
  2. 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 called

A 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
quiz iconTeste seus conhecimentos

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