英文:
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
,那么调用者知道 y
是 Int
,原因是 x
是 Int
,你可以做所有上面所示的那些不允许做的事情。
请注意,尽管调用者不知道 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 Numeric
和 any 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论