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

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

How to avoid spelling a complex type in Swift?

问题

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

struct BorderedRectangle1: View {
  let gesture: Gesture

  init(color: Color, border: Bool) {
    self.gesture = TapGesture().modifiers(.option).onEnded {
      // do something
    }.simultaneously(with: TapGesture().modifiers(.command).onEnded {
      // do something else
    })
  }

  var body: some View {
    Rectangle()
      .gesture(gesture)
  }
}

但这在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属性更改为计算属性来“修复”它:

  var gesture: some Gesture {
    TapGesture().modifiers(.option).onEnded {
      // do something
    }.simultaneously(with: TapGesture().modifiers(.command).onEnded {
      // do something else
    })  
  }

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

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:

struct BorderedRectangle1: View {
  let gesture: Gesture

  init(color: Color, border: Bool) {
    self.gesture = TapGesture().modifiers(.option).onEnded {
      // do something
    }.simultaneously(with: TapGesture().modifiers(.command).onEnded {
      // do something else
    })
  }

  var body: some View {
    Rectangle()
      .gesture(gesture)
  }
}

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:

  var gesture: some Gesture {
    TapGesture().modifiers(.option).onEnded {
      // do something
    }.simultaneously(with: TapGesture().modifiers(.command).onEnded {
      // do something else
    })  }

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;

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

答案1

得分: 0

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

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

// 创建一个符合 Gesture 的泛型类型
struct BorderedRectangle1<G: Gesture>: View {
    
    // 属性的类型是 G
    let gesture: G
    
    init(color: Color, border: Bool) {
        self.gesture = TapGesture().modifiers(.option).onEnded {
            // 做一些事情
        }.simultaneously(with: TapGesture().modifiers(.command).onEnded {
            // 做另一些事情
        }) as! G        // 确保 gesture 的类型是 G
    }
    
    var body: some View {
        Rectangle()
            .gesture(gesture)
    }
}

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

// 创建一个符合 Gesture 的泛型类型
struct BorderedRectangle1<G: Gesture>: View {
    
    // 属性的类型是 G
    let gesture: G
    
    // 参数的类型是 G
    init(gesture: G) {
        self.gesture = gesture
    }
    
    var body: some View {
        Rectangle()
            .gesture(gesture)
    }
}
英文:

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:


// Create a generic type that conforms to Gesture
struct BorderedRectangle1&lt;G: Gesture&gt;: View {
    
    // The property is of type G
    let gesture: G
    
    init(color: Color, border: Bool) {
        self.gesture = TapGesture().modifiers(.option).onEnded {
            // do something
        }.simultaneously(with: TapGesture().modifiers(.command).onEnded {
            // do something else
        }) as! G        // Ensure the gesture is of type G
    }
    
    var body: some View {
        Rectangle()
            .gesture(gesture)
    }
}

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

// Create a generic type that conforms to Gesture
struct BorderedRectangle1&lt;G: Gesture&gt;: View {
    
    // The property is of type G
    let gesture: G
    
    // The parameter is of type G
    init(gesture: G) {
        self.gesture = gesture
    }
    
    var body: some View {
        Rectangle()
            .gesture(gesture)
    }
}

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:

确定