I really like what we’ve seen so far of Swift, Apple’s new programming language. For starters, I was happy to learn that references cannot be nil[1], and integer arithmetic is checked b…
original source : https://schani.wordpress.com/2014/06/03/playing-with-swift/
이 예시에서 associatedtype을 위해 protocol 정의부분 안에서 사용되고 있는 typealias 는 deprecated 되었음을 인지할것
I really like what we’ve seen so far of Swift, Apple’s new programming language. For starters, I was happy to learn that references cannot be nil[1], and integer arithmetic is checked by default[2].
Let’s look at how Swift deals with sequences, and learn a little bit about generics on the way. Arrays, for example, are sequences, so you can iterate over them with a for loop:
for x in [1,2,3] { println(x) }
Lots of other types are sequences, too, like strings, dictionaries and ranges. What makes them sequences is that they all implement the Sequence protocol:
protocol Sequence { typealias GeneratorType : Generator func generate() -> GeneratorType }
I’m not sure why Swift elects to do generic protocols via typealias instead of just having the protocol take type arguments, like C# does, which might look something like this:
protocol Sequence<T> { func generate() -> Generator<T> }
Whatever the reason might be, we can see that a sequence can generate a Generator, which is defined as follows:
protocol Generator { typealias Element func next() -> Element? }
Generators have a next method which returns either the next element in the sequence, or nil, when the end has been reached. The for loop from above is probably mostly equivalent to
var gen = [1,2,3].generate() while let x = gen.next() { println(x) }
The equivalent of Sequence and Generator in C# are IEnumerable and IEnumerator.
The map function takes a sequence and a function, returning a new sequence containing the results of applying the function to the elements of the given sequence. For example:
for x in map([1,2,3], {i in i*2}) { println(x) }
It’s important to realize that the sequence which map returns is not necessarily of the same type as the one it is passed:
println([1,2,3]) println(map([1,2,3], {i in i*2}))
[1, 2, 3] VSs17MapCollectionView (has 2 children)
Also, sequences can generate their elements lazily:
var seq = map([1,2,3], { (i: Int) -> Int in println("processing " + String(i)) return i*2 }) var gen = seq.generate() println(gen.next())
Let’s write a function that takes a sequence and returns an array containing all the sequence’s elements!
First we need to figure out the type of this function. It turns out that this doesn’t work:
func toArray (seq: Sequence) -> seq.GeneratorType.Element[]
The compiler complains that seq is an undeclared type. This doesn’t work, either:
func toArray (seq: Sequence) -> Sequence.GeneratorType.Element[]
Here the complaint is that Sequence.GeneratorType is ambiguous. That’s because we can’t tell the compiler that the two Sequence types are the same. Maybe we can use generics to solve the problem:
func toArray<S:Sequence> (seq: S) -> S.GeneratorType.Element[] { var arr = S.GeneratorType.Element[]() ... return arr }
Swift is now happy with the type of the function, but unfortunately it doesn’t let us instantiate the array. Instead it thinks we’re trying to subscribe S.GeneratorType.Element, which isn’t possible, because it’s a type and not a value. As far as I can tell, the only way to get around this problem is to introduce a second generic argument, which we can force to the correct type via a where clause:
func toArray<S : Sequence, T where T == S.GeneratorType.Element> (seq : S) -> T[] { var arr = T[]() for x in seq { arr.append(x) } return arr } println(toArray(map([1,2,3], {x in x*2})))