Как в Swift добавить собственный инициализатор для структуры, сохранив memberwise инициализатор?

Ответ

Swift автоматически генерирует memberwise инициализатор для структур только если вы не определяете собственные инициализаторы в основном теле структуры. Чтобы добавить кастомный инициализатор и не потерять дефолтный, есть два основных подхода:

1. Определение кастомного инициализатора в extension Так как memberwise инициализатор не переопределяется в extension, он остаётся доступным.

struct Person {
    var name: String
    var age: Int
}

extension Person {
    init(name: String) {
        // Вызываем автоматически сгенерированный инициализатор
        self.init(name: name, age: 0)
    }
}

// Оба инициализатора доступны:
let person1 = Person(name: "Alex", age: 30) // Memberwise init
let person2 = Person(name: "Anna")          // Custom init (age = 0)

2. Использование значения по умолчанию для параметра Это самый простой способ, если нужно лишь задать значение по умолчанию для одного из свойств.

struct Person {
    var name: String
    var age: Int = 0 // Значение по умолчанию
}

// Можно использовать оба варианта:
let person1 = Person(name: "Alex", age: 30)
let person2 = Person(name: "Anna") // age автоматически равен 0

Важно: Для классов memberwise инициализатор не генерируется. Чтобы сохранить designated инициализатор и добавить convenience, используйте ключевое слово convenience.

class Vehicle {
    var wheels: Int

    init(wheels: Int) {
        self.wheels = wheels
    }

    convenience init() {
        self.init(wheels: 4) // Вызывает designated инициализатор
    }
}

Ответ 18+ 🔞

А, вот это классика, блядь! Сидишь такой, пишешь свою структуру, всё пиздато, всё работает, а потом — бац! — захотел добавить свой инициализатор, и тут же твой удобный, блядь, memberwise init накрылся медным тазом! Пиздец, да? Swift тебе как бы намекает: «Решил умничать? Ну так теперь, сука, сам всё пиши!»

Но не всё так страшно, ёпта. Есть пара трюков, чтобы и волки были сыты, и овцы целы. То есть чтобы и свой кастомный инициализатор замутить, и дефолтный, который Swift сам сгенерировал, не потерять.

Первый способ — extension, хитрая жопа! Смотри, логика простая: автоматический инициализатор не переопределяется, если ты свой пишешь в extension. Это как отдельная комната, блядь. В основном теле структуры — чистота, всё как есть. А в extension'е ты уже творишь, что хочешь.

struct Person {
    var name: String
    var age: Int
}

extension Person {
    init(name: String) {
        // А внутри просто вызываем тот самый, родной, memberwise init
        self.init(name: name, age: 0)
    }
}

// И теперь, охуеть, оба работают:
let person1 = Person(name: "Alex", age: 30) // Старый добрый memberwise
let person2 = Person(name: "Anna")          // Твой новый, где age = 0

Вот и всё, ебать мои старые костыли! Ничего не сломалось.

Второй способ — для ленивых (он же самый разумный) Если тебе просто нужно, чтобы какое-то свойство имело значение по умолчанию, то можно вообще не париться. Просто присвой ему это значение прямо в объявлении.

struct Person {
    var name: String
    var age: Int = 0 // Во, ёпта! Значение по умолчанию прикрутил
}

// И снова можно вызывать как угодно:
let person1 = Person(name: "Alex", age: 30)
let person2 = Person(name: "Anna") // age автоматом станет 0

Swift увидит значение по умолчанию и сгенерирует сразу два варианта инициализатора. Красота, блядь!

А вот с классами — отдельная песня, пиздец! Тут тебе memberwise инициализатор из коробки не светит вообще, ни при каких условиях. Для классов это как «удобный» (convenience) инициализатор. Главное правило: convenience init должен в итоге вызвать designated init.

class Vehicle {
    var wheels: Int

    // Это designated инициализатор, главный по тарелкам
    init(wheels: Int) {
        self.wheels = wheels
    }

    // А это convenience — он просто делегирует всё главному
    convenience init() {
        self.init(wheels: 4) // Эй, designated, лови работу!
    }
}

Короче, запомни: для структур — либо extension, либо значения по умолчанию. Для классов — designated и convenience. И всё будет пучком, без лишней ебалы с переписыванием всего подряд.