考虑这个myFilter
函数,它接受泛型参数并根据谓词过滤数组。这与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
}
即使在后一个例子中,我们也不是达到了泛型的地步吗?
答案 0 :(得分:77)
泛型是类型安全的,这意味着如果你将字符串作为泛型传递并尝试使用整数,编译器会抱怨并且你将无法编译你的(这很好)。 (这是因为Swift正在使用静态类型,并且能够为您提供编译器错误 )
如果使用AnyObject,编译器不知道该对象是被视为String还是Integer。它可以让你随心所欲地做任何事情(这很糟糕)。
e.g。如果你尝试传递一个String 它之前使用过的Integer,应用程序将崩溃。 (这是因为Swift使用动态类型并且仅
泛型基本上告诉编译器:
“我稍后会给你一个类型,我希望你强制执行 键入我指定的任何地方。“
AnyObject基本上告诉编译器:
“不要担心这个变量不需要强制执行任何类型让我做任何我想做的事。”
答案 1 :(得分:14)
注意:Icaro的答案仍然是接受的答案,我只是在扩展他的解释。
TL; DR :检查Icaro的答案。
关于AnyObject
Icaro的用法正确地说:
不要担心这个变量不需要在这里强制执行任何类型 我做任何我想做的事。
这是什么意思?我们来看一下问题中的代码示例(我已经上升并将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
。如果仔细观察,源数组的内容可以是任何内容。封闭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)
哇,那有效,不是吗?满脸笑容?没有。
注意如何:
return (a as! Int) % 2 == 0
我强行向下a
。如果a
不是Int
,则此行会崩溃。但它的用法是合理的;毕竟,我们只想过滤掉Int
,我很聪明,只使用Int
s的数组。
但是,因为说,我是一个天真的程序员,我这样做:
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"]
......有问题,我们不会发生车祸。我马上就修好了!
原来,有。泛型。再次引用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)
这个新过滤器很棒。它不会让我这样做:
let evens = myFilter(source: ints, predicate:predicate)
因为predicate
和source
的类型不匹配。编译时间错误。
泛型是通用的:在这个特定的例子中 - 在编写myFilter
函数时,你不需要给出source
的类型或predicate
的参数。 {1}}需要,它是T,它是任何东西。但是,一旦我说source
是一个任意数组,你必须确保predicate
接受的论点是相同的。在我们之前的ANYTHING1,ANYTHING2命名法的背景下,我们可以说泛型强迫ANYTHING1等于ANYTHING2
答案 2 :(得分:1)
考虑在第一个函数T中不是一个类型,就像AnyObject一样,但是类型变量;这意味着在第一个函数中,您可以将任何类型的值数组作为第一个参数传递,但谓词仅对 特定类型的值作为第二个参数进行操作。也就是说,您可以在字符串上传递字符串和谓词数组,或者在整数上传递整数数组和谓词,而不能在字符串上传递整数数组和谓词。因此,函数的主体保证对于类型的关注是正确的。
相反,在第二个示例中,您可以传递任何类型的值和一个对任何(可能不同的!)类型进行操作的谓词,这样,如果谓词将在函数体中调用,其值为第一个参数,然后可能发生动态类型错误。幸运的是,Swith类型检查器将谓词的调用标记为类型错误,以防止这种可能性。