Swift(UI)中的some关键字是什么? [英] What is the `some` keyword in Swift(UI)?
问题描述
新的 SwiftUI教程具有以下代码:
struct ContentView: View {
var body: some View {
Text("Hello World")
}
}
第二行单词some
及其在其网站上被突出显示,就像它是关键字一样.
The second line the word some
, and on their site is highlighted as if it were a keyword.
Swift 5.1似乎没有以some
作为关键字,而且我看不到some
这个词还有什么作用,因为它通常出现在类型所在的地方.是否有Swift的未发布新版本?是否以我不知道的方式在类型上使用了该函数?
Swift 5.1 does not appear to have some
as a keyword, and I don't see what else the word some
could be doing there, since it goes where the type usually goes. Is there a new, unannounced version of Swift? Is it a function that's being used on a type in a way I didn't know about?
关键字some
有什么作用?
推荐答案
some View
是 "noreferrer"> SE-0244 ,可在带有Xcode 11的Swift 5.1中使用.您可以将其视为反向"通用占位符.
some View
is an opaque result type as introduced by SE-0244 and is available in Swift 5.1 with Xcode 11. You can think of this as being a "reverse" generic placeholder.
与调用方可以满足的常规通用占位符不同:
Unlike a regular generic placeholder which is satisfied by the caller:
protocol P {}
struct S1 : P {}
struct S2 : P {}
func foo<T : P>(_ x: T) {}
foo(S1()) // Caller chooses T == S1.
foo(S2()) // Caller chooses T == S2.
不透明的结果类型是实现满足的隐式通用占位符,因此您可以考虑一下:
An opaque result type is an implicit generic placeholder satisfied by the implementation, so you can think of this:
func bar() -> some P {
return S1() // Implementation chooses S1 for the opaque result.
}
看起来像这样:
func bar() -> <Output : P> Output {
return S1() // Implementation chooses Output == S1.
}
实际上,此功能的最终目标是允许采用这种更明确的形式的反向泛型,这也将使您添加约束,例如-> <T : Collection> T where T.Element == Int
. 有关详细信息,请参阅此帖子.
In fact, the eventual goal with this feature is to allow reverse generics in this more explicit form, which would also let you add constraints, e.g -> <T : Collection> T where T.Element == Int
. See this post for more info.
要摆脱的主要问题是,返回some P
的函数是返回符合P
的特定 single 具体类型的值的函数.尝试在函数中返回不同的符合类型会产生编译器错误:
The main thing to take away from this is that a function returning some P
is one that returns a value of a specific single concrete type that conforms to P
. Attempting to return different conforming types within the function yields a compiler error:
// error: Function declares an opaque return type, but the return
// statements in its body do not have matching underlying types.
func bar(_ x: Int) -> some P {
if x > 10 {
return S1()
} else {
return S2()
}
}
因为隐式通用占位符不能由多种类型满足.
As the implicit generic placeholder cannot be satisfied by multiple types.
这与返回P
的函数相反,该函数可以用来表示两者 S1
和S2
,因为它表示任意P
符合值:
This is in contrast to a function returning P
, which can be used to represent both S1
and S2
because it represents an arbitrary P
conforming value:
func baz(_ x: Int) -> P {
if x > 10 {
return S1()
} else {
return S2()
}
}
好吧,那么不透明结果类型-> some P
相对于协议返回类型-> P
有什么好处?
Okay, so what benefits do opaque result types -> some P
have over protocol return types -> P
?
当前协议的主要限制是PAT(具有关联类型的协议)不能用作实际类型.尽管此限制可能会在该语言的将来版本中取消,但由于不透明的结果类型实际上只是通用的占位符,因此它们现在可以与PATs一起使用.
A major current limitation of protocols is that PATs (protocols with associated types) cannot be used as actual types. Although this is a restriction that will likely be lifted in a future version of the language, because opaque result types are effectively just generic placeholders, they can be used with PATs today.
这意味着您可以执行以下操作:
This means you can do things like:
func giveMeACollection() -> some Collection {
return [1, 2, 3]
}
let collection = giveMeACollection()
print(collection.count) // 3
2.不透明的结果类型具有身份
由于不透明的结果类型强制返回单个具体类型,因此编译器知道对同一函数的两次调用必须返回相同类型的两个值.
2. Opaque result types have identity
Because opaque result types enforce a single concrete type is returned, the compiler knows that two calls to the same function must return two values of the same type.
这意味着您可以执行以下操作:
This means you can do things like:
// foo() -> <Output : Equatable> Output {
func foo() -> some Equatable {
return 5 // The opaque result type is inferred to be Int.
}
let x = foo()
let y = foo()
print(x == y) // Legal both x and y have the return type of foo.
这是合法的,因为编译器知道x
和y
具有相同的具体类型.这是 ==
的一项重要要求,其中两个参数均为
This is legal because the compiler knows that both x
and y
have the same concrete type. This is an important requirement for ==
, where both parameters of type Self
.
protocol Equatable {
static func == (lhs: Self, rhs: Self) -> Bool
}
这意味着它期望两个值都与具体符合类型相同.即使Equatable
可用作类型,您也无法将两个任意的Equatable
符合值相互比较,例如:
This means that it expects two values that are both the same type as the concrete conforming type. Even if Equatable
were usable as a type, you wouldn't be able to compare two arbitrary Equatable
conforming values with each other, for example:
func foo(_ x: Int) -> Equatable { // Assume this is legal.
if x > 10 {
return 0
} else {
return "hello world"
}
}
let x = foo(20)
let y = foo(5)
print(x == y) // Illegal.
由于编译器无法证明两个任意Equatable
值具有相同的基础具体类型.
As the compiler cannot prove that two arbitrary Equatable
values have the same underlying concrete type.
以类似的方式,如果我们引入了另一个不透明的类型返回函数:
In a similar manner, if we introduced another opaque type returning function:
// foo() -> <Output1 : Equatable> Output1 {
func foo() -> some Equatable {
return 5 // The opaque result type is inferred to be Int.
}
// bar() -> <Output2 : Equatable> Output2 {
func bar() -> some Equatable {
return "" // The opaque result type is inferred to be String.
}
let x = foo()
let y = bar()
print(x == y) // Illegal, the return type of foo != return type of bar.
该示例变得非法,因为尽管foo
和bar
都返回some Equatable
,但是它们的反向"通用占位符Output1
和Output2
可以由不同的类型来满足.
The example becomes illegal because although both foo
and bar
return some Equatable
, their "reverse" generic placeholders Output1
and Output2
could be satisfied by different types.
与常规协议类型的值不同,不透明结果类型与常规通用占位符的组合很好,例如:
Unlike regular protocol-typed values, opaque result types compose well with regular generic placeholders, for example:
protocol P {
var i: Int { get }
}
struct S : P {
var i: Int
}
func makeP() -> some P { // Opaque result type inferred to be S.
return S(i: .random(in: 0 ..< 10))
}
func bar<T : P>(_ x: T, _ y: T) -> T {
return x.i < y.i ? x : y
}
let p1 = makeP()
let p2 = makeP()
print(bar(p1, p2)) // Legal, T is inferred to be the return type of makeP.
如果makeP
刚刚返回了P
,则此方法将无效,因为两个P
值可能具有不同的基础具体类型,例如:
This wouldn't have worked if makeP
had just returned P
, as two P
values may have different underlying concrete types, for example:
struct T : P {
var i: Int
}
func makeP() -> P {
if .random() { // 50:50 chance of picking each branch.
return S(i: 0)
} else {
return T(i: 1)
}
}
let p1 = makeP()
let p2 = makeP()
print(bar(p1, p2)) // Illegal.
为什么在具体类型上使用不透明的结果类型?
这时您可能在想自己,为什么不将代码编写为:
Why use an opaque result type over the concrete type?
At this point you may be thinking to yourself, why not just write the code as:
func makeP() -> S {
return S(i: 0)
}
好吧,使用不透明的结果类型使您可以通过仅公开P
提供的接口来使类型S
成为实现细节,从而使您可以灵活地在以后更改具体类型而无需中断任何操作取决于功能的代码.
Well, the use of an opaque result type allows you to make the type S
an implementation detail by exposing only the interface provided by P
, giving you flexibility of changing the concrete type later down the line without breaking any code that depends on the function.
例如,您可以替换:
func makeP() -> some P {
return S(i: 0)
}
具有:
func makeP() -> some P {
return T(i: 1)
}
而不会破坏任何调用makeP()
的代码.
without breaking any code that calls makeP()
.
请参见语言指南的不透明类型"部分和 Swift进化提案以获取更多信息关于此功能.
See the Opaque Types section of the language guide and the Swift evolution proposal for further information on this feature.
这篇关于Swift(UI)中的some关键字是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!