Before we look at how to use Generics in Swift, let’s take a
look at the problem that they are designed to solve. Lets say that we wanted to write a function
that swapped the values of two Int
types. We could very easily write the
function like this:
func swapInts (inout
x: Int, inout y: Int) {
let tmp = x
x = y
y = tmp
}
Now lets say that we also have a need to swap the values of
two String types. We could then write another function like
this:
func swapString
(inout x: String, inout y: String) {
let tmp = x
x = y
y = tmp
}
Having two functions like this isn’t too bad but what if we
also had a need two swap two UInt, Double and Boolean types as well? This
could get out of hand very quickly. The
worse part is we are duplicating most of the code each time we add a new swap
function. This is where Generics can
help us.
Generics allow us to write flexible and reusable code that
avoids the duplication that we saw in the previous examples. Now lets look at how we could write one
function with Generics that would allow us to swap the values of any data
type.
func
swapGeneric<T> (inout x: T, inout y: T) {
let tmp = x
x = y
y = tmp
}
The swapGeneric() function looks pretty similar to the other
two swap functions that we saw earlier except for the capital T. The capital T is used as a placeholder and
lets Swift know that we will be defining the type, associated with the
placeholder, at run time. When we define
a Generic function we include the placeholder between two angled brackets
(<>). We can then use that
placeholder in place of any type definition within the function, the function’s
definition or as the return type of the function.
There is nothing special about the capital T that we used in our example. We can
actually use any valid identifier but
generally we use a capital T or a capital E.
We would use the genericSwap() function like
this:
var
a = 1.1
var
b = 2.2
swapGeneric(&a,
&b)
println("a
= \(a) b = \(b)")
var
c = "One"
var
d = "two"
swapGeneric
(&c, &d)
println("c
= \(c) d = \(d)")
In these examples, we see that we can swap two Double types or two String types with the same swapGeneric()
function. We could expanded these
examples to include any data type that we want.
We are also not limited to using just a single generic type. Lets look at an example of where we use two
generic types.
func
printValue<T,E> (value1: T, value2: E) {
println("value1: \(value1)")
println("value2: \(value2)")
}
In this function we have two generic types defined, the T and
the E. Here are a couple of examples of how we could
use this function.
printValue(“hello”,
1234)
printValue(3.1415,
“bye”)
We can see that we can include different data types within
the parameters that we are sending to the printValue() function.
In this post, we briefly looked at how we could use Generics
within a function definition to create a function whose parameter types can
change at runtime as needed. This is one
of the most popular uses for Generics and is also the basis of Swift’s
collection types (Array, Dictionary).
For a more in-depth discussion of Generics and how to create Generic and
Associated types, check out my book Mastering Swift published by Packt Publishing.
No comments:
Post a Comment