简体   繁体   English

具有关联值的枚举的多个键路径的动态成员查找

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

Implementing dynamic member lookup on an enum with associated values leads to build errors when there is more than one keypath function.当存在多个键路径 function 时,在具有关联值的枚举上实现动态成员查找会导致构建错误。

I have an enum with multiple associates values, as described below:我有一个包含多个关联值的枚举,如下所述:

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

The structs Movie and Book inherit protocols Filmed and Written , which themselves inherit from the more generic protocol Entertainment :结构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
}

So far, this works and has allowed me to access variables such as isbn and title , which are defined in Entertainment , from the top-level Media object through the subscript keypath lookup.到目前为止,这可行,并允许我通过下标 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)

Now, when I try to add the subscript function below in Media so that I can optionally access variables conforming to either Filmed or Written , I receive an error for the above print statements stating Ambiguous use of 'subscript(dynamicMember:)'现在,当我尝试在下面的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
    }
}

In this example, the build errors are as follows:在此示例中,构建错误如下:

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

When I remove the second subscript function, the build errors are gone.当我删除第二个下标 function 时,构建错误消失了。

Please let me know if I'm doing anything wrong in my implementation here.如果我在此处的实施中做错了什么,请告诉我。

Figured out the answer:想出了答案:

By changing Filmed and Written to no longer conform to Entertainment , the build errors were removed.通过将FilmedWritten更改为不再符合Entertainment ,构建错误被删除。 The code as following now works:以下代码现在可以工作:

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

Here is the output of the print statements:这是打印语句的 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