转载请注明 http://write.blog.csdn.net/postedit/28442151
翻译者:gumpstar
昨天Swift刚出来,以后自己可能会在手机上开发计算机视觉应用,就打算每天学习一点点。
简介
Swift是供iOS和OS X应用编程的新编程语言,基于C和Objective-C,而却没有C的一些兼容约束。Swift采用了安全的编程模式和添加现代的功能来是的编程更加简单、灵活和有趣。界面则基于广受人民群众爱戴的Cocoa和Cocoa Touch框架,展示了软件开发的新方向。
Swift在市场存在了多年。Apple基于已有的编译器、调试器、框架作为其基础架构。通过ARC(Automatic Reference Counting,自动引用计数)来简化内存管理。我们的框架栈则一直基于Cocoa。Objective-C进化支持了块、collection literal和模块,允许现代语言的框架无混乱即可使用。感谢这些基础工作,才使得可以在Apple软件开发中引入新的编程语言。
Objective-C开发者会感到Swift的似曾相识。Swift采用了Objective-C的命名参数和动态对象模型。提供了对Cocoa框架和mix-and-match的互操作性。基于这些基础,Swift引入了很多新功能和结合面向过程和面向对象的功能。
Swift对新的程序员也是友好的。他是工业级品质的系统编程语言,却又像脚本语言一样的友好。他支持playground,允许程序员实验一段Swift代码功能并立即看到结果,而无需麻烦的构建和运行一个应用。
Swift集成了现代编程语言思想,以及Apple工程文化的智慧。编译器是按照性能优化的,而语言是为开发优化的,无需互相折中。可以从"Hello, world"开始学起并过渡到整个系统。所有这些使得Swift成为Apple软件开发者创新的源泉。
Swift是编写iOS和OSX应用的梦幻方式,并且会持续推进新功能的引入。我们对 Swift充满野心,我们迫不及待的看到你用他来做点什么。
第一个程序
我们来看看hello world
println("Hello, world")
对,这就是全部代码,只有一行!!!不需要包含库,比如<iostream>,也不需要分号,也不需要main函数,因为在全部范围(global scope)写的代码就是程序的进入点(entry point)
简单值
let语句创建一个常量,var创建一个变量,常量值不需要在编译时(compile
time)就知道,但是必须只能赋值一次
var myVariable = 42 myVariable = 50 let myConstant = 42
如果要进行赋值,类型要一致.但是你不需要显示写出类型,编译器会自动推导,在上面的例子中,编译器就推导出了myVariable是一个整型.
当然可以显示指定,如下使用了一个冒号显示声明为Double类型
let implicitInteger = 70 let implicitDouble = 70.0 let explicitDouble: Double = 70
EXPERIMENT
Create a constant with an explicit type of Float and a value of 4.
let explictFloat: Float = 4
值不会隐式转化为另一种类型,必须要显示转化
let label = "The width is " let width = 94 let widthLabel = label + String(width)
还有更简单的方法把值包括在字符串中,在圆括号前插入‘\‘
let apples = 3 let oranges = 5 let appleSummary = "I have \(apples) apples." let fruitSummary = "I have \(apples + oranges) pieces of fruit.
PHP中也有这样的格式
使用[]创建数组和字典,在方括号里用下标(index)或者键值(key)来访问元素
var shoppingList = ["catfish", "water", "tulips", "blue paint"] shoppingList[1] = "bottle of water" var occupations = [ "Malcolm": "Captain", "Kaylee": "Mechanic", ] occupations["Jayne"] = "Public Relations”
创建空数组空字典,使用如下初始化语句
let emptyArray = String[]() let emptyDictionary = Dictionary<String, Float>()
如果类型可以被推导,那么就可以使用[]来初始化数组或者[:]来初始化字典,比如说,当你要将它们作为参数传递给一个函数,就不需要显示指定类型了。
shoppingList = [] // Went shopping and bought everything.
控制流
用if和switch创建条件语句,用for-in,for,while和do-while创建循环,条件语句的()是可选的,但是主体语句的{}是必须的
let individualScores = [75, 43, 103, 87, 12] var teamScore = 0 for score in individualScores { if score > 50 { teamScore += 3 } else { teamScore += 1 } } teamScore
一个if语句必须是bool类型的
这意味着if score{...}这种语句是错误的
有optional类型,跟SML有些类似.
一个optional value要么包含一个值,要么是nil,在类型后面插入?表示这是一个optional
var optionalString: String? = "Hello" optionalString == nil var optionalName: String? = "John Appleseed" var greeting = "Hello!" if let name = optionalName { greeting = "Hello, \(name)" }
假如optionalName是nil,那么if语句就是false,
switch语句支持不同类型的数据和更多的比较操作符,不限于整数和一些相等的测试
let vegetable = "red pepper" switch vegetable { case "celery": let vegetableComment = "Add some raisins and make ants on a log." case "cucumber", "watercress": let vegetableComment = "That would make a good tea sandwich." case let x where x.hasSuffix("pepper"): let vegetableComment = "Is it a spicy \(x)?" default: let vegetableComment = "Everything tastes good in soup." }
不用写break语句,进入那个case后会退出
使用for-in来迭代字典key-value对
let interestingNumbers = [ "Prime": [2, 3, 5, 7, 11, 13], "Fibonacci": [1, 1, 2, 3, 5, 8], "Square": [1, 4, 9, 16, 25], ] var largest = 0 for (kind, numbers) in interestingNumbers { for number in numbers { if number > largest { largest = number } } } largest
while语句基本无变化
var n = 2 while n < 100 { n = n * 2 } n var m = 2 do { m = m * 2 } while m < 100 m
可以使用..来表示一个range,如下,两段代码做的事情是一样的
0..3表示[0,3),0...3表示[0,3]
var firstForLoop = 0 for i in 0..3 { firstForLoop += i } firstForLoop var secondForLoop = 0 for var i = 0; i < 3; ++i { secondForLoop += 1 } secondForLoop
其实感觉swift的函数就是函数式编程语言的东西
使用func关键字声明函数,使用->声明函数返回类型
[cpp] view
plaincopy
- func greet(name: String, day: String) -> String {
- return "Hello \(name), today is \(day)."
- }
- greet("Bob", "Tuesday")
也可以返回元组
[cpp] view
plaincopy
- func getGasPrices() -> (Double, Double, Double) {
- return (3.59, 3.69, 3.79)
- }
- getGasPrices()
也可以接收变参
[cpp] view
plaincopy
- func sumOf(numbers: Int...) -> Int {
- var sum = 0
- for number in numbers {
- sum += number
- }
- return sum
- }
- sumOf()
- sumOf(42, 597, 12)
函数可以嵌套
[cpp] view
plaincopy
- func returnFifteen() -> Int {
- var y = 10
- func add() {
- y += 5
- }
- add()
- return y
- }
- returnFifteen()
函数是第一等公民(函数式编程嘛......),函数可以返回函数,也可以接收函数
下面这个函数返回一个函数(接收一个int返回一个int的函数),
[cpp] view
plaincopy
- func makeIncrementer() -> (Int -> Int) {
- func addOne(number: Int) -> Int {
- return 1 + number
- }
- return addOne
- }
- var increment = makeIncrementer()
- increment(7)
下面这个函数接收一个函数(接收一个int返回bool的函数)
[cpp] view
plaincopy
- func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool {
- for item in list {
- if condition(item) {
- return true
- }
- }
- return false
- }
- func lessThanTen(number: Int) -> Bool {
- return number < 10
- }
- var numbers = [20, 19, 7, 12]
- hasAnyMatches(numbers, lessThanTen)
闭包
函数是特殊的闭包,你可以用{}套住一个闭包而不需要指定名称,用 in 来分开参数和返回类型
[cpp] view
plaincopy
- numbers.map({
- (number: Int) -> Int in
- let result = 3 * number
- return result
- })
这个函数使得numbers里的每一个数字都变成了原来的3倍
你可以有很多种方式书写更简介的闭包,当一个闭包的类型已知,或者返回类型已知,或者都知道,你可以省略一些类型参数。单语句的闭包隐式返回唯一语句。
[cpp] view
plaincopy
- numbers.map({ number in 3 * number })
你也可以使用数字而不是名字来访问参数,这种方法在很短的闭包中非常有用。一个传递给函数的闭包若作为最后一个参数可以立即跟在参数后
[cpp] view
plaincopy
- sort([1, 5, 3, 12, 2]) { $0 > $1 }
note:函数式编程只学过一个学期,closure也掌握的不是很好,上面的式子是按从大到小排序么?希望懂函数式编程的大神解答。
对象与类
先创建一个简单的类
class Shape { var numberOfSides = 0 func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." } }
之后我们可以实例化,并用.操作符调用变量和方法
var shape = Shape() shape.numberOfSides = 7 var shapeDescription = shape.simpleDescription()
这个简单的类少了一个初始化方法,下面我们来添加init()方法
class NamedShape { var numberOfSides: Int = 0 var name: String init(name: String) { self.name = name } func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." } }
你也可以声明并定义deinit()函数创建析构方法
下面我们来讨论子类
使用:来继承
使用override关键字覆盖方法
如果不小心覆盖了一个方法却没有使用override,编译器会报错
class Square: NamedShape { var sideLength: Double init(sideLength: Double, name: String) { self.sideLength = sideLength super.init(name: name) numberOfSides = 4 } func area() -> Double { return sideLength * sideLength } override func simpleDescription() -> String { return "A square with sides of length \(sideLength)." } } let test = Square(sideLength: 5.2, name: "my test square") test.area() test.simpleDescription()
可以定义变量的get和set方法
class EquilateralTriangle: NamedShape { var sideLength: Double = 0.0 init(sideLength: Double, name: String) { self.sideLength = sideLength super.init(name: name) numberOfSides = 3 } var perimeter: Double { get { return 3.0 * sideLength } set { sideLength = newValue / 3.0 } } override func simpleDescription() -> String { return "An equilateral triagle with sides of length \(sideLength)." } } var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle") triangle.perimeter triangle.perimeter = 9.9 triangle.sideLength
在perimeter的set方法里,新的值有一个隐式名‘newValue’,你可以显示提供名字 set(newValue : Double){}
EquilateralTriangle的初始化方法分3阶段
- 定义自己声明的变量的值
- 调用父类构造器
- 修改父类变量值.任意其他的方法,如set,get也能在这里调用
willset和didset可以在赋值前和赋值后调用,如下代码
class TriangleAndSquare { var triangle: EquilateralTriangle { willSet { square.sideLength = newValue.sideLength } } var square: Square { willSet { triangle.sideLength = newValue.sideLength } } init(size: Double, name: String) { square = Square(sideLength: size, name: name) triangle = EquilateralTriangle(sideLength: size, name: name) } } var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape") triangleAndSquare.square.sideLength triangleAndSquare.triangle.sideLength triangleAndSquare.square = Square(sideLength: 50, name: "larger square") triangleAndSquare.triangle.sideLength
在构造square时会设置triangle的长度,在构造triangle时会设置square的长度
类里面的方法跟普通函数有一个重要的区别。普通函数的参数只能在函数作用域有效,但是类方法的参数却在你调用时也可以使用(除了第一个参数)。参数可以有二个名字,如下。第2个参数的第2个名字在函数体里使用,但是第1个名字却可以在调用时使用。
class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes times: Int) { count += amount * times } } var counter = Counter() counter.incrementBy(2, numberOfTimes: 7)
当你与optional打交道时,可以这样书写
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
当?前面的东西时nil时,所有?后面的东西都被忽略整个表达式就是nil.否则,?之前的值就被解读并且正常运行。
let sideLength = optionalSquare?.sideLength
枚举与结构体
使用enum创造一个枚举类型,枚举也可以有关联的方法
enum Rank: Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King func simpleDescription() -> String { switch self { case .Ace: return "ace" case .Jack: return "jack" case .Queen: return "queen" case .King: return "king" default: return String(self.toRaw()) } } } let ace = Rank.Ace let aceRawValue = ace.toRaw()
在上面的例子中,枚举的raw value时Int,所以你只需要指定第一个值Ace = 1,下面就是按顺序递增,和C++的枚举类型赋值类似。你也可以指定字符串或者浮点数为枚举类型的raw value
使用toRaw()和fromRaw()来转换raw value和枚举类型
if let convertedRank = Rank.fromRaw(3) { let threeDescription = convertedRank.simpleDescription() }
枚举的成员值就是实际值,而不是其他方式写的原始值。实际上,有些情况是原始值,就是你不提供的时候。
enum Suit { case Spades, Hearts, Diamonds, Clubs func simpleDescription() -> String { switch self { case .Spades: return "spades" case .Hearts: return "hearts" case .Diamonds: return "diamonds" case .Clubs: return "clubs" } } } let hearts = Suit.Hearts let heartsDescription = hearts.simpleDescription()
注意上面引用Hearts成员的两种方法:当赋值到 hearts 常量时,枚举成员 Suit.Hearts 通过全名引用,因为常量没有明确的类型。在 switch 中,枚举通过 .Hearts 引用,因为 self 的值是已知的。你可以在任何时候使用简化的方法。
使用struct创建结构体。struct支持很多类的特性(比如初始化和方法)。一个重要的不同之处在于struct拷贝传递(call by value),而class按引用传递(pass by reference)
struct Card { var rank: Rank var suit: Suit func simpleDescription() -> String { return "The \(rank.simpleDescription()) of \(suit.simpleDescription())" } } let threeOfSpades = Card(rank: .Three, suit: .Spades) let threeOfSpadesDescription = threeOfSpades.simpleDescription()
一个枚举类型的实例会与一个值绑定,枚举类型相同成员的不同实例会与不同的值绑定。当创建实例的时候提供了关联的值,这个值和 raw value不同:不同实例的raw vaule是一样的.
enum ServerResponse { case Result(String, String) case Error(String) } let success = ServerResponse.Result("6:00 am", "8:09 pm") let failure = ServerResponse.Error("Out of cheese.") switch success { case let .Result(sunrise, sunset): let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)." case let .Error(error): let serverResponse = "Failure... \(error)" }
success会与第一个case匹配,这就是pattern match
Swift中文教程(1)-简介,布布扣,bubuko.com