在super.init调用之前初始化非可选属性,而无需复制代码 [英] Initialize Non-Optional Property Before super.init call without duplicating code

查看:86
本文介绍了在super.init调用之前初始化非可选属性,而无需复制代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Swift中对我来说最令人沮丧的情况之一是当我有一个这样的类时:

One of the most frustrating situations for me in Swift is when I have a class like this:

class A: NSObject {
    var a: Int

    override init() {
        clear()
        super.init()
    }

    func clear() {
        a = 5
    }
}

当然,这会导致多个编译器错误('self' used in method call 'clear' before 'super.init' callProperty 'self.a' not initialized at super.init call.

Of course, this causes multiple compiler errors ('self' used in method call 'clear' before 'super.init' call and Property 'self.a' not initialized at super.init call.

更改构造函数行的顺序只能解决第一个错误:

And changing the order of the constructor lines only fixes the first error:

override init() {
    super.init()
    clear()
}

通常,我最终要做两件事之一.第一种选择是使a成为隐式解包的可选,但是我觉得这是很糟糕的样式,因为在构造函数返回后,a永远不会是nil:

Usually, I end up doing one of two things. The first option is to make a an implicitly unwrapped optional, but I feel that this is terrible style because a will never be nil after the constructor returns:

var a: Int! = nil

第二个选项是在构造函数中复制我的clear()函数的功能:

The second option is to copy the functionality of my clear() function in the constructor:

override init() {
    a = 5
    super.init()
}

对于这个简化的示例来说,这很好用,但是不必要地在更复杂的代码库中重复了很多代码.

This works fine for this simplified example, but it unnecessarily duplicates a lot of code in more complex code bases.

有没有一种方法可以初始化a而不复制我的clear函数或将a设置为可选?如果没有,为什么不呢?!

Is there a way to initialize a without duplicating my clear function or making a an optional? If not, why not?!

推荐答案

在这种特定于 的情况下,为什么不这样"非常简单.您所写的内容将允许我编写以下内容:

The "why not" in this specific case is very straightforward. What you've written would allow me to write this:

class B: A {
    override func clear() {}
}

然后a不会被初始化.因此,您编写的内容永远不可能是合法的Swift.

And then a would not be initialized. So what you've written can never be legal Swift.

也就是说,有一个更深的版本可能是合法的,但不是.如果您标记了类final或如果这是一个结构,则编译器也许可以通过内联所有可能的方法调用来证明所有代码路径上的所有内容均已正确初始化,但是编译器今天不会做所有这些事情;它太复杂了.编译器只是说我的证明引擎没有那么强大,所以将其关闭."

That said, there's a deeper version that probably could be legal but isn't. If you marked the class final or if this were a struct, then the compiler might be able to prove that everything is correctly initialized along all code paths by inlining all the possible method calls, but the compiler doesn't do all that today; it's too complicated. The compiler just says "my proof engine isn't that strong so knock it off."

IMO,这里的正确解决方案是!类型,尽管我不会添加= nil.这是误导.我会这样写:

IMO, the correct solution here is a ! type, though I wouldn't add = nil. That's misleading. I would write it this way:

class A: NSObject {
    var a: Int!    // You don't have to assign `!` types; they're automatically nil

    override init() {
        super.init()
        clear()
    }

    func clear() {
        a = 5
    }
}

这表示我有责任确保在使用a之前先进行设置."这正是您在做什么.当我需要通过自我代表时,我会一直这样做.我希望编译器可以探索每个方法调用中的每个可能的代码路径,但是今天还不行(鉴于编译时间可能会做些什么,也许我不希望如此).

This says "I am taking responsibility to make sure that a is going to be set before it is used." Which is exactly what you are doing. I do this all the time when I need to pass self as a delegate. I wish the compiler could explore every possible code path across every method call, but it doesn't today (and given what it might do to compile times, maybe I don't wish that).

但是我觉得这很糟糕,因为在构造函数返回后a永远不会为空

but I feel that this is terrible style because a will never be nil after the constructor returns

这正是!类型的重点.当其他任何对象可以拿到它们时,它们应该永远为零.如果它可能是nil,则您不应该使用!.我同意!危险的(因为编译器不再为您提供帮助),但这不是坏样式.

That's exactly the point of ! types. They should never be nil by the time any other object can get their hands on it. If it could be nil, then you shouldn't be using !. I agree that ! is dangerous (since the compiler is no longer helping you), but it's not bad style.

IMO唯一的其他合理方法是分配默认值.我当然不会使用实际值.这将邀请您发现细微的错误.我只想使用一些默认值就可以了.

The only other reasonable approach IMO is to assign default values. I wouldn't use the actual values of course; that would an invitation to subtle bugs. I would just use some default value to get things in place.

class A: NSObject {
    var a = Int.min // -1 might be reasonable. I just like it to be clearly wrong
    override init() {
        super.init()
        clear()
    }

    func clear() {
        a = 5
    }
}

我不喜欢这种方法,尽管我在一些地方使用了它.我认为它不会给!提供任何安全性(它不会崩溃,但是您几乎可以肯定会给您细微的行为错误,我希望崩溃).这是程序员必须注意的地方,因为编译器的功能足以证明一切正确,而!的要点是标记这些地方.

I don't love this approach, though I've used it in a few places. I don't think it gives you any safety over the ! (it won't crash, but you'll almost certainly give you subtle behavioral bugs, and I'd rather the crash). This is a place where the programmer must pay attention because the compiler is powerful enough to prove everything's correct, and the point of ! is to mark those places.

这篇关于在super.init调用之前初始化非可选属性,而无需复制代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆