Swift中与关联类型的子句歧义的通用

时间:2022-09-16 14:35:09

I was writing some example code in a playground and wanted a function that returns the distance between two values, both of which conform to the Strideable protocol in Swift so that I could use the distance(to other: Self) -> Self.Stride function. My implementation was as follows:

我在操场上写了一些示例代码,想要一个函数返回两个值之间的距离,这两个值都符合Swift中的Strideable协议,这样我就可以使用距离(对其他:Self) - > Self.Stride函数。我的实施如下:

func distanceFrom<T: Strideable, U>(_ a: T, to b: T) -> U where T.Stride == U
{
    return a.distance(to: b)
}

After observing this function for a while, I realized that I wasn't sure which Stride was being used in the where clause, the one from a or from b. From what I understand it would be possible for a and b to define different associated types for Stride. Also I haven't made any statements to ensure that a.Stride == b.Stride, although I understand that I could expand my where clause to do so.

在观察了这个函数一段时间之后,我意识到我不确定在where子句中使用了哪个Stride,来自a或b的那个。根据我的理解,a和b可以为Stride定义不同的关联类型。此外,我没有做任何声明来确保a.Stride == b.Stride,虽然我知道我可以扩展我的where子句来这样做。

So, which one would get used to check equivalence to U? To be clear, the question isn't about this particular code block, but rather any situation in which this ambiguity would exist.

那么,哪一个会习惯于检查与U的等价?需要明确的是,问题不在于这个特定的代码块,而在于存在这种模糊性的任何情况。

1 个解决方案

#1


1  

a and b are the same type. If you wanted them to be different Strideable types you would add another generic parameter conforming to Strideable such that the function signature appears as follows:

a和b是相同的类型。如果您希望它们是不同的Strideable类型,您将添加符合Strideable的另一个通用参数,以便函数签名如下所示:

func bar<T: Strideable, V: Strideable, U>(_ a: T, to b: V) -> U where T.Stride == U, V.Stride == U {
  return a.distance(to: a) //Trivial return statement (see explanation below)
}

Although the aforementioned code would compile, return a.distance(to: b) would not compile because they (a and b) are different types and the definition of distance in Swift3 is public func distance(to other: Self) -> Self.Stride (note the use of Self which restricts other to the same type as the Strideable upon which this function is called). In conclusion, although you could make a and b different types, for your application it would not make sense to do so.

虽然上面的代码会编译,但返回a.distance(to:b)不会编译,因为它们(a和b)是不同的类型,Swift3中距离的定义是公共函数距离(对于其他:Self) - > Self。 Stride(注意使用Self,将其他类型限制为与调用此函数的Strideable相同的类型)。总而言之,尽管你可以制作一个和另外两种类型,但对于你的应用来说,这样做是没有意义的。

As further evidence for not being able to call your original posted code with different types please see the attached Playground screenshot which shows an error when using different types.

作为无法使用不同类型调用原始发布代码的进一步证据,请参阅随附的Playground屏幕截图,其中显示使用不同类型时的错误。

However, this works fine in the playground.

但是,这在操场上很好用。

func distanceFrom<T: Strideable, U>(_ a: T, to b: T) -> U where T.Stride == U {
  return a.distance(to: b)
}


let doubleFoo: Double = 4.5
let intFoo: Double = 4

let g = distanceFrom(doubleFoo, to: intFoo) // gives me a double of -0.5

I hope this helps.

我希望这有帮助。

#1


1  

a and b are the same type. If you wanted them to be different Strideable types you would add another generic parameter conforming to Strideable such that the function signature appears as follows:

a和b是相同的类型。如果您希望它们是不同的Strideable类型,您将添加符合Strideable的另一个通用参数,以便函数签名如下所示:

func bar<T: Strideable, V: Strideable, U>(_ a: T, to b: V) -> U where T.Stride == U, V.Stride == U {
  return a.distance(to: a) //Trivial return statement (see explanation below)
}

Although the aforementioned code would compile, return a.distance(to: b) would not compile because they (a and b) are different types and the definition of distance in Swift3 is public func distance(to other: Self) -> Self.Stride (note the use of Self which restricts other to the same type as the Strideable upon which this function is called). In conclusion, although you could make a and b different types, for your application it would not make sense to do so.

虽然上面的代码会编译,但返回a.distance(to:b)不会编译,因为它们(a和b)是不同的类型,Swift3中距离的定义是公共函数距离(对于其他:Self) - > Self。 Stride(注意使用Self,将其他类型限制为与调用此函数的Strideable相同的类型)。总而言之,尽管你可以制作一个和另外两种类型,但对于你的应用来说,这样做是没有意义的。

As further evidence for not being able to call your original posted code with different types please see the attached Playground screenshot which shows an error when using different types.

作为无法使用不同类型调用原始发布代码的进一步证据,请参阅随附的Playground屏幕截图,其中显示使用不同类型时的错误。

However, this works fine in the playground.

但是,这在操场上很好用。

func distanceFrom<T: Strideable, U>(_ a: T, to b: T) -> U where T.Stride == U {
  return a.distance(to: b)
}


let doubleFoo: Double = 4.5
let intFoo: Double = 4

let g = distanceFrom(doubleFoo, to: intFoo) // gives me a double of -0.5

I hope this helps.

我希望这有帮助。