如何避免在Swift中拼写复杂类型?

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

How to avoid spelling a complex type in Swift?

问题

这是使用SwiftUI时出现的问题,但实际上是有关Swift类型的基本问题。尝试创建如下的视图:

  1. struct BorderedRectangle1: View {
  2. let gesture: Gesture
  3. init(color: Color, border: Bool) {
  4. self.gesture = TapGesture().modifiers(.option).onEnded {
  5. // do something
  6. }.simultaneously(with: TapGesture().modifiers(.command).onEnded {
  7. // do something else
  8. })
  9. }
  10. var body: some View {
  11. Rectangle()
  12. .gesture(gesture)
  13. }
  14. }

但这在let gesture: Gesture上不能编译,出现错误 Use of protocol 'Gesture' as a type must be written 'any Gesture'. Replace 'Gesture' with 'any Gesture'

通过将 let gesture: Gesture 替换为 let gesture: any Gesture,可以消除上述错误,但在body中的 Rectangle() 上会出现另一个错误:Type 'any Gesture' cannot conform to 'Gesture'.

我可以通过将gesture属性更改为计算属性来“修复”它:

  1. var gesture: some Gesture {
  2. TapGesture().modifiers(.option).onEnded {
  3. // do something
  4. }.simultaneously(with: TapGesture().modifiers(.command).onEnded {
  5. // do something else
  6. })
  7. }

我明白编译器必须能够在声明和使用位置都能够推断出类型。那么如何在保持gesture的声明为存储属性且不拼写显式类型的情况下使其工作呢?

  1. let gesture: ?? // <= 在这里填入什么?
英文:

This is coming up while using SwiftUI bit it really is a fundamental Swift question about types. Trying to have a view like so:

  1. struct BorderedRectangle1: View {
  2. let gesture: Gesture
  3. init(color: Color, border: Bool) {
  4. self.gesture = TapGesture().modifiers(.option).onEnded {
  5. // do something
  6. }.simultaneously(with: TapGesture().modifiers(.command).onEnded {
  7. // do something else
  8. })
  9. }
  10. var body: some View {
  11. Rectangle()
  12. .gesture(gesture)
  13. }
  14. }

but this doesn't compile with Use of protocol 'Gesture' as a type must be written 'any Gesture'. Replace 'Gesture' with 'any Gesture'

Replacing let gesture: Gesture => let gesture: any Gesture eliminates the above error but another error appears on Rectangle() in the body: Type 'any Gesture' cannot conform to 'Gesture'.

I was able to "fix" it by making the gesture property computed:

  1. var gesture: some Gesture {
  2. TapGesture().modifiers(.option).onEnded {
  3. // do something
  4. }.simultaneously(with: TapGesture().modifiers(.command).onEnded {
  5. // do something else
  6. }) }

I get it that the compiler must be able to infer a type in both the declaration and use sites. So how to make it work while keeping the declaration of gesture as a stored property and without spelling the explicit type which is SimultaneousGesture&lt;_EndedGesture&lt;_ModifiersGesture&lt;TapGesture&gt;&gt;, _EndedGesture&lt;_ModifiersGesture&lt;TapGesture&gt;&gt;&gt;

  1. let gesture: ?? // &lt;= what goes in here?

答案1

得分: 0

你需要声明一个泛型类型,该类型将是存储属性的类型。该泛型类型必须符合 Gesture

这里是一个编译通过的代码示例:

  1. // 创建一个符合 Gesture 的泛型类型
  2. struct BorderedRectangle1<G: Gesture>: View {
  3. // 属性的类型是 G
  4. let gesture: G
  5. init(color: Color, border: Bool) {
  6. self.gesture = TapGesture().modifiers(.option).onEnded {
  7. // 做一些事情
  8. }.simultaneously(with: TapGesture().modifiers(.command).onEnded {
  9. // 做另一些事情
  10. }) as! G // 确保 gesture 的类型是 G
  11. }
  12. var body: some View {
  13. Rectangle()
  14. .gesture(gesture)
  15. }
  16. }

如果你需要将手势传递给 View,以下是如何实现的示例:

  1. // 创建一个符合 Gesture 的泛型类型
  2. struct BorderedRectangle1<G: Gesture>: View {
  3. // 属性的类型是 G
  4. let gesture: G
  5. // 参数的类型是 G
  6. init(gesture: G) {
  7. self.gesture = gesture
  8. }
  9. var body: some View {
  10. Rectangle()
  11. .gesture(gesture)
  12. }
  13. }
英文:

You need to declare a generic type, which will be the type of the stored property. That generic type must conform to Gesture.

Here's a code that compiles:

  1. // Create a generic type that conforms to Gesture
  2. struct BorderedRectangle1&lt;G: Gesture&gt;: View {
  3. // The property is of type G
  4. let gesture: G
  5. init(color: Color, border: Bool) {
  6. self.gesture = TapGesture().modifiers(.option).onEnded {
  7. // do something
  8. }.simultaneously(with: TapGesture().modifiers(.command).onEnded {
  9. // do something else
  10. }) as! G // Ensure the gesture is of type G
  11. }
  12. var body: some View {
  13. Rectangle()
  14. .gesture(gesture)
  15. }
  16. }

If you need to pass a gesture to the View, here's how it works:

  1. // Create a generic type that conforms to Gesture
  2. struct BorderedRectangle1&lt;G: Gesture&gt;: View {
  3. // The property is of type G
  4. let gesture: G
  5. // The parameter is of type G
  6. init(gesture: G) {
  7. self.gesture = gesture
  8. }
  9. var body: some View {
  10. Rectangle()
  11. .gesture(gesture)
  12. }
  13. }

huangapple
  • 本文由 发表于 2023年5月29日 22:26:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76358160.html
匿名

发表评论

匿名网友

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

确定