Menu
Coddy logo textTech

Конкатенация объектов

Часть раздела Object Oriented Programming путешествия по Lua на Coddy — урок 28 из 70.

Оператор .. в Lua объединяет строки, но что, если вы хотите объединить объект со строкой? Метаметод __concat позволяет точно определить, как именно это должно работать.

Когда Lua встречает a .. b и один из операндов имеет метаметод __concat, она вызывает эту функцию с обоими значениями. Это полезно, когда вы хотите, чтобы объекты естественным образом вписывались в строковые выражения.

local Name = {}
Name.__index = Name

function Name:new(first, last)
    local obj = {first = first, last = last}
    setmetatable(obj, Name)
    return obj
end

function Name.__concat(a, b)
    if type(a) == "string" then
        return a .. b.first .. " " .. b.last
    else
        return a.first .. " " .. a.last .. b
    end
end

Обратите внимание, что функция проверяет, какой из операндов является строкой. Поскольку .. может использоваться как "Hello " .. obj или obj .. "!", ваш метаметод должен обрабатывать оба случая.

local person = Name:new("Ada", "Lovelace")

print("Dr. " .. person)      -- Вывод: Dr. Ada Lovelace
print(person .. " PhD")      -- Вывод: Ada Lovelace PhD

Как и другие метаметоды операторов, __concat использует синтаксис с точкой и получает оба операнда в качестве аргументов. Ключевое отличие от арифметических метаметодов заключается в том, что вы обычно работаете со смешанными типами — вашим объектом и строкой.

challenge icon

Задание

Легко

Давайте создадим класс Title, который может естественным образом встраиваться в строковые выражения с помощью оператора ... Это полезно, когда вы хотите объединять объекты со строками понятным и интуитивным способом — например, добавляя обращения или суффиксы к заголовку или званию человека.

Вы организуете свой код в двух файлах:

  • Title.lua: Определите класс Title с полем text, в котором хранится строка заголовка. Включите конструктор :new(text) и реализуйте метаметод __concat. Ваш метаметод должен обрабатывать оба случая: когда строка стоит перед объектом ("prefix" .. obj) и когда строка стоит после него (obj .. "suffix"). Результат должен соответствующим образом объединять строку с текстом заголовка.
  • main.lua: Подключите модуль Title, создайте экземпляр заголовка и продемонстрируйте конкатенацию с обеих сторон.

Вы получите три входных значения:

  1. Текст заголовка (например, "Engineer")
  2. Строку-префикс для размещения перед заголовком (например, "Senior ")
  3. Строку-суффикс для размещения после заголовка (например, " III")

В вашем основном файле создайте Title с заданным текстом. Затем выполните две конкатенации и выведите каждый результат на отдельной строке:

  1. Объедините строку-префикс с объектом заголовка
  2. Объедините объект заголовка со строкой-суффиксом

Например, если входные данные — Engineer, Senior и III, вывод должен быть следующим:

Senior Engineer
Engineer III

Первая строка показывает префикс, объединенный с заголовком, а вторая — заголовок, объединенный с суффиксом. Ваш метаметод __concat делает такое естественное смешивание строк возможным!

Шпаргалка

Метаметод __concat позволяет определить пользовательское поведение для оператора конкатенации .. при работе с объектами.

Когда Lua встречает a .. b и один из операндов имеет метаметод __concat, она вызывает эту функцию с обоими значениями.

Базовая реализация

local MyClass = {}
MyClass.__index = MyClass

function MyClass:new(value)
    local obj = {value = value}
    setmetatable(obj, MyClass)
    return obj
end

function MyClass.__concat(a, b)
    if type(a) == "string" then
        return a .. b.value
    else
        return a.value .. b
    end
end

Обработка обоих порядков операндов

Поскольку .. может использоваться как "string" .. obj или obj .. "string", ваш метаметод должен проверять, какой операнд является строкой, и обрабатывать оба случая:

function Name.__concat(a, b)
    if type(a) == "string" then
        return a .. b.first .. " " .. b.last
    else
        return a.first .. " " .. a.last .. b
    end
end

Пример использования

local person = Name:new("Ada", "Lovelace")

print("Dr. " .. person)      -- Вывод: Dr. Ada Lovelace
print(person .. " PhD")      -- Вывод: Ada Lovelace PhD

Как и другие метаметоды операторов, __concat использует синтаксис с точкой и получает оба операнда в качестве аргументов.

Попробуйте сами

-- Чтение входных данных
local titleText = io.read()
local prefix = io.read()
local suffix = io.read()

-- Подключение модуля Title
local Title = require('Title')

-- TODO: Создать экземпляр Title с заданным titleText

-- TODO: Объединить prefix с объектом title и вывести результат

-- TODO: Объединить объект title с suffix и вывести результат
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Object Oriented Programming