【问题标题】:Cannot assign to generic property in protocol无法分配给协议中的通用属性
【发布时间】:2017-04-05 06:30:35
【问题描述】:

我想知道我在这段代码中是否遗漏了一些简单的东西,或者它只是 Swift 诡计的混合,阻止了我做我想做的事。

我允许实现Foo 协议的类型包含任何类型的entity 属性,只要它符合StringIdentifiable

protocol StringIdentifiable {
  var id: String? { get }
}

protocol Foo: class {
  associatedtype AnyStringIdentifiable: StringIdentifiable
  var entity: AnyStringIdentifiable? { get set }
}

从 Swift 3.1 开始,如果不使用 associatedtype,则此“任何类型”部分 wouldn't be possible。继续,假设我有另一个需要Foo 属性的协议。但是,Foo 是通用的,所以您可能知道我们不能这样做,因为 “通用协议只能用作通用约束”。为了避免类型擦除混乱,我决定在我的第二个协议中使用另一个 associatedtype 并且编译器不会抱怨:

protocol Bar {
  //var foo: Foo { get set } // can't do because Foo is generic
  associatedtype AnyFoo: Foo
  var foo: AnyFoo { get set }
}

但是现在,如果我尝试在foo 中设置某些内容,编译器会报错:

extension Bar {
  func setEntity(_ entity: StringIdentifiable) {
    foo.entity = entity
  }
}

错误是无法将类型“StringIdentifiable”的值分配给类型“_?”

注意:这个问题的代码可以在操场上测试。

【问题讨论】:

    标签: swift generics


    【解决方案1】:

    你可以这样做

    //: Playground - noun: a place where people can play
    
    import Cocoa
    
    protocol StringIdentifiable {
        var id: String? { get }
    }
    
    protocol Foo: class {
        associatedtype AnyStringIdentifiable: StringIdentifiable
        var entity: AnyStringIdentifiable? { get set }
    }
    
    protocol Bar {
        //var foo: Foo { get set } // can't do because Foo is generic
        associatedtype AnyFoo: Foo
        var foo: AnyFoo { get set }
    }
    
    extension Bar {
        func setEntity(_ entity: AnyFoo.AnyStringIdentifiable) {
            foo.entity = entity
        }
    }
    

    在 Bar 中,您可以在设置 foo.entity 时使用 AnyFoo.AnyStringIdentifiable 来确保类型正确,因为 foo.entity 的类型是 AnyFoo.AnyStringIdentifiable

    【讨论】:

    • 这只是类型系统帮助你!想一想 - 对于给定的 Bar,您知道它有一个 AnyFoo,即 FooAnyFoo 有一个 AnyStringIdentifiable,他始终是 StringIdentifiable。仅仅因为两个东西都是AnyFoo,并不意味着它们都共享相同的AnyStringIdentifiable。因此,从Bar 的角度来看,您没有足够的知识来了解您需要哪种类型的StringIdentifiable。但是Bar 知道它有什么类型的Foo,而Foo 知道它有什么类型的StringIdentifiable。所以你必须这样解决它:AnyFoo.AnyStringIdentifiable.
    • 现在我不同意这一点……首先,任何东西都是关联类型。我不喜欢我能够在协议本身之外引用这些类型的事实。能够从 Bar 内部调用 AnyStringIdentifiable 非常奇怪。其次,我相信从 Bar 的角度来看有足够的知识,Bar 知道它有一些东西是 Foo,而 Foos 有一些东西是 StringIdentifiable。他们前面有“Any”(作为关联类型)这一事实使它更加通用(尽管如果解决了 SR-522,则不需要它)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-10
    • 2017-08-24
    • 1970-01-01
    • 2020-11-17
    • 2014-12-03
    • 1970-01-01
    • 2022-08-15
    相关资源
    最近更新 更多