当可选参数可以具有不同类型时,不明确的Swift初始化器

时间:2016-11-28 17:43:49

标签: swift

现在我正在使用一个有很多可选属性的类。对于一些可选属性,我希望能够采用不同的类型,并且基本上将它们转换为我想要存储它的类型,以方便用户。例如,用户可以提供DateStringInt来指示特定日期。这是我正在尝试做的一个例子。 (忽略我正在做一个可能不安全的包装的事实。)

class SOExample {
    let value: Int
    let time: Double?

    init(value: Int, time: Double? = nil) {
        self.value = value
        self.time = time
    }

    convenience init(value: Int, time: Int? = nil) {
        if time != nil {
            self.init(value: value, time: Double(time!))
        } else {
            self.init(value: value, time: nil)
        }
    }
}

当我尝试在没有任何选项的情况下初始化时出现问题 - 它不知道要使用什么初始化程序。例如,SOExample(value: 7)在单元测试中将其返回:

error: ambiguous use of 'init(value:time:)'
        let soExample = SOExample(value: 7)
                        ^
<unknown>:0: note: found this candidate
<unknown>:0: note: found this candidate
<unknown>:0: error: build had 1 command failures

我怎样才能做我想做的事情?我是以完全错误的方式来做这件事的吗?我应该使用除多个初始值设定项之外的其他内容来执行此操作吗?

3 个答案:

答案 0 :(得分:1)

您可以通过删除其中一个初始化函数中不需要的参数来解决此问题。

答案 1 :(得分:0)

解决问题的最简单方法是在便捷方法中重命名第二个参数。当你传递nil导致你的问题时,两个初始化方法的签名是相同的。我不确定这是否适合你的情况。

class SOExample {
let value: Int
let time: Double?

init(value: Int, time: Double? = nil) {
    self.value = value
    self.time = time
}

convenience init(value: Int, timeAsInt: Int? = nil) {
    if timeAsInt != nil {
        self.init(value: value, time: Double(timeAsInt!))
    } else {
        self.init(value: value, time: nil)
    }
}

}

鉴于两种方法的签名是相同的,并且您不能对具有不同类型和默认值nil的第二个参数使用相同的标签,您可以为您的类创建一个静态方法,该方法将采用一种类型Any然后解决可能的情况。

    class SOExample {
    let value: Int
    let time: Double?




    init(value: Int, time: Double? = nil) {
        self.value = value
        self.time = time
    }

    static func make(value: Int, time: Any? = nil) -> SOExample {

        if time != nil {

            // Int
            if let timeInt = time as? Int {
                return SOExample(value: value, time: Double(timeInt))
            }

            // String
            if let timeString = time as? String {
                if let timeDouble = Double(timeString) {
                    return SOExample(value: value, time: timeDouble)
                }
            }
        }

        return SOExample(value: value)
    }
}

然后你会像这样使用它:

let exampleOne = SOExample.make(value: 4, time: 4)
let exampleTwo = SOExample.make(value: 4, time: "4")

答案 2 :(得分:0)

根据Eugene Zhenya Gordin的建议,可以通过删除convenience init初始化程序中的可选组件来解决此问题。如果我们只希望在time参数为Int时调用初始化程序,那么该变量应该成为该特定init所必需的。这解决了这种情况下的模糊性。

class SOExample {
    let value: Int
    let time: Double?

    init(value: Int, time: Double? = nil) {
        self.value = value
        self.time = time
    }

    convenience init(value: Int, time: Int) {
        self.init(value: value, time: Double(time))
    }
}

这并不允许我使用Int?作为参数类型,因为最终这看起来像是无法解决的模糊性。不妨强迫它,因为无论如何这对我的应用程序来说效果都不错。