通过协议传递类型参数?

时间:2014-06-28 15:14:19

标签: generics swift

我尝试使用泛型实现以下用例的解决方案:

有一个对话框类,对话框用于从列表中选择一个项目。 Dialog必须是通用的,所以我为这些项目创建了一个协议,例如列表中使用的标签,以及" delegate"的协议,用于处理被点击的项目。

该对话框将点击的项目传递给代理人。由于我使用泛型,我的想法是我不得使用强制转换来获取具有正确类型的项目(更准确地说是项目中包含的模型对象)。我在游乐场文件中准备了一个自包含的示例,以说明我的意思。

这不会编译,因为我没有将该项目放下。

我可以用Java解决这个问题 - 刚刚实现它,DialogListener和DialogItem都有类型参数<T>,所以我可以在声明/实例化中传递<Student> int,在监听器中我接收参数{{ 1}}因此不需要向下倾斜。

我怀疑可能无法在Swift中执行此操作,因为我在文档中看不到任何可用内容,但我希望我错了...

为了说清楚,问题是,如何实现这一点,作为通用解决方案,而不必使用任何演员?

DialogItem<Student>

这是Java代码,可以按我的意愿运行:

///////////////////////////////////////////////////////
// Model class

class Student {
    let name:String

    init(name:String) {
        self.name = name
    }
}

///////////////////////////////////////////////////////
// Dialog item, this wraps the model class

protocol DialogItem {

    typealias T

    func getLabel() -> String

    func getModel() -> T
}

///////////////////////////////////////////////////////
// Implementation of dialog item "wrapper" for student

class StudentDialogItem : DialogItem {

    let student:Student

    init(student:Student) {
        self.student = student
    }

    func getLabel() -> String {
        return student.name
    }

    func getModel() -> Student {
        return student
    }
}


///////////////////////////////////////////////////////
// Listener
// ---> how can I pass T to DialogListener and then to DialogItem, to get items with correct type?

protocol DialogListener {


    func onItemSelected(item:DialogItem)
}


///////////////////////////////////////////////////////
// Dialog, with "dummy" functionality

class ItemSelectionDialog {
    let items:[DialogItem]
    let listener:DialogListener

    init (items:[DialogItem], listener:DialogListener) {
        self.items = items
        self.listener = listener
    }

    func show() {
        for item in items {
            println(item.getLabel())
        }
    }

    func simulateClick(index:Int) {
        listener.onItemSelected(items[index])
    }
}

///////////////////////////////////////////////////////
// Implementation of dialog listener

class DialogListenerImpl : DialogListener {

    func onItemSelected(item: DialogItem)  {
        let student:Student = item.getModel() //<---- DialogItem doesn't have type information, compiler doesn't even seem to recognise getModel()!
        //do something with student
        println("Selected a student!, name: " + student.name)
    }
}



///////////////////////////////////////////////////////

let items:[Student] = [Student(name: "Student1-name"), Student(name: "Student2-name"), Student(name: "Student3-name")]

let listener = DialogListenerImpl()

let studentDialogItems:[StudentDialogItem] = items.map({StudentDialogItem(student: $0)})

let dialog = ItemSelectionDialog(items: studentDialogItems, listener: listener)

dialog.show()

dialog.simulateClick(1)

1 个答案:

答案 0 :(得分:0)

不支持协议中的通用类型。但item.getModel()Student的实现中的Java和Swift代码中都知道onSelectedItem返回onItemSelected(DialogItem<Student> item)的事实。在Java代码中,您可以将其声明为泛型类型系统let student:Student = item.getModel() as Student 的一部分。在Swift代码中,您可以使用:

{{1}}

这不令人满意,但有效。