Swift   发布时间:2022-03-31  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了swift – 通用类型集合大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

概述

在之前的问题得到解决的基础上,但它导致了另一个问题.如果协议/类类型存储在集合中,则检索并实例化它们会引发错误.一个假设的例子如下.该范例基于“程序到接口而不是实现” what does it mean to “program to an interface”? instantiate from protocol.Type reference dynamically at runtime publ
在之前的问题得到解决的基础上,但它导致了另一个问题.如果协议/类类型存储在集合中,则检索并实例化它们会引发错误.一个假设的例子如下.该范例基于“程序到接口而不是实现” What does it mean to “program to an interface”?

instantiate from protocol.Type reference dynamically at runtime

public protocol ISpeakable {
    init()
    func speak()
}

class Cat : ISpeakable {
    required init() {}
    func speak() {
        println("Meow");
    }
}

class Dog : ISpeakable {
    required init() {}
    func speak() {
        println("Woof");
    }
}

//Test class is not aware of the specific implementations of ISpeakable at compile time
class Test {
    func instantiateAndCallSpeak<T: ISpeakable>(Animal:T.TypE) {
        let animal = Animal()
        animal.speak()
    }
}

// Users of the Test class are aware of the specific implementations at compile/runtime

//works
let t = test()
t.instantiateAndCallSpeak(Cat.self)
t.instantiateAndCallSpeak(Dog.self)

//doesn't work if types are retrieved from a collection
//Uncomment to show Error - IAnimal.Type is not convertible to T.Type
var animals: [ISpeakable.Type] = [Cat.self,Dog.self,Cat.self]

for animal in animals {
    //t.instantiateAndCallSpeak(animal) //throws error
}

for (index:Int,value:ISpeakable.TypE) in enumerate(animals) {
    //t.instantiateAndCallSpeak(value) //throws error
}

编辑 – 我目前的解决方法是迭代集合,但当然它是有限的,因为api必须知道各种各样的实现.另一个限制是这些类型的子类(例如PersianCat,GeRMANShepherd)将不会调用它们的重写函数,或者我将转到Objective-C进行救援(NSClassFromString等)或等待SWIFT支持功能.

注意(背景):实用程序的用户将这些类型推送到数组中,并在通知时执行for循环

var animals: [ISpeakable.Type] = [Cat.self,Cat.self]

for Animal in animals {
    if Animal is Cat.Type {
        if let AnimalClass = Animal as? Cat.Type {
            var instance = AnimalClass()
            instance.speak()
        }
    } else if Animal is Dog.Type {
        if let AnimalClass = Animal as? Dog.Type {
            var instance = AnimalClass()
            instance.speak()
        }
    }
}
基本上答案是:正确,你不能这样做. Swift需要在编译时确定类型参数的具体类型,而不是在运行时.这出现在许多小角落案件中.例如,您无法构造通用闭包并将其存储在变量中而不指定类型.

如果我们将其归结为最小的测试用例,这可能会更清楚一些

protocol Creatable { init() }

struct Object : Creatable { init() {} }

func instantiate<T: Creatable>(Thing: T.TypE) -> T {
    return Thing()
}

// works. object is of type "Object"
let object = instantiate(Object.self)   // (1)

// 'Creatable.Type' is not convertible to 'T.Type'
let type: Creatable.Type = Object.self
let thing = instantiate(typE)  // (2)

在第1行,编译器有一个问题:在这个实例化实例中T应该是什么类型?这很容易,它应该是对象.这是一个具体的类型,所以一切都很好.

在第2行,没有Swift可以制作的具体类型T.它只有Creatable,这是一个抽象类型(我们通过代码检查知道类型的实际值,但Swift不虑值,只是类型) .获取和返回协议是可以的,但是将它们变成类型参数是不可行的.今天,斯威夫特不合法.

这在Swift Programming Language: Generic Parameters and Arguments中暗示:

你需要做任何你想在Swift中做另一种方式的事情.

作为一个有趣的奖金,尝试明确要求不可能:

let thing = instantiate(Creatable.self)

并且…迅速崩溃.

从您的进一步评论中,我认为闭包完全符合您的要求.你已经使你的协议需要简单的构造(init()),但这是一个不必要的限制.您只需要调用者告诉函数如何构造对象.使用闭包很容易,并且不需要以这种方式进行类型参数化.这不是一个解决方法;我相信这是实现您所描述的模式的更好方法.请虑以下内容(一些小的更改,使示例更像Swift):

// Removed init(). There's no need for it to be trivially creatable.
// Cocoa protocols that inDicate a method generally end in "ing" 
// (NSCopying,NSCoding,NSLocking). They do not include "I"
public protocol Speaking {
    func speak()
}

// Converted these to structs since that's all that's required for
// this example,but it works as well for classes.
struct Cat : Speaking {
    func speak() {
        println("Meow");
    }
}

struct Dog : Speaking {
    func speak() {
        println("Woof");
    }
}

// Demonstrating a more complex object that is easy with closures,// but hard with your original protocol
struct Person: Speaking {
    let name: String
    func speak() {
        println("My name is \(Name)")
    }
}

// Removed Test class. There was no need for it in the example,// but it works fine if you add it.
// You pass a closure that returns a Speaking. We don't care *how* it does
// that. It doesn't have to be by construction. It Could return an exisTing one.
func instantiateAndCallSpeak(builder: () -> Speaking) {
    let animal = builder()
    animal.speak()
}

// Can call with an immediate form.
// Note that Cat and Dog are not created here. They are not created until builder()
// is called above. @autoclosure would avoid the braces,but I typically avoid it.
instantiateAndCallSpeak { Cat() }
instantiateAndCallSpeak { Dog() }

// Can put them in an array,though we do have to specify the type here. You Could
// create a "typealias SpeakingBuilder = () -> Speaking" if that came up a lot.
// Again note that no Speaking objects are created here. these are closures that
// will generate objects when applied.
// Notice how easy it is to pass parameters here? these don't all have to have the
// same initializers.
let animalBuilders: [() -> Speaking] = [{ Cat() },{ Dog() },{ Person(name: "Rob") }]

for animal in animalBuilders {
    instantiateAndCallSpeak(animal)
}

大佬总结

以上是大佬教程为你收集整理的swift – 通用类型集合全部内容,希望文章能够帮你解决swift – 通用类型集合所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。