Swift - укажите соответствие протоколу параметра типа c - PullRequest
2 голосов
/ 22 апреля 2020

То, что я пытаюсь сделать, - это иметь два обобщенных параметра типа c, где один является указанным c типом, а другой - протоколом, подобным следующему:

@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
    }

}

Таким образом, фактический тип может быть скрыт и иметь доступ только к протоколу.

Теперь это не работает, потому что P - это не классовый, не протокольный тип, поэтому T не может быть ограничен этим.

Есть ли способ обойти это?

Ответы [ 3 ]

1 голос
/ 22 апреля 2020

Я думаю, что вы можете создать протокол для наследования T, тогда вам вообще не понадобится P:

protocol ImplementationProtocol: AnyObject {}

@propertyWrapper
struct Implementation<T: ImplementationProtocol> { 

    var wrappedValue: ImplementationProtocol { projectedValue }

    var projectedValue: T

    init(_ instance: T) {
        self.projectedValue = instance
    }

}

теперь ваша буква "T" должна будет соответствовать "реализации протокола" и «wrappedValue» также должен соответствовать «реализации протокола», как вы пытались выполнить sh в своем коде выше.

надеюсь, что это поможет

0 голосов
/ 22 апреля 2020

То, что вы хотите, не является особенностью языка, поэтому ближайший вариант - это решение во время выполнения, которое сводит на нет некоторые свойства-оболочки-свойства.

@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 }
    }
  }
}
0 голосов
/ 22 апреля 2020
@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
    }

}
...