swift中泛型和 Any 类型

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了swift中泛型和 Any 类型相关的知识,希望对你有一定的参考价值。

参考技术A 除了泛型,Swift 还支持 Any 类型,它能代表任何类型的值。从表面上看,这好像和泛型极其相似。Any 类型和泛型两者都能用于定义接受两个不同类型参数的函数。然而,理解两者之间的区别至关重要:泛型可以用于定义灵活的函数,类型检查仍然由编译器负责;而 Any 类型则可以避开 Swift 的类型系统 (所以应该尽可能避免使用)。

让我们考虑一个最简单的例子,构想一个函数,除了返回它的参数,其它什么也不做。如果使用泛型,我们可能写为下面这样:

而使用 Any 类型,则可能写为这样:

“noOp 和 noOpAny 两者都将接受任意参数。关键的区别在于我们所知道的返回值。在 noOp 的定义中,我们可以清楚地看到返回值和输入值完全一样。而 noOpAny 的例子则不太一样,返回值是任意类型 — 甚至可以是和原来的输入值不同的类型。我们可以给出一个 noOpAny 的错误定义,如下所示:

使用 Any 类型可以避开 Swift 的类型系统。然而,尝试将使用泛型定义的 noOp 函数返回值设为 0 将会导致类型错误。此外,任何调用 noOpAny 的函数都不知道返回值会被转换为何种类型。而结果就是可能导致各种各样的运行时错误。”

NSManagedObjectContext 扩展中泛型函数中的奇怪 Swift 行为

【中文标题】NSManagedObjectContext 扩展中泛型函数中的奇怪 Swift 行为【英文标题】:Strange Swift behavior in generic function in NSManagedObjectContext extension 【发布时间】:2015-07-10 09:43:07 【问题描述】:

我目前正在使用 Swift 开发一个 iOS 项目,并且正在尝试使用 Swift 泛型和协议在 NSManagedObjectContext 之上构建某种扩展。我已经实现了一些方法,如下所示:

extension NSManagedObjectContext 

   func objectWhere<T: NSManagedObject>(entityClass: T.Type, predicate: NSPredicate) -> T? 
       let entityName = NSStringFromClass(entityClass)
       let request = NSFetchRequest(entityName: entityName)

       //...fetch object code here

       return result?.first
   

这个方法很好用,但是当我想实现一个 upsert 时,棘手的问题就来了。基本上我正在做的是创建一个像这样的协议:

protocol Updatable 
     static func primaryKeyJSON() -> String

     static func primaryKey() -> String

     func populate(JSON: [NSObject: AnyObject], context: NSManagedObjectContext)

     func update(JSON: [NSObject: AnyObject], context: NSManagedObjectContext)

接下来我要做的是用这个协议扩展我的一个 NSManagedObject 子类。例如,在我当前的项目中,我有一个名为 Person 的类,它实现了这个协议。这个协议应该允许我在同一个 NSManagedObjectContext 扩展中创建一个 upsert 方法,如下所示:

func upsert<T where T: NSManagedObject, T: Updatable>(entityClass: T.Type, JSON: [NSObject: AnyObject]) -> T? 
    return nil

但问题是,每当我调用此方法时,Xcode 都会报错:“预期的成员名称或类型名称后的构造函数调用”。

c.upsert(Person, JSON: ["test": "sometest"])

然而,最奇怪的是,这个问题的第一种方法效果很好。此外,当我从 upsert 函数中删除 JSON: 参数时,它不会给出该错误并且编译和运行完全正常。

谁能告诉我这是怎么回事?

【问题讨论】:

我无法解释为什么,但如果你写 upsert(Person.self ... 我会编译。可能值得一试。 嗯确实可以编译,奇怪的是所有其他方法都可以在没有 .self 的情况下工作。我会检查我是否可以提交雷达。谢谢! 【参考方案1】:

我认为类/结构或协议的类型不会隐式返回它的类型。但是,当您的函数中只有一个参数(例如 T.Type)时,就会发生这种情况。

Apples Swift Library 是这样说的:

您可以使用后缀 self 表达式将类型作为值访问。例如,SomeClass.self 返回 SomeClass 本身,而不是 SomeClass 的实例。 SomeProtocol.self 返回 SomeProtocol 本身,而不是在运行时符合 SomeProtocol 的类型的实例。

这将来可能会改变,我的手指也交叉。但是现在,当您的函数中有多个参数时,您必须输入self 后缀。

protocol SomeProtocol 

func someFunc1<T: SomeProtocol>(_: T.Type) -> String  "\(T.self)" 
func someFunc2<T: SomeProtocol>(_: T.Type, someInt: Int) -> String  "\(T.self) + \(someInt)"

extension Int : SomeProtocol 

someFunc1(Int) // returns "Swift.Int" <--- this is a bug
someFunc1(Int.self) // returns "Swift.Int"

someFunc2(Int, someInt: 42) // Expected memeber name or constructer call after type name
someFunc2(Int.self, someInt: 42) // returns "Swift.Int + 42"

顺便说一句。我认为您可以像这样修改您的代码:

func objectWhere<T: NSManagedObject>(_: T.Type, predicate: NSPredicate) -> T? 
    let entityName = "\(T.self)"
    /* ... */

更新:这个问题只是一个错误,阅读here:

【讨论】:

以上是关于swift中泛型和 Any 类型的主要内容,如果未能解决你的问题,请参考以下文章

Swift - 泛型

Swift - 泛型

NSManagedObjectContext 扩展中泛型函数中的奇怪 Swift 行为

swift 使用值类型泛型和内存指针进行队列

0513 泛型和学生信息

0513 泛型和学生信息