[英]Swift - Specify conformity to a protocol of a generic type parameter
What I'm trying to do is to have two generic type parameters where one is a specific type and the other a protocol like so:我想要做的是有两个泛型类型参数,其中一个是特定类型,另一个是协议,如下所示:
@propertyWrapper
struct Implementation<T, P> where T : AnyObject, T : P { // Compiler error
var wrappedValue: P { projectedValue }
var projectedValue: T
init(_ instance: T) {
self.projectedValue = instance
}
}
This way, the actual type can be hidden and have only the protocol exposed.这样,可以隐藏实际类型,只暴露协议。
Now this doesn't work because P
is a non-class, non-protocol type, so T
cannot be constrained to it.现在这不起作用,因为
P
是非类、非协议类型,所以T
不能被限制在它上面。
Is there a way around this?有没有解决的办法?
I think you can create a protocol for T to inherit from, then you wouldn't need the P at all:我认为你可以为 T 创建一个协议来继承,那么你根本不需要 P :
protocol ImplementationProtocol: AnyObject {}
@propertyWrapper
struct Implementation<T: ImplementationProtocol> {
var wrappedValue: ImplementationProtocol { projectedValue }
var projectedValue: T
init(_ instance: T) {
self.projectedValue = instance
}
}
now your "T" will have to conform to "ImplementationProtocol" and "wrappedValue" will also have to conform to "ImplementationProtocol" as you tried to accomplish in your code above.现在您的“T”必须符合“ImplementationProtocol”,“wrappedValue”也必须符合“ImplementationProtocol”,正如您在上面的代码中试图完成的那样。
hope it helps希望能帮助到你
@propertyWrapper
struct Implementation<T, P> where T : AnyObject{
var wrappedValue: P? = nil
var projectedValue: T {
didSet {
if let value = projectedValue as? P {
wrappedValue = value
}
}
}
init(_ instance: T) {
self.projectedValue = instance
}
}
What you want is not a feature of the language, so your closest option is a runtime solution that negates some property wrapper sugar.你想要的不是语言的特性,所以你最接近的选择是一个运行时解决方案,它否定了一些属性包装糖。
@propertyWrapper
struct Implementation<Object: AnyObject, Protocol> {
init(_ projectedValue: Object) throws {
if let error = CastError.Desired(projectedValue, Protocol.self)
{ throw error }
self.projectedValue = projectedValue
}
var projectedValue: Object
var wrappedValue: Protocol { projectedValue as! Protocol }
}
protocol Protocol { }
class Class: Protocol { init() { } }
struct Struct {
@Implementation<Class, Protocol> var implementation: Protocol
init() throws {
_implementation = try .init( .init() )
}
}
public enum CastError {
/// An error that represents that an desired cast is not possible.
public struct Desired<Instance, DesiredCast>: Error {
/// `nil` if `instance` is a `DesiredCast`.
/// - Parameter instance: Anything. 🤷
public init?(_ instance: Instance, _: DesiredCast.Type) {
if instance is DesiredCast
{ return nil }
}
}
/// An error that represents that an undesired cast is possible.
public struct Undesired<Instance, UndesiredCast>: Error {
/// `nil` if `instance` is not an `UndesiredCast`.
/// - Parameter instance: Anything. 🤷
/// - Note: Ineffective if `instance` is a protocol instance
/// and `UndesiredCast` is `AnyObject`.
public init?(_ instance: Instance, _: UndesiredCast.Type) {
guard type(of: instance) is UndesiredCast.Type
else { return nil }
}
}
}
I believe you are approaching the entire problem in a way that is causing far too much abstraction, making it difficult to find a solution because the definition of the problem is not based in a real world use case.我相信您正在以一种导致太多抽象的方式处理整个问题,从而难以找到解决方案,因为问题的定义不是基于现实世界的用例。
Going back to basic principles.回到基本原则。 A protocol is defined as "a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality."
协议被定义为“适合特定任务或功能的方法、属性和其他要求的蓝图”。
You want to define P as a protocol with some kind of function.您想将 P 定义为具有某种 function 的协议。
It would be good to take a step back and understand what it is you a trying to achieve with your property wrapper.退后一步并了解您尝试使用属性包装器实现的目标是一件好事。
Comment: Property wrappers are rarely effective and I have yet to see a good use of them outside very concrete cases, like SwiftUI.评论:属性包装器很少有效,我还没有看到在非常具体的情况下很好地使用它们,比如 SwiftUI。 They are a language extension feature that dramatically limits what you can do with a particular variable.
它们是一种语言扩展功能,极大地限制了您可以对特定变量执行的操作。 Unless you have a really good architecture around it, property wrappers are rarely an effective choice in solving a problem.
除非你有一个非常好的架构,否则属性包装器很少是解决问题的有效选择。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.