簡體   English   中英

`Identifiable` 一致性返回類型泛型作為變量

[英]`Identifiable` conformance return type generic as variable

背景:

我正在嘗試從 Apple 的此示例構建OutlineGrouphttps://developer.apple.com/documentation/swiftui/outlinegroup

但是,我不想使用 static 類型,而是想使用符合我的協議的對象。 因此,如果在 swift 中可行的話,這個問題就更籠統了:

問題:

我有協議,可以為我提供來自各種對象的coworkersname

protocol CastProtocol {
    var name: String { get }
    var coworkers: [CastProtocol]? { get } // here will be the build error later
}

並以兩個模型為例:

class Actor: Identifiable, CastProtocol {
    var id: Self { self }
    var name: String { return "Chuck Norris" }
    
    var coworkers: [CastProtocol]? {
        return [
            Director()
        ]
    }
}

class Director: Identifiable, CastProtocol {
    var id: Self { self }
    var name: String { return "Gina Carey" }
    
    var coworkers: [CastProtocol]? {
        return [
            Actor(),
            Director(),
            Actor()
        ]
    }
}

所以到目前為止一切正常,但我需要確保我的CastProtocol符合Identifiable ,因此將我的協議實現更改為:

protocol CastProtocol: Identifiable {
    ...
}

現在這產生了一個問題:

協議“CastProtocol”只能用作通用約束,因為它具有 Self 或關聯的類型要求

問題:

  1. 所以有一種方法可以在coworkers中返回不是 static 類型,或者我應該 go 子類化?
  2. 這是一個正確的方法嗎? 也許我唯一缺少的是在可識別的協議級別標識符要求中聲明? 但如果是這樣 - 怎么做?
  3. 我認為我不能真正使用 associatedType 的 go。 如果此示例中的coworkers可以包含ActorDirector associatedType 我認為不能使用

協議從不符合其他協議。 語法protocol CastProtocol: Identifiable並不意味着“CastProtocol 符合 Identifiable”。 它的意思是“為了符合 CastProtocol,一個類型也必須符合 Identifiable”。

但是,對於這個問題,不,您不能要求這樣做。 Identifiable包括一個關聯的類型ID 考慮這段代碼:

let coworker in coworkers {
    let id = coworker.id // What type is `id` here?
    ...
}

在這種情況下,Swift 無法分配單個類型類型id 有一天,他們可能會添加一個名為 Generalized Existential 的功能,該功能允許將id推斷為Any where Self: Hashable類型,但目前無法在 Swift 中表達。

但在你的情況下,它無論如何都無法工作。 說你可以做到這一點。 由於您已將標識符設置為 object 本身,因此系統最終需要評估Director == Actor 這在 Swift 中是不可能的。 那些不是同一類型。

相反,如果您真的希望 Cast 成員成為類,我懷疑您想要這個:

protocol CastMember: class {
    var name: String { get }
    var coworkers: [CastMember] { get } // Optional Arrays are almost always wrong
    var id: ObjectIdentifer { get }
}

extension CastMember {
    var id: ObjectIdentifier { ObjectIdentifier(self) }
}

// You can still put Identifiable here for [Actor] properties
class Actor: CastProtocol, Identifiable {
    // ...
}

現在,這不會讓您將這些直接放入ForEach(actor.coworkers)調用中,我認為這是您想要的。 就個人而言,我只是傳遞id: \.id參數,但如果你經常這樣做,你當然可以通過擴展使它更好一點:

extension ForEach where Content : View, Data.Element == CastMember {
    public init(_ data: Data, @ViewBuilder content: @escaping (Data.Element) -> Content) {
        self.init(data, id: \.id, content: content)
    }
}

注意Data.Element == CastMember不是: 這適用於 CastMember 數組,而不是符合 CastMember 的事物數組。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM