关于在协议扩展中使用Self关键字和不透明返回类型Some的问题。

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

Question about using Self keyword and opaque return type Some in protocol extensions

问题

在上面的代码部分中,作者指出,为了添加协议扩展以具有平方功能,我们可以使用 Self 关键字,以便引用调用 Numeric 类型的具体类型(例如 int、double)。然而,我想知道是否可以将 Self 直接替换为 some Numeric?这样做是否也能达到相同的效果,因为编译器可以在调用 squared() 时确定正在引用的确切类型?这些调用之间有什么区别?

英文:

I am beginning to learn some Swift at the moment and I have been following the 100 Days of Swift on Hacking with Swift (Day 13). I have a question about using the Self keyword.

extension Numeric {
    func squared() -> Self {
        self * self
    }
}

In the above section of code, the author notes that to add the protocol extension to have squared functionality we can use the Self keyword so that the specific type (i.e. int, double) of the calling Numeric type is referenced. However, I was wondering could we just replace Self with some Numeric instead? Would that also accomplish the same task because the compiler could figure out what exact type was being referenced in this instance when squared() is called? What is the difference between these calls?

答案1

得分: 1

Sure, here's the translated content:

但我在想,我们是否可以只用 some Numeric 替换 Self

是的,但仅仅是在扩展本身仍然能够编译的意义上。编译器确实可以看到 self * self 是类型为 Self 的表达式,而 Self 显然符合 Numeric,因此可以在返回 some Numeric 的方法中返回。

然而,squared 的调用者可能会出现问题,这就是区别所在。

some 的概念是调用者不知道返回的实际类型是什么。如果你返回 Self,调用者就能够保证 x.squared()x 具有相同的类型。但是对于 some Numeric,调用者只知道 squared 返回符合 Numeric 的类型,但不知道具体是哪种类型。

这意味着可以像这样实现 squared(尽管这没有任何意义):

extension Numeric { 
    func squared() -> some Numeric { 
        Date().timeIntervalSince1970
    } 
}

毕竟,timeIntervalSince1970 返回 TimeInterval,它也是 Numeric

示例:

func doSomethingWithInts(_ x: Int) { ... }

let x = 2
let y = x.squared() // 如果 squared 返回 "some Numeric"...
print(y.bitWidth) // 这是不允许的
doSomethingWithInts(y) // 这也是不允许的

毕竟,squared 可以被实现为返回任何特定的符合 Numeric 的类型,不一定是与 x 相同的类型。如果它返回 TimeInterval 呢?那里没有 bitWidth

另一方面,如果 squared 返回 Self,那么调用者知道 yInt,原因是 xInt,你可以做所有上面所示的那些不允许做的事情。

请注意,尽管调用者不知道 some Numeric 的具体类型是什么,但它确实知道它每次都是相同的类型。例如,这是有效的:

let a = 2
let b = 3
var x = a.squared() // 调用 Int 上的 squared 返回 "some Numeric"
// 下面的调用返回的 Numeric 类型与 a.squared() 相同
// 因为 b 也是 Int,所以允许赋值
x = b.squared() 
print(x)

这有点偏题,但上述内容就是区分 some Numericany Numeric 的方法。

阅读更多关于 some 的内容在这篇帖子中

英文:

> However, I was wondering could we just replace Self with some Numeric instead?

Yes, but only in the sense that the extension itself will still compile. The compiler can indeed see that self * self is an expression of type Self, and Self trivially conforms to Numeric, and so can be returned in a method returning some Numeric.

However, callers of squared will probably break, and that is where the difference is.

The idea of some is that callers don't know what the actual type returned is. If you were returning Self, the caller has the guarantee that x.squared() is the same type as x. But with some Numeric, the caller only knows that squared returns a type conforming to Numeric, but doesn't know which specific type it is.

This means that it is possible to implement squared like this (not that this makes any sense):

extension Numeric { 
    func squared() -> some Numeric { 
        Date().timeIntervalSince1970
    } 
}

After all, timeIntervalSince1970 returns TimeInterval. which is also Numeric.

Example:

func doSomethingWithInts(_ x: Int) { ... }

let x = 2
let y = x.squared() // if squared returns "some Numeric"...
print(y.bitWidth) // this is not allowed
doSomethingWithInts(y) // nor is this

After all. squared could be implemented to return any specific Numeric-conforming type, not necessarily the same type as x. What if it returned TimeInterval? There is no bitWidth there.

If squared returned Self on the other hand, then the caller knows that y is Int, for the reason that x is Int, and you can do all those things shown above that you were not allowed to do.

Note that although the caller doesn't know what specific type some Numeric is, it does know that it is the same type every time. For example, this works:

let a = 2
let b = 3
var x = a.squared() // calling squared on Int returns "some Numeric"
// the Numeric type returned by the call below is the same type as a.squared()
// because b is also Int, so the assignment is allowed
x = b.squared() 
print(x)

This is a bit off-topic, but the above is what differentiates some Numeric and any Numeric.

Read more about some in this post.

答案2

得分: 1

你可以使用 some Numeric,但它提供了一个较弱的保证:

extension Numeric {
    func squared() -> some Numeric {
      // 仅为示例,忽略细节
      // 不透明返回类型始终为 `Int`,与 `Self` 无关。
      123
    }
}

let iThoughtThisWouldBeADouble = 2.0.squared()

print(type(of: iThoughtThisWouldBeADouble)) // 惊喜,它是一个 Int。

在这个示例中,squared() 可以 返回与 self 相同的类型,但如示例所示,它没有义务这样做。Self(在此示例中为 Double)只是满足 some Numeric 的一个示例,但任何其他符合 Numeric 协议的类型(如 Int)也可以适用。

英文:

You could use some Numeric, but it's a weaker guarentee:

extension Numeric {
    func squared() -> some Numeric {
      // Just a dummy implementation, ignore the details
      // The opaque return type is always an `Int`, regardless of `Self`.
      123
    }
}

let iThoughtThisWouldBeADouble = 2.0.squared()

print(type(of: iThoughtThisWouldBeADouble)) // Surprise, it's an Int.

In this example, squared() can return the same type as self, but it's not obligated to, as shown. Self (Double in this example) is just one example that satisfies some Numeric, but any other Numeric-conforming type (like Int) can also fit.

huangapple
  • 本文由 发表于 2023年6月6日 09:28:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/76410896.html
匿名

发表评论

匿名网友

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

确定