@Xiaojun-Jin
2015-03-27T09:31:38.000000Z
字数 8241
阅读 1470
Swift
struct Pair<T: Equatable> {let a: T!let b: T!init(a: T, b: T) {self.a = aself.b = b}func equal() -> Bool {return a == b}}let pair = Pair(a: 5, b: 10)pair.a // 5pair.b // 10pair.equal() // falselet floatPair = Pair(a: 3.14159, b: 2.0)floatPair.a // 3.14159floatPair.b // 2.0floatPair.equal() // false
This struct now can take parameters of any types (int, float or else) by using Generics.
// automatically inferredlet array = [1, 2, 3, 4]let dictionary = ["dog": 1, "elephant": 2]
// fully defininglet array: Array<Int> = [1, 2, 3, 4]let dictionary: Dictionary<String, Int> = ["dog": 1, "elephant": 2]
// short formlet array: [Int] = [1, 2, 3, 4]let dictionary: [String: Int] = ["dog": 1, "elephant": 2]
Instead of using the
isEqualToString:method, in Swift you are able to directly use==to compare strings.
switch person.name {case "Matt Galloway":println("Author of an interesting Swift article")case "Ray Wenderlich":println("Has a great website")case "Tim Cook":println("CEO of Apple Inc.")default:println("Someone else")}
There are no breaks in sight. That's because cases in switches no longer fall through to the next one!
switch i {case 0, 1, 2:println("Small")case 3...7:println("Medium")case 8..<10:println("Large")case _ where i % 2 == 0:println("Even")case _ where i % 2 == 1:println("Odd")default:break}
Here break is added to declare that default will do noting. Note that switch also has the ability to define a case as a calculation of the input.
Closure expression syntax has the following general form:
{ (parameters) -> return type in statements }
{ (s1: String, s2: String) -> Bool in return s1 > s2 }
If the return types can be inferred (which is often the case), the return arrow (->), the parentheses, and keyword
returncan also be omitted.
{ parameters in statements}
{ s1, s2 in s1 > s2 }// Shorthand Argument Names{ $0 > $1 }
An array that contains [a, b, c] is really the same as another array that contains [a, b, c] and they are completely interchangeable. It doesn't matter whether you use the first array or the second, because they represent the exact same thing. That's why arrays are structs.
You would model a person as a class because two person objects are two different things. Just because two people have the same name and birthdate, doesn't mean they are the same person.
Perhaps you've seen a class declaration like this before:
class MyViewController: UITableViewDelegate, UITableViewDataSource, UIScrollViewDelegate,UINavigationControllerDelegate,UIImagePickerControllerDelegate, UITextFieldDelegate
We won't judge you for having such a busy view controller, but we do suggest having each protocol conformance declared in its own extension:
class MyViewController {// Standard view controller stuff here}extension MyViewController: UITableViewDelegate {// Table view delegate methods here}extension MyViewController: UITextFieldDelegate {// Text field delegate methods here}// etc.
This keeps things organized and helps keep related methods together. It also means you can add a protocol and related methods in one step in one place, rather than editing the class declaration and then adding methods somewhere to a potentially crowded list of methods.
let tap: UITapGestureRecognizer// error: Property 'tap' not initialized at super.init calllet tap: UITapGestureRecognizer?// defined as optional value to avoid force initializing in init function
// no return value, thus no return arrow (->) is includedfunc sayGoodbye(personName: String) {println("Goodbye, \(personName)!")}
Functions without a defined return type return a special value of type Void. This is simply an empty
tuple, in effect a tuple with zero elements, which can be written as ().
func isEven(number: Int) -> Bool {return number % 2 == 0}evens = Array(1...10).filter(isEven)println(evens)
Functional filtering: Array(1...10) creates an Array 1...10 creates a Range. The filter statement creates and returns a new array that contains only the items for which the given function returns true.
evens = Array(1...10).filter { (number) in number % 2 == 0 }println(evens)
Functions are just named closures. Compiler infers the type of the parameter number and return types of the closure from its usage context.
evens = Array(1...10).filter { $0 % 2 == 0 }println(evens)
The above uses argument shorthand notation, implicit returns, type inference!
Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure's arguments by the names
$0,$1,$2, and so on.
Generic Function:
func myFilter<T>(source: [T], predicate:(T) -> Bool) -> [T] {var result = [T]()for i in source {if predicate(i) {result.append(i)}}return result}evens = myFilter(Array(1...10)) { $0 % 2 == 0 }println(evens)// or calling like this:evens = myFilter(Array(1...10)) { number in number % 2 == 0 }println(evens)
If generic function takes two function parameters:
func myFilter<T>(source: [T], predicate:(T) -> Bool, tFun:() -> ()) -> [T] {var result = [T]()for i in source {if predicate(i) {result.append(i)}}tFun()return result}func isEven(number: Int) -> Bool {return number % 2 == 0}func tFun() -> () {println("I am Rylan.")}
let evens = myFilter(Array(1...10), isEven, tFun)// alternativelylet evens = myFilter(Array(1...10), { $0 % 2 == 0 }, {println("I am Rylan.")})
If you need to pass a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a
Trailing Closureinstead.
// trailing closureslet evens1 = myFilter(Array(1...10),{ nuber in nuber % 2 == 0 }) { println("dd") }
// func reduce<U>(initial: U, combine: (U, T) -> U) -> U// reduce(0) {...} trailing closures style// 'typealias Element = T', so 'T' refers to array element?evenSum = Array(1...10).filter { (number) in number % 2 == 0 }.reduce(0) { (total, number) in total + number }// concise versionevenSum = Array(1...10).filter { $0 % 2 == 0 }.reduce(0) { $0 + $1 }println(evenSum)
let numbers = Array(1...10).reduce("numbers: ") {(total, number) in total + "\(number) "} /*{ $0 + "\($1) " }*/println(numbers)
Imperative method:
let words = ["Cat", "Chicken", "fish", "Dog","Mouse", "Guinea Pig", "monkey"]// Using a typealias makes the code more readabletypealias Entry = (Character, [String])func buildIndex(words: [String]) -> [Entry] {var result = [Entry]()var letters = [Character]()for word in words {let firstLetter = Character(word.substringToIndex(advance(word.startIndex, 1)).uppercaseString)if !contains(letters, firstLetter) {letters.append(firstLetter)}}for letter in letters {var wordsForLetter = [String]()for word in words {let firstLetter = Character(word.substringToIndex(advance(word.startIndex, 1)).uppercaseString)if firstLetter == letter {wordsForLetter.append(word)}}result.append((letter, wordsForLetter))}return result}println(buildIndex(words))
Functional Way:
func buildIndex(words: [String]) -> [Entry] {let letters = words.map {(word) -> Character inCharacter(word.substringToIndex(advance(word.startIndex, 1)).uppercaseString)}// omit return type (->)/*let letters = words.map {(word) inCharacter(word.substringToIndex(advance(word.startIndex, 1)).uppercaseString)}*/// concise version/*let letters = words.map {Character($0.substringToIndex(advance($0.startIndex, 1)).uppercaseString)}*/println(letters) // [C, C, F, D, M, G, M]return [Entry]()}
map creates a new array with the results of calls to the supplied closure for each element in the supplied array. You use map to perform transformations; in this case, map transforms an array of type [String] into an array of type [Character].
func distinct<T: Equatable>(source: [T]) -> [T] {var unique = [T]()for item in source {if !contains(unique, item) {unique.append(item)}}return unique}
distinct iterates over all the items in an array, building a new array that contains only the unique items.
Update buildIndex as follows:
func buildIndex(words: [String]) -> [Entry] {let letters = words.map {(word) -> Character inCharacter(word.substringToIndex(advance(word.startIndex, 1)).uppercaseString)}let distinctLetters = distinct(letters)return distinctLetters.map {(letter) -> Entry inreturn (letter, words.filter {(word) -> Bool inCharacter(word.substringToIndex(advance(word.startIndex, 1)).uppercaseString) == letter})}}
Concise version (create func firstLetter to remove duplicate code):
func buildIndex(words: [String]) -> [Entry] {func firstLetter(str: String) -> Character {return Character(str.substringToIndex(advance(str.startIndex, 1)).uppercaseString)}let letters = words.map {(word) -> Character infirstLetter(word)}let distinctLetters = distinct(letters)return distinctLetters.map {(letter) -> Entry inreturn (letter, words.filter {(word) -> Bool infirstLetter(word) == letter})}}
func filter(includeElement: (T) -> Bool) -> [T]// Return anArraycontaining the elementsxofselffor whichincludeElement(x)istrue
Even more concise version:
func buildIndex(words: [String]) -> [Entry] {func firstLetter(str: String) -> Character {return Character(str.substringToIndex(advance(str.startIndex, 1)).uppercaseString)}return distinct(words.map(firstLetter)).map {(letter) -> Entry inreturn (letter, words.filter {(word) -> Bool infirstLetter(word) == letter})}}