Swift中的异构通用容器 [英] Heterogeneous generic container in Swift

查看:131
本文介绍了Swift中的异构通用容器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在将具有通用类型的结构放入一个数组时遇到问题.我知道Swift将Array的元类型转换为具体类型,这就是冲突.我试图找到其他解决方案,但我认为需要您的帮助.

I have a problem to put structs with a generic type in one array. I know that Swift converts the meta type of an Array into a concrete type and that this is the conflict. I tried to find a different solution but I think I need your help.

在此定义结构和协议:

protocol ItemProtocol {
    var id: String { get }
}

struct Section<T: ItemProtocol> {
    var items: [T]
    var renderer: Renderer<T>
}

struct Renderer<T> {
    var title: (T) -> String
}

以下是实现ItemProtocol的两个示例结构:

Here two example structs that implement the ItemProtocol:

struct Book: ItemProtocol {
    var id: String
    var title: String
}

struct Car: ItemProtocol {
    var id: String
    var brand: String
}

这是我设置部分的方式:

This is how i setup the sections:

let book1 = Book(id: "1", title: "Foo")
let book2 = Book(id: "2", title: "Bar")
let books = [book1, book2]
let bookSection = Section<Book>(items: books, renderer: Renderer<Book> { (book) -> String in
    return "Book title: \(book.title)"
})
let car1 = Car(id: "1", brand: "Foo")
let car2 = Car(id: "2", brand: "Bar")
let cars = [car1, car2]
let carSection = Section<Car>(items: cars, renderer: Renderer<Car> { (car) -> String in
    return "Car brand: \(car.brand)"
})

现在,我想将各个部分放在一起.这是我尝试过的.但是,这三行中的每行都会给我一个错误:

Now i want to put the sections together. Here is what i tried. But each of these 3 lines give me an error:

let sections: [Section<ItemProtocol>] = [bookSection, carSection]
let sections2: [Section] = [bookSection, carSection]
let sections3: [Section<AnyObject: ItemProtocol>] = [bookSection, carSection]

sections.forEach({ section in
    section.items.forEach({ item in
        let renderedTitle = section.renderer.title(item)
        print("\(renderedTitle)")
    })
})

对于sections数组的声明,我得到此错误:

For the declaration of the sections array i get this error:

不支持将"ItemProtocol"用作符合协议"ItemProtocol"的具体类型

Using 'ItemProtocol' as a concrete type conforming to protocol 'ItemProtocol' is not supported

对于sections2数组的声明,此错误:

For the declaration of the sections2 array this error:

无法将"Section"类型的值转换为预期的元素"Section"类型

Cannot convert value of type 'Section' to expected element type 'Section'

然后sections3抛出该错误:

预期为'>',以完成通用参数列表

Expected '>' to complete generic argument list

推荐答案

问题是不同的Section类型(具有不同的通用参数)之间没有共同点(Any除外).一种可能的解决方案是将所有Section类型统一为一个协议,并使用该协议来构建数组:

The problem is there is no common ground (excepting Any) between different Section types (with different generic arguments). One possible solution would be to unify all Section types into one protocol, and use that protocol to build the array:

protocol SectionProtocol {
    var genericItems: [ItemProtocol] { get }
    var renderedTitles: [String] { get }
}

extension Section: SectionProtocol {
    var genericItems: [ItemProtocol] { return items }
    var renderedTitles: [String] {
        return items.map { renderer.title($0) }
    }
}

let sections: [SectionProtocol] = [bookSection, carSection]

sections.forEach { section in
    section.renderedTitles.forEach { renderedTitle in
        print("\(renderedTitle)")
    }
}

因此,您无需遍历元素,而是遍历渲染的标题,每个部分都应能够构造这些标题.

So instead of iterating through the elements, you iterate through the rendered titles, which each section should be able to construct.

现在这解决了您的问题的基本用例,但是,取决于您在应用程序中使用的部分,可能还不够,因此您必须依靠键入橡皮擦,如其他答复者所述.

Now this addresses the basic use case from your question, however depending on you use the section in your app it might not be enough and you'll have to recourse to type erasers, as other answerers mentioned.

这篇关于Swift中的异构通用容器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆