Ответ
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. И всё будет пучком, без лишней ебалы с переписыванием всего подряд.