generics和Swift中的AnyObject之间的区别

考虑这个myFilter函数,它接受一个generics参数,并根据谓词过滤数组。 这与Swift提供的filter()函数是一样的。

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

这与以往有什么不同,

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

即使在后一个例子中,我们是不是也能达到generics的地步呢?

generics是types安全的,这意味着如果你传递一个string作为一个通用的,并尝试使用整数编译器会抱怨,你将无法编译你的(这是好的)。 (这是因为Swift使用静态types ,并能够给你一个编译器错误

如果使用AnyObject,编译器不知道该对象是否可以被当作String或Integer。 它将允许你做任何你想要的(这是不好的)。

例如,如果您尝试传递一个string时,它以前使用整数应用程序将崩溃。 (这是因为Swift使用dynamictypes只会给你一个运行时崩溃

generics基本上告诉编译器:

“我将在稍后给你一个types,我希望你在我指定的任何地方执行这种types 。”

AnyObject基本上告诉编译器:

“不要担心这个variables, 不需要在这里执行任何types的操作,让我做任何我想做的事情。”

:Icaro的答案仍然是被接受的答案,我只是扩大了他的解释。

TL; DR :检查Icaro的答案。

关于AnyObject Icaro的用法AnyObject得好:

不要担心这个variables,不需要在这里强制执行任何types的任何操作。

这是什么意思? 我们来看问题中的代码示例(我已经进行了一些改动,将AnyObject更改为Any而不改变问题的含义):

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

这意味着, myFilter函数需要两个参数一个source和一个闭包predicate 。 如果仔细观察,源数组的内容可以是任何东西。 closurespredicate的参数也可以是任意的。 如果我们要命名这些“任何东西” – 比如ANYTHING1和ANTHING2–这种方法不需要ANTHING1等于ANYTHING2。

让我们坐下来思考这个问题的意义

比方说,我们想从一个整数数组中筛选出evens,让我们使用我们的Anyfilter来实现这个

 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) 

哇,那工作,不是吗? 所有的笑容? 没有。

注意如何在行中:

 return (a as! Int) % 2 == 0 

我正在强制性地演出a 。 如果除了Int以外的其他任何东西,这行就会崩溃。 但是它的用法是合理的。 毕竟,我们只想过滤出Int而且我足够聪明,只需要使用Int数组。

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

 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) 

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

 var ints = [1,2,3,4,5,"6"] 

…是错误的,我们不会有一个崩溃。 我会马上解决它!

原来,有。 generics。 再次引用Icaro,

我将在稍后给你一个types,我希望你在我指定的任何地方执行这个types。

 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) 

这个新的filter真棒。 它不会让我这样做:

let evens = myFilter(source: ints, predicate:predicate)因为predicatesource的types不匹配。 编译时间错误。

generics是通用的:在这个特定的例子中 – 在编写myFilter函数的时候,你不需要给predicate的types或predicate所需的参数,它是T,它是任何东西。 但是,一旦我说source是一个任意数组,你必须确保predicate接受的参数是相同的。 在我们以前的ANYTHING1 ANYTHING2术语的背景下,我们可以说generics使得ANYTHING1等于ANYTHING2

考虑在第一个函数T 不是一个types,就像是AnyObject,而是一个typesvariables ; 这意味着在第一个函数中,您可以传递任何types的值的数组作为第一个参数,而谓词仅在特定types的值上作为第二个参数。 也就是说,你可以在string上传递一个string和一个谓词数组,或者一个整数数组和一个整数的谓词,而不能在string上传递一个整数数组和一个谓词。 所以,函数的主体是保证正确的types有关。

相反,在第二个例子中,可以传递任何types的值和一个操作任何(可能不同的!)types的谓词,这样,如果在函数体中用第一个参数的值调用谓词,那么可能会发生dynamictypes错误。 幸运的是,Swithtypes检查器将谓词的调用标记为types错误,以防止这种可能性。