ios-Swi中泛型和AnyObject之间的区别

考虑此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
}

即使在后面的示例中,我们也无法达到泛型的意义吗?

avismara asked 2020-08-08T22:32:23Z
3个解决方案
79 votes

泛型是类型安全的,这意味着如果您将字符串作为泛型传递并尝试将其用作整数,则编译器将抱怨并且您将无法编译您的(很好)。 (发生这种情况是因为Swift使用静态类型,并且能够给您一个编译器错误)

如果使用AnyObject,则编译器不知道该对象是否可以视为String或Integer。 它可以让您随心所欲地做(这很不好)。

例如 如果您尝试在以前使用的Integer字符串中传递字符串,则应用程序将崩溃。 (发生这种情况是因为Swift正在使用动态类型输入,只会给您造成运行时崩溃)

泛型基本上告诉编译器:

“我稍后再给您一个类型,我希望您强制执行 在我指定的任何地方键入。”

AnyObject基本上告诉编译器:

“不用担心这个变量,这里不需要强制任何类型,让我做我想做的事。”

Icaro answered 2020-08-08T22:32:56Z
13 votes

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

TL; DR:检查Icaro的答案。

关于myFilter Icaro的用法正确地提出了:

不用担心这个变量,这里不需要强制任何类型 我做我想做的一切。

这是什么意思? 让我们以问题中的代码示例为例(在不改变问题含义的情况下,我迈出了一步,将myFilter更改为source):

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。如果仔细看,源数组的内容可以是任何东西。 闭包source的参数也可以是任何东西。 如果我们将这些命名为“ ANYTHING”(例如ANYTHING1和ANYTHING2),则此方法不需要ANYTHING1等于ANYTHING2。

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

假设我们要从整数数组中滤除偶数,然后使用myFilter滤镜对此进行过滤

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

我正在强制向下广播myFilter。如果source不是predicate以外的其他行,则此行将崩溃。 毕竟,我们只想过滤掉sources,我很聪明,只使用了predicates数组。

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

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"]

...是错误的,我们不会发生崩溃。 我会马上修复它!

原来有。 泛型。 再次引用伊卡洛,

我稍后再给你一个类型,我要你强制执行 在我指定的任何地方键入。

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)

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

myFilter,因为sourcepredicate的类型不匹配。 编译时错误。

泛型以这种方式是泛型的:在此特定示例中,在编写myFilter函数时,您无需给出source的类型或predicate接受的参数,它就是T,它是任何东西。 但是一旦我说source是任何东西的数组,您就必须确保predicate接受的参数是相同的。 在我们之前的ANYTHING1,ANYTHING2命名法的背景下,可以说泛型强制ANYTHING1等于ANYTHING2

avismara answered 2020-08-08T22:34:38Z
1 votes

考虑在第一个函数中T不是像AnyObject那样的类型,而是一个类型变量。 这意味着在第一个函数中,您可以将任何类型的值的数组作为第一个参数,但是将仅对特定类型的值进行操作的谓词作为第二个参数。 也就是说,您可以传递字符串数组和字符串谓词,也可以传递整数数组和谓词整数,而不能传递整数数组和谓词字符串。 因此,对于与类型有关的内容,函数的主体保证是正确的。

相反,在第二个示例中,您可以传递任何类型的值和可对任何(可能不同!)类型进行操作的谓词,这样,如果谓词将使用第一个参数的值在函数的主体中调用, 那么可能会发生动态类型错误。 幸运的是,Swith类型检查器将谓词的调用标记为类型错误,以防止发生这种情况。

Renzo answered 2020-08-08T22:35:03Z
translate from https://stackoverflow.com:/questions/31041265/difference-between-generics-and-anyobject-in-swift