模糊使用带有默认值的初始化函数

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

ambiguous use of init with default values

问题

以下是翻译好的部分:

我有一个类,它有两个看起来相似的初始化方法:

    public init(
            contentInsets: MyInsets = .init(vertical: .level0, horizontal: .level6),
            midToLeftSpacing: CGFloat = 0,
            rightToMidSpacing: CGFloat = 0
    )
    
    public init(
            contentInsets: MyInsets = .init(vertical: .level0, horizontal: .level6),
            midToLeftSpacing: MyInsetLevel = .level0,
            rightToMidSpacing: MyInsetLevel = .level0
    )

现在,我遇到了一个问题,似乎当我尝试调用初始化方法时,编译器无法确定选择哪一个:

    init(
    vertical: .level0,
    left: .level22,
    right: .level0
    )

会产生错误 - `Ambiguous use of 'init'`

可以通过修改初始化方法或添加带默认值的下一个参数来轻松解决,但这看起来不太合适,有没有其他方法来指定要调用的初始化方法?
英文:

I have class that have two similar looking initializers:

public init(
        contentInsets: MyInsets = .init(vertical: .level0, horizontal: .level6),
        midToLeftSpacing: CGFloat = 0,
        rightToMidSpacing: CGFloat = 0
)

public init(
        contentInsets: MyInsets = .init(vertical: .level0, horizontal: .level6),
        midToLeftSpacing: MyInsetLevel = .level0,
        rightToMidSpacing: MyInsetLevel = .level0
)

Now i run into problem, looks like when i trying to call initializer compiler can't figure out which one to chose:

init(
vertical: .level0,
left: .level22,
right: .level0
)

Gives error - Ambiguous use of 'init'

It could be easily fixed with modifying initializer or adding next argument with default value, but it doesn't look right, is there any other way to specify init method called?

答案1

得分: 1

你的示例与你的代码不匹配(没有定义init(vertical:left:right)),所以我将尝试用一个避免额外类型的完整示例来概括这个问题。我将只使用Double和Int。

想象一个结构体X,它在内部存储三个Double:

struct X {
    var x: Double
    var y: Double
    var z: Double
    init(x: Double = 0, y: Double = 0, z: Double = 0) {
        self.x = x
        self.y = y
        self.z = z
    }
}

你还想能够传递三个Int,但三个值必须都是Double或Int,并且你希望有默认值。**每次使用默认值只是一个具有较少参数的额外方法的缩写。**为了避免冲突,你需要至少包含一个参数作为非默认值:

extension X {
    init(x: Int, y: Int = 0, z: Int = 0) {
        self.init(x: Double(x), y: Double(y), z: Double(z))
    }
    init(y: Int, z: Int = 0) { self.init(x: 0, y: y, z: z) }
    init(z: Int) { self.init(x: 0, y: 0, z: z) }
}

现在,每种组合都是合法的,但没有歧义。

当只有一种额外的初始化方式时,这很好。但也许你希望有多种方式。然后,协议是有用的。例如,这种方法允许每个参数都可以是Int或Double:

protocol XParameter {
    var xParameterValue: Double { get }
}

extension Double: XParameter {
    var xParameterValue: Double { self }
}

extension Int: XParameter {
    var xParameterValue: Double { Double(self) }
}

struct X {
    var x: Double
    var y: Double
    var z: Double
    init(x: some XParameter = 0, y: some XParameter = 0, z: some XParameter = 0) {
        self.x = x.xParameterValue
        self.y = y.xParameterValue
        self.z = z.xParameterValue
    }
}
英文:

Your example doesn't match your code (there is no init(vertical:left:right) defined), so I'm going to try to generalize this problem a bit with a full example that avoids the extra types. I'll just use Double and Int here.

Imagine a struct X that internally stores three Doubles:

struct X {
    var x: Double
    var y: Double
    var z: Double
    init(x: Double = 0, y: Double = 0, z: Double = 0) {
        self.x = x
        self.y = y
        self.z = z
    }
}

You also want to be able to pass three Ints instead, but all three must either be Doubles or Ints, and you want default values. Every use of default values is just a shorthand for an extra method with fewer parameters. To avoid conflicts, you need to include at least one of the parameters as non-default:

extension X {
    init(x: Int, y: Int = 0, z: Int = 0) {
        self.init(x: Double(x), y: Double(y), z: Double(z))
    }
    init(y: Int, z: Int = 0) { self.init(x: 0, y: y, z: z) }
    init(z: Int) { self.init(x: 0, y: 0, z: z) }
}

Now, every combination is legal, but there are no ambiguities.

This is nice when there's just one extra way to call the init. But maybe you want there to be many. Then a protocol is useful. For example, this approach allows either Int or Double for every parameter:

protocol XParameter {
    var xParameterValue: Double { get }
}

extension Double: XParameter {
    var xParameterValue: Double { self }
}

extension Int: XParameter {
    var xParameterValue: Double { Double(self) }
}

struct X {
    var x: Double
    var y: Double
    var z: Double
    init(x: some XParameter = 0, y: some XParameter = 0, z: some XParameter = 0) {
        self.x = x.xParameterValue
        self.y = y.xParameterValue
        self.z = z.xParameterValue
    }
}

huangapple
  • 本文由 发表于 2023年2月14日 03:04:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/75440201.html
匿名

发表评论

匿名网友

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

确定