在Swift中泛型和任何对象之间的区别

时间:2022-02-27 22:04:32

Consider this myFilter function that takes in a generic argument and filters the array based on the predicate. This is same as the filter() function provided by Swift.

考虑这个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
}

How is this different from,

这和,

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

Aren't we achieving the point of generics even in the latter example?

即使在后面的例子中,我们也没有达到泛型的意义吗?

3 个解决方案

#1


58  

Generics are type safe, meaning if you pass a string as a generic and try to use as a integer the compiler will complain and you will not be able to compile your (which is good). (This happens because Swift is using Static typing, and is able to give you a compiler error)

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

If you use AnyObject the compiler has no idea if the object can be treated as a String or as an Integer. It will allow you to do whatever you want with it (which is bad).

如果使用AnyObject,编译器不知道对象是否可以被当作字符串或整数。它将允许你做任何你想做的事情(这是不好的)。

e.g. if you try to pass a String when it the your previously used Integer the application will crash. (This happens because Swift is using Dynamic typing and will only give you a runtime crash)

如果你试图传递一个字符串,当它是你以前使用的整数时,应用程序将崩溃。(这是因为Swift使用的是动态类型,只会导致运行时崩溃)

Generics basically tells the compiler:

泛型基本上告诉编译器:

"I am going to give you a type later and I want you to enforce that type everywhere I specify."

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

AnyObject basically tells the compiler:

AnyObject基本上告诉编译器:

"Don't worry about this variable no need to enforce any type here let me do whatever I want to."

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

#2


12  

Note: Icaro's answer would still be the accepted answer, I am just extending his explanation.

注:伊卡罗的回答仍然是公认的答案,我只是在扩展他的解释。

TL;DR : Check Icaro's answer.

莱:查一下伊卡罗的答案。

About the usage of AnyObject Icaro rightly puts:

关于任何对象的使用,Icaro正确地指出:

Don't worry about this variable no need to enforce any type here let me do whatever I want to.

不用担心这个变量不需要强制执行任何类型我想怎么做都行。

What does this mean? Let's take the code example in the question (I've gone a step up and changed AnyObject to Any without changing the meaning of the question):

这是什么意思?让我们以问题中的代码示例为例(我在不改变问题的含义的情况下将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
}

This means, the myFilter function takes in two arguments one source and a closure predicate. If you look closely, the contents of the source array can be ANYTHING. And the argument of the closure predicate can be ANYTHING as well. If we were to name these "ANYTHING"s -- say ANYTHING1 and ANYTHING2 -- this approach doesn't require ANYTHING1 to be equal to ANYTHING2.

这意味着,myFilter函数接受两个参数:一个源和一个闭包谓词。如果仔细观察,源数组的内容可以是任何东西。闭包谓词的参数也可以是任何东西。如果我们给这些“任何东西”命名——说任何东西1和任何东西2——这个方法不需要任何东西1等于任何东西2。

Let's sit back and ponder over the implications of this...

让我们坐下来思考一下这个问题的含义。

Say, we want to filter out evens from an array of integers and let's use our Any filter for this

比如说,我们想要从一个整数数组中过滤掉evens让我们使用任意的过滤器

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)

Wow, that worked, didn't it? All smiles? No.

哇,成功了,不是吗?所有的微笑?不。

Notice how in the line :

注意这一行是如何:

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

I'm forcefully down-casting a. This line would crash if a was anything other than an Int. But its usage is justified; after all, we want to just filter out the Ints and I am smart enough to use just an array of Ints.

我用力地把a降下来,如果a不是Int,这行就会崩溃,但是它的用法是合理的;毕竟,我们想过滤掉Ints我很聪明,只使用Ints数组。

But, because say, I am a naive programmer, I do this :

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

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)

This happily compiles, but crashes in the runtime. If only there was a way, where the compiler would tell me that this line...

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

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

... was faulty, we would not have had a crash. I would have fixed it right away!

…如果是错误的,我们就不会崩溃。我会马上修好的!

Turns out, there is. Generics. To quote Icaro again,

结果是,有。泛型。再次引用Icaro,

I am going to give you a type later and I want you to enforce that type everywhere I specify.

稍后我将给您一个类型,我希望您在我指定的任何地方都执行该类型。

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)

This new filter is awesome. It won't let me do :

这个新过滤器棒极了。它不会让我这么做:

let evens = myFilter(source: ints, predicate:predicate) because, the types of the predicate and source don't match. Compile time error.

让evens = myFilter(源:ints,谓词:谓词),因为谓词和源的类型不匹配。编译时错误。

Generics is generic in this way : in this specific example -- while at the point of writing the myFilter function, you do not need to give a type of the source or the argument that predicate takes, it's T, it's ANYTHING. But once I say that source is an array of ANYTHING, you HAVE to make sure the argument that the predicate accepts is the same ANYTHING. With the background of our previous ANYTHING1, ANYTHING2 nomenclature, we can say that generics forces ANYTHING1 to be equal to ANYTHING2

泛型以这种方式是通用的:在这个特定的示例中——在编写myFilter函数时,您不需要给出谓词所使用的源或参数的类型,它是T,它是任何东西。但是一旦我说源是任何东西的数组,你必须确保谓词接受的参数是相同的。在我们之前的ANYTHING1, ANYTHING2命名法的背景下,我们可以说泛型迫使ANYTHING1等于ANYTHING2

#3


1  

Consider that in the first function T is not a type, like is AnyObject, but a type variable; this means that in the first function you can pass an array of values of any type as first parameter, but a predicate which operates only on values of that specific type as second parameter. That is you can pass an array of strings and a predicate on strings, or an array of integers and a predicate on integers, while you cannot pass an array of integers and a predicate on strings. So, the body of the function is guaranteed to be correct for what concern the types.

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

Instead in the second example you can pass a value of any type and a predicate which operates on any (possibly different!) type, so that, if the predicate would be called in the body of the function with the value of the first parameter, then a dynamic type error could occur. Fortunately, the Swith typechecker marks the call of the predicate as type error, in order to prevent this possibility.

而在第二个示例中您可以传递任何类型的值和一个谓词运营在任何(可能不同!)类型,因此,如果谓词在体内被称为函数的第一个参数的值,然后一个动态类型可能会发生错误。幸运的是,Swith typechecker将谓词的调用标记为类型错误,以防止这种可能性。

#1


58  

Generics are type safe, meaning if you pass a string as a generic and try to use as a integer the compiler will complain and you will not be able to compile your (which is good). (This happens because Swift is using Static typing, and is able to give you a compiler error)

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

If you use AnyObject the compiler has no idea if the object can be treated as a String or as an Integer. It will allow you to do whatever you want with it (which is bad).

如果使用AnyObject,编译器不知道对象是否可以被当作字符串或整数。它将允许你做任何你想做的事情(这是不好的)。

e.g. if you try to pass a String when it the your previously used Integer the application will crash. (This happens because Swift is using Dynamic typing and will only give you a runtime crash)

如果你试图传递一个字符串,当它是你以前使用的整数时,应用程序将崩溃。(这是因为Swift使用的是动态类型,只会导致运行时崩溃)

Generics basically tells the compiler:

泛型基本上告诉编译器:

"I am going to give you a type later and I want you to enforce that type everywhere I specify."

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

AnyObject basically tells the compiler:

AnyObject基本上告诉编译器:

"Don't worry about this variable no need to enforce any type here let me do whatever I want to."

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

#2


12  

Note: Icaro's answer would still be the accepted answer, I am just extending his explanation.

注:伊卡罗的回答仍然是公认的答案,我只是在扩展他的解释。

TL;DR : Check Icaro's answer.

莱:查一下伊卡罗的答案。

About the usage of AnyObject Icaro rightly puts:

关于任何对象的使用,Icaro正确地指出:

Don't worry about this variable no need to enforce any type here let me do whatever I want to.

不用担心这个变量不需要强制执行任何类型我想怎么做都行。

What does this mean? Let's take the code example in the question (I've gone a step up and changed AnyObject to Any without changing the meaning of the question):

这是什么意思?让我们以问题中的代码示例为例(我在不改变问题的含义的情况下将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
}

This means, the myFilter function takes in two arguments one source and a closure predicate. If you look closely, the contents of the source array can be ANYTHING. And the argument of the closure predicate can be ANYTHING as well. If we were to name these "ANYTHING"s -- say ANYTHING1 and ANYTHING2 -- this approach doesn't require ANYTHING1 to be equal to ANYTHING2.

这意味着,myFilter函数接受两个参数:一个源和一个闭包谓词。如果仔细观察,源数组的内容可以是任何东西。闭包谓词的参数也可以是任何东西。如果我们给这些“任何东西”命名——说任何东西1和任何东西2——这个方法不需要任何东西1等于任何东西2。

Let's sit back and ponder over the implications of this...

让我们坐下来思考一下这个问题的含义。

Say, we want to filter out evens from an array of integers and let's use our Any filter for this

比如说,我们想要从一个整数数组中过滤掉evens让我们使用任意的过滤器

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)

Wow, that worked, didn't it? All smiles? No.

哇,成功了,不是吗?所有的微笑?不。

Notice how in the line :

注意这一行是如何:

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

I'm forcefully down-casting a. This line would crash if a was anything other than an Int. But its usage is justified; after all, we want to just filter out the Ints and I am smart enough to use just an array of Ints.

我用力地把a降下来,如果a不是Int,这行就会崩溃,但是它的用法是合理的;毕竟,我们想过滤掉Ints我很聪明,只使用Ints数组。

But, because say, I am a naive programmer, I do this :

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

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)

This happily compiles, but crashes in the runtime. If only there was a way, where the compiler would tell me that this line...

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

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

... was faulty, we would not have had a crash. I would have fixed it right away!

…如果是错误的,我们就不会崩溃。我会马上修好的!

Turns out, there is. Generics. To quote Icaro again,

结果是,有。泛型。再次引用Icaro,

I am going to give you a type later and I want you to enforce that type everywhere I specify.

稍后我将给您一个类型,我希望您在我指定的任何地方都执行该类型。

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)

This new filter is awesome. It won't let me do :

这个新过滤器棒极了。它不会让我这么做:

let evens = myFilter(source: ints, predicate:predicate) because, the types of the predicate and source don't match. Compile time error.

让evens = myFilter(源:ints,谓词:谓词),因为谓词和源的类型不匹配。编译时错误。

Generics is generic in this way : in this specific example -- while at the point of writing the myFilter function, you do not need to give a type of the source or the argument that predicate takes, it's T, it's ANYTHING. But once I say that source is an array of ANYTHING, you HAVE to make sure the argument that the predicate accepts is the same ANYTHING. With the background of our previous ANYTHING1, ANYTHING2 nomenclature, we can say that generics forces ANYTHING1 to be equal to ANYTHING2

泛型以这种方式是通用的:在这个特定的示例中——在编写myFilter函数时,您不需要给出谓词所使用的源或参数的类型,它是T,它是任何东西。但是一旦我说源是任何东西的数组,你必须确保谓词接受的参数是相同的。在我们之前的ANYTHING1, ANYTHING2命名法的背景下,我们可以说泛型迫使ANYTHING1等于ANYTHING2

#3


1  

Consider that in the first function T is not a type, like is AnyObject, but a type variable; this means that in the first function you can pass an array of values of any type as first parameter, but a predicate which operates only on values of that specific type as second parameter. That is you can pass an array of strings and a predicate on strings, or an array of integers and a predicate on integers, while you cannot pass an array of integers and a predicate on strings. So, the body of the function is guaranteed to be correct for what concern the types.

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

Instead in the second example you can pass a value of any type and a predicate which operates on any (possibly different!) type, so that, if the predicate would be called in the body of the function with the value of the first parameter, then a dynamic type error could occur. Fortunately, the Swith typechecker marks the call of the predicate as type error, in order to prevent this possibility.

而在第二个示例中您可以传递任何类型的值和一个谓词运营在任何(可能不同!)类型,因此,如果谓词在体内被称为函数的第一个参数的值,然后一个动态类型可能会发生错误。幸运的是,Swith typechecker将谓词的调用标记为类型错误,以防止这种可能性。