为什么我要编写 required init() {}?

huangapple go评论61阅读模式
英文:

Why should I write required init() {}?

问题

我不明白为什么我会得到编译器错误:

>构造一个类类型为'Self'的对象,必须使用'required'初始化程序`

为什么我要编写 required init() {}?

以下是完整代码。

class ParentFactory {
    static func create() -> Self {
        return self.init()
    }
    
//    required init(){}
    
    func printMessage() {
        print("Super")
    }
}

class Child1Factory: ParentFactory {
    override func printMessage() {
        print("1 ")
    }
}

class Child2Factory: ParentFactory {
    override func printMessage() {
        print("2 ")
    }
}


class Factory {
    static func createFactory(_ type: String) -> ParentFactory {
        if type == "1" {
            return Child1Factory.create()
        } else {
            return Child2Factory.create()
        }
    }
}

如果我写required init() {},错误就不会发生。我不明白为什么即使初始化程序中没有任何代码,我也需要required init

英文:

I don't understand why I get the compiler error:

>Constructing an object of class type 'Self' with a metatype value must use a 'required' initializer`

为什么我要编写 required init() {}?

Below is full code.

class ParentFactory {
    static func create() -> Self {
        return self.init()
    }
    
//    required init(){}
    
    func printMessage() {
        print("Super")
    }
}

class Child1Factory: ParentFactory {
    override func printMessage() {
        print("1 Class")
    }
}

class Child2Factory: ParentFactory {
    override func printMessage() {
        print("2 Class")
    }
}


class Factory {
    static func createFactory(_ type: String) -> ParentFactory {
        if type == "1" {
            return Child1Factory.create()
        } else {
            return Child2Factory.create()
        }
    }
}

If I write required init() {}, the error does not occur. I don't understand why I need required init even if it doesn't have any code in the initializer.

答案1

得分: 2

Swift文档中:

Swift为任何提供了所有属性的默认值且没有提供至少一个初始化程序的结构或类提供了一个默认初始化程序。默认初始化程序只是创建一个所有属性都设置为它们的默认值的新实例。

你的 ParentFactory 没有存储属性,所以理论上将创建默认初始化程序并且应该足够了。但是,你使用了元类型 Self,所以你不一定在实例化一个 ParentFactory - 它可以是 ParentFactory 的子类,而实际上这就是你正在做的事情。

现在,想象一下如果 Child1Factory 看起来像这样:

class Child1Factory: ParentFactory {
    let aProperty: Int
    
    init(number: Int) {
        self.aProperty = number
        super.init()
    }

    override func printMessage() {
        print("1 Class")
    }
}

这是一个完全有效的实现 - 我们有一个初始化程序,它初始化了类属性并调用了超类初始化程序。然而,我不能说 let child = Child1Factory() - 那个初始化程序不存在,但这正是在调用 Child1Factory.create 时执行 Self.init() 时正在发生的事情。

为了防止这种情况发生,你的父类必须具有与 Self 初始化程序的签名匹配的 required init - 这样就保证了该类和所有子类都具有具有该初始化程序签名的 init。

这不重要初始化程序是否为空。重要的是你确保所有子类都可以使用该初始化程序签名调用。

英文:

From the Swift documentation
> Swift provides a default initializer for any structure or class that provides default values for all of its properties and doesn’t provide at least one initializer itself. The default initializer simply creates a new instance with all of its properties set to their default values.

Your ParentFactory has no stored properties and so, in theory, the default initialiser will be created and should be sufficient. But, you have used the meta type Self, so you aren't necessarily instantiating a ParentFactory - It could be a subclass of ParentFactory, and indeed this is what you are doing.

Now, imagine if Child1Factory looked like this:

class Child1Factory: ParentFactory {
    let aProperty: Int
    
    init(number: Int) {
        self.aProperty = number
        super.init()
    }

    override func printMessage() {
        print("1 Class")
    }
}

This is a perfectly valid implementation - We have an initialiser that initialises the class properties and that calls the superclass initialiser. However, I can't say let child = Child1Factory() - That initialiser doesn't exist, but this is exactly what you are doing when you call Child1Factory.create and it executes Self.init().

To protect against this, your parent class must have a required init that matches the signature of the Self init - That way it is guaranteed that this class and all subclasses will have an init with that signature.

It doesn't matter that the initialiser is empty. What matters is that you are ensuring that all subclasses can be called with that initialiser signature.

huangapple
  • 本文由 发表于 2023年5月26日 11:20:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76337449.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定