簡體   English   中英

具有關聯值的枚舉的多個鍵路徑的動態成員查找

[英]Dynamic member lookup with multiple keypaths for enums with associated values

當存在多個鍵路徑 function 時,在具有關聯值的枚舉上實現動態成員查找會導致構建錯誤。

我有一個包含多個關聯值的枚舉,如下所述:

@dynamicMemberLookup
enum Media {
    case movie(Movie)
    case book(Book)
    
    subscript<T>(dynamicMember keyPath: KeyPath<Entertainment, T>) -> T {
        switch self {
            case .movie(let movie):
                return movie[keyPath: keyPath]
            case .book(let book):
                return book[keyPath: keyPath]
        }
    }
}

結構MovieBook繼承協議FilmedWritten ,它們本身繼承自更通用的協議Entertainment

protocol Entertainment {
    var isbn: Int { get }
    var title: String { get }
    var sales: Int { get set }
}

protocol Written: Entertainment {
    var author: String { get }
}

protocol Filmed: Entertainment {
    var actors: [String] { get set }
}

struct Movie: Filmed {
    var isbn: Int
    var title: String
    var sales: Int
    var actors: [String]
}

struct Book: Written {
    var isbn: Int
    var title: String
    var sales: Int
    var author: String
}

到目前為止,這可行,並允許我通過下標 keypath 查找從頂級Media object 訪問在Entertainment中定義的變量,例如isbntitle

let media: Media = .movie(Movie(isbn: 1011, title: "Top Gun", sales: 1000, actors: ["Tom Cruise", "Miles Teller"]))

print(media.title)
print(media.sales)

現在,當我嘗試在下面的Media中添加下標 function 以便我可以選擇訪問符合FilmedWritten的變量時,我收到上述打印語句的錯誤,說明Ambiguous use of 'subscript(dynamicMember:)'

subscript<T>(dynamicMember keyPath: KeyPath<Filmed, T>) -> T? {
    switch self {
        case .movie(let movie):
            return movie[keyPath: keyPath]
        default:
            return nil
    }
}

在此示例中,構建錯誤如下:

let media: Media = .movie(Movie(isbn: 1011, title: "Top Gun", sales: 1000, actors: ["Tom Cruise", "Miles Teller"]))

print(media.title) // BUILD ERROR: Ambiguous use of 'subscript(dynamicMember:)'
print(media.sales) // BUILD ERROR: Ambiguous use of 'subscript(dynamicMember:)'
print(media.actors) // This doesn't throw an error and successfully logs

當我刪除第二個下標 function 時,構建錯誤消失了。

如果我在此處的實施中做錯了什么,請告訴我。

想出了答案:

通過將FilmedWritten更改為不再符合Entertainment ,構建錯誤被刪除。 以下代碼現在可以工作:

protocol Entertainment {
    var isbn: Int { get }
    var title: String { get }
    var sales: Int { get set }
}

protocol Written {
    var author: String { get }
}

protocol Filmed {
    var actors: [String] { get set }
}

struct Movie: Entertainment, Filmed {
    var isbn: Int
    var title: String
    var sales: Int
    var actors: [String]
}

struct Book: Entertainment, Written {
    var isbn: Int
    var title: String
    var sales: Int
    var author: String
}

@dynamicMemberLookup
enum Media {
    case movie(Movie)
    case book(Book)
    
    subscript<T>(dynamicMember keyPath: KeyPath<Entertainment, T>) -> T {
        switch self {
            case .movie(let movie):
                return movie[keyPath: keyPath]
            case .book(let book):
                return book[keyPath: keyPath]
        }
    }

    subscript<T>(dynamicMember keyPath: KeyPath<Filmed, T>) -> T? {
        switch self {
            case .movie(let movie):
                return movie[keyPath: keyPath]
            default:
                return nil
        }
    }
}

這是打印語句的 output:

let media: Media = .movie(Movie(isbn: 1011, title: "Top Gun", sales: 1000, actors: ["Tom Cruise", "Miles Teller"]))

print(media.title) // OUTPUT: "Tom Cruise"
print(media.sales) // OUTPUT: 1000
print(media.actors) // OUTPUT: Optional<[String]>: ["Tom Cruise", "Miles Teller"]

暫無
暫無

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

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