Swift中泛型和AnyObject之间的区别

avi*_*ara 42 functional-programming ios swift

考虑这个myFilter函数,它接受泛型参数并根据谓词过滤数组.这与filter()Swift提供的功能相同.

func myFilter<T>(source: [T], predicate:(T) -> Bool) -> [T] {
  var result = [T]()
  for i in source {
    if predicate(i) {
      result.append(i)
    }
  }
  return result
}
Run Code Online (Sandbox Code Playgroud)

这有什么不同,

func myFilter(source: [AnyObject], predicate:(AnyObject) -> Bool) -> [AnyObject] {
  var result = [AnyObject]()
  for i in source {
    if predicate(i) {
      result.append(i)
    }
  }
  return result
}
Run Code Online (Sandbox Code Playgroud)

即使在后一个例子中,我们也不是达到了泛型的地步吗?

Ica*_*aro 80

泛型是类型安全的,这意味着如果您将字符串作为泛型传递并尝试使用整数,编译器将会抱怨并且您将无法编译您的(这很好).(这是因为Swift使用静态类型,并且能够给你编译错误)

如果使用AnyObject,编译器不知道该对象是否可以被视为String或Integer.它可以让你随心所欲地做任何事情(这很糟糕).

例如,如果您尝试在先前使用的Integer中传递String ,则应用程序将崩溃.(这是因为Swift使用动态类型并且只会给你一个运行时崩溃)

泛型基本上告诉编译器:

"我稍后会给你一个类型,我希望你在我指定的任何地方强制执行该类型."

AnyObject基本上告诉编译器:

"不要担心这个变量,不需要强制执行任何类型,让我做任何我想做的事情."

  • @Honey您可以将任何已知的`@objc`消息发送到类型为"AnyObject"的内容(它的行为与Obj-C的`id`非常相似) - 请参阅"[Dynamic Method Lookup](https://developer.apple.com) /library/content/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-ID42)"Swift with Cocoa和Objective-C指南的部分.虽然注意到这个答案很老,甚至在Swift 2正式发布之前就已经写好了. (2认同)

avi*_*ara 13

注意:Icaro的答案仍然是公认的答案,我只是在扩展他的解释.

TL; DR:检查Icaro的答案.

关于AnyObjectIcaro 的用法正确地说:

不要担心这个变量不需要强制执行任何类型这里让我做任何我想做的事情.

这是什么意思?让我们在这个问题的代码示例(我已经走了一步,并改变AnyObjectAny不改变这个问题的意思):

func myFilter(source: [Any], predicate:(Any) -> Bool) -> [Any] {
  var result = [Any]()
  for i in source {
    if predicate(i) {
      result.append(i)
    }
  }
  return result
}
Run Code Online (Sandbox Code Playgroud)

这意味着,该myFilter函数接受两个参数1 source和一个闭包predicate.如果仔细观察,源数组的内容可以是任何内容.封闭的论点predicate也可以是任何东西.如果我们要命名这些"ANYTHING" - 比如ANYTHING1和ANYTHING2 - 这种方法不要求ANYTHING1等于ANYTHING2.

让我们坐下来思考这个含义......

比如说,我们想要从整数数组中过滤出均衡,然后让我们使用我们的Any过滤器

var ints = [1,2,3,4,5] as [Any]
var predicate = { (a : Any) -> Bool in
    return (a as! Int) % 2 == 0
}

let evens = myFilter(source: ints, predicate:predicate)
Run Code Online (Sandbox Code Playgroud)

哇,那工作,不是吗?满脸笑容?没有.

注意如何在线:

return (a as! Int) % 2 == 0
Run Code Online (Sandbox Code Playgroud)

我强行低头a.如果a除了以外的任何东西,这条线会崩溃Int.但它的用法是合理的; 毕竟,我们想要过滤掉Ints,我很聪明,只使用一个Ints 数组.

但是,因为说,我是一个天真的程序员,我这样做:

var ints = [1,2,3,4,5,"6"] as [Any]
var predicate = { (a : Any) -> Bool in
    return (a as! Int) % 2 == 0
}

let evens = myFilter(source: ints, predicate:predicate)
Run Code Online (Sandbox Code Playgroud)

这很愉快地编译,但在运行时崩溃.如果只有一种方式,编译器会告诉我这一行......

var ints = [1,2,3,4,5,"6"]
Run Code Online (Sandbox Code Playgroud)

......错了,我们不会发生撞车事故.我马上就修好了!

事实证明,有.泛型.再次引用Icaro,

我稍后会给你一个类型,我希望你在我指定的任何地方强制执行该类型.

func myFilter<T>(source: [T], predicate:(T) -> Bool) -> [T] {
    var result = [T]()
    for i in source {
        if predicate(i) {
            result.append(i)
        }
    }
    return result
}

var ints = [1,2,3,4,5,6]
var predicate = { (a : Int) -> Bool in
    return a % 2 == 0
}

let evens = myFilter(source: ints, predicate:predicate)
Run Code Online (Sandbox Code Playgroud)

这个新的过滤器很棒.它不会让我这样做:

let evens = myFilter(source: ints, predicate:predicate)因为,类型predicatesource不匹配.编译时间错误.

泛型以这种方式是通用的:在这个特定的例子中 - 在编写myFilter函数时,你不需要给出一个类型source的参数或者参数predicate,它是T,它是任何东西.但是,一旦我说这source是一个任何数组,你必须确保predicate接受的论点是相同的.在我们之前的ANYTHING1,ANYTHING2命名法的背景下,我们可以说仿制药强制ANYTHING1等于ANYTHING2