Swift语法入门
正文参考:
------------------------------------2016/07/01写在前面的分割线---------------------------------------------------------------
距2015/9/10,时隔几个月之后重新回来捡起Swift,它尽然已经更新到3.0preview版本了。辞旧迎新,决定在旧博文添加新内容,必要的地方会标注出不同版本的差异。
中文翻译:来自苹果Swift.org的官方推荐,可以一看,the-swift-programming-language-in-chinese
开发者网站上的语法更新较慢,也可能是release之后才会更新。
要看最新的包括preview版本的Swift语法,可以下载epub版本的语法电子书,链接在:https://swift.org/documentation/#the-swift-programming-language
------------------------------------------正文--------------------------------------------------------------------------------------------
一、简单数值类型
1、let关键字声明一个常量,var关键字声明一个变量,每条语句后面可以不接分号。
var myVariable =
myVariable =
let myConstant =
2、常量或变量的数据类型不必显示声明,初始化赋值时编译器会推断数据类型。当然,也可以显示声明数据类型。
let implicitInteger =
let implicitDouble = 70.0
let explicitDouble: Double =
3、不同类型数据之间不存在隐式转换,如果需要转换,则需要进行显示声明。
let label = "The width is "
let width =
let widthLabel = label + String(width)
4、使用\()可以将数值插入string变量中
let apples =
let oranges =
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
5、用[]创建array类型和dictionary类型的数据,可以用index或key作为索引,最后一个元素后面允许接一个逗号。
var shoppingList = ["catfish", "water", "tulips", "blue paint"]
shoppingList[] = "bottle of water" var occupations = [
"Malcolm": "Captain",
"Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"
6、声明一个空的array或dictionary
let emptyArray = [String]()
let emptyDictionary = [String: Float]()
如果元素类型已知,也可以如下赋空值:
shoppingList = []
occupations = [:]
二、控制流
1、if和switch进行条件控制,for
-in
, for
, while
, and 和repeat
-while进行循环控制
条件语句可以不加括号,但控制段的{}是必须的
条件语句的值必须是Boolean类型,不存在其他类型与Boolean类型的隐式转换。
let individualScores = [, , , , ]
var teamScore =
for score in individualScores {
if score > {
teamScore +=
} else {
teamScore +=
}
}
print(teamScore)
2、可以用if和let来处理值可能为空的情况,这些值是optional类型,在声明数据类型后面加一个问号,就声明了一个optional类型的值,其可能有值,也可能为nil。
var optionalString: String? = "Hello"
print(optionalString == nil) var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}
如果optionalName的值为nil,则判断语句的值为false,否则,判断语句为真,optionalName的unwrapped值将赋值给name变量。
另一种处理optinal值的方式是用??运算符来提供默认值。若oprinal值为nil,则赋默认值。
let nickName: String? = nil
let fullName: String = "John Appleseed"
let informalGreeting = "Hi \(nickName ?? fullName)"
如上,nickName为nil, 则字符串中取fullName的值。
3、switch支持多种数据类型和多种比较操作,并不局限于整数类型
let vegetable = "red pepper"
switch vegetable {
case "celery":
print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
print("That would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
print("Is it a spicy \(x)?")
default:
print("Everything tastes good in soup.")
}
注意这里的let以一定格式来为x赋值。
switch中,执行完某一个case中的语句后不再继续执行下面case,所以不必显示的添加break语句。
4、for-in中可以使用键值对来对dictionary进行迭代,由于dictionary是乱序的,所以迭代顺序是任意的。
let interestingNumbers = [
"Prime": [, , , , , ],
"Fibonacci": [, , , , , ],
"Square": [, , , , ],
]
var largest =
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
}
}
print(largest)
5、while 和repeat-while
var n =
while n < {
n = n *
}
print(n) var m =
repeat {
m = m *
} while m <
print(m)
6、可以用..<来表示循环条件的范围,也可以显示写出
var firstForLoop =
for i in ..< {
firstForLoop += i
}
print(firstForLoop) var secondForLoop =
for var i = ; i < ; ++i {
secondForLoop += i
}
print(secondForLoop)
用..<表示一个半闭区间,用...表示一个闭合区间
三、函数和闭包(Functions And Closures)
1、用func关键字声明一个函数,括号中声明参数列表,用->声明函数返回类型
func greet(name: String, day: String) -> String {
return "Hello \(name), today is \(day)."
}
greet("Bob", day: "Tuesday")
默认情况下,函数用参数名来作为参数的label。也可以在函数名前面写出自定义的label,或者写_表示不用label。
func greet(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")
(参数名是在函数内部实现中使用的名字,而label则是外部调用函数时显示的参数名字)
2、用一个元组(tuple)来使函数返回多个值,这些值用名字或索引值区分。
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[]
var max = scores[]
var sum = for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
} return (min, max, sum)
}
let statistics = calculateStatistics([, , , , ])
print(statistics.sum)
print(statistics.)
3、函数的参数可以是不定数目的,把他们放入一个array即可。
func sumOf(numbers: Int...) -> Int {
var sum =
for number in numbers {
sum += number
}
return sum
}
sumOf()
sumOf(, , )
4、函数之间可以嵌套,可以使用内部函数来减小函数的复杂度和长度。
func returnFifteen() -> Int {
var y =
func add() {
y +=
}
add()
return y
}
returnFifteen()
5、函数的返回值可以是一个函数。
func makeIncrementer() -> (Int -> Int) {
func addOne(number: Int) -> Int {
return + number
}
return addOne
}
var increment = makeIncrementer()
increment()
6、函数的参数可以是一个函数。
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 <
}
var numbers = [, , , ]
hasAnyMatches(numbers, condition: lessThanTen)
7、函数实际上是一种特殊的闭包(代码块可以迟滞调用)。闭包中的代码可以访问其范围内的变量和函数,甚至是其他范围内。可以用{}直接声明一个没有名字的Closure,用in关键字来分开参数列表返回类型和函数主体。
numbers.map({
(number: Int) -> Int in
let result = * number
return result
})
8、有一些技巧可以使闭包更为精简。
如果闭包的类型已知,例如委托调用,你可以省略参数类型或返回类型,只有一条语句的闭包默认返回这条语句的值。
let mappedNumbers = numbers.map({ number in * number })
print(mappedNumbers)
可以用数字代替名字来声明参数,闭包作为函数的最后一个参数时可以立即显示在()后面,如果闭包作为函数的唯一参数,则()可以省略。
let sortedNumbers = numbers.sort { $ > $ }
print(sortedNumbers)
四、对象和类
1、创建一个类
class Shape {
var numberOfSides =
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
2、创建类的一个实例
var shape = Shape()
shape.numberOfSides =
var shapeDescription = shape.simpleDescription()
3、上面的类缺少初始化器,用init来声明一个初始化器。
class NamedShape {
var numberOfSides: Int =
var name: String init(name: String) {
self.name = name
} func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
每一个属性都要在声明时或初始化器中进行赋一个初值。
4、使用deinit来清理一些当对象被清理时需要清理的变量。
5、创建一个子类
override声明子类中复写父类的方法。
class Square: NamedShape {
var sideLength: Double init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides =
} 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()
6、属性可以有setter和getter
class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0 init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides =
} var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newValue / 3.0
}
} override func simpleDescription() -> String {
return "An equilateral triangle with sides of length \(sideLength)."
}
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
triangle.perimeter = 9.9
print(triangle.sideLength)
setter中默认传入的值的名字是newValue,可以在set后面用()声明一个自定义的名字。
7、用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: , name: "another test shape")
print(triangleAndSquare.square.sideLength)
print(triangleAndSquare.triangle.sideLength)
triangleAndSquare.square = Square(sideLength: , name: "larger square")
print(triangleAndSquare.triangle.sideLength)
9、处理可选值类型
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength
如果可选值为nil,则?后面的代码被忽略,整个表达式的值为nil。
五、枚举和结构
1、enum声明枚举类型,enum也可以有自己的函数
enum Rank: Int {
case Ace =
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.rawValue)
}
}
}
let ace = Rank.Ace
let aceRawValue = ace.rawValue
2、用init?(rawValue:)来初始化一个枚举类型的实例
if let convertedRank = Rank(rawValue: ) {
let threeDescription = convertedRank.simpleDescription()
}
3、一个枚举的枚举值就是它实际的值,而不仅仅是它的raw值的另一种写法。如果枚举没有意义性的raw类型,可以不提供raw类型(也就是数据类型)。
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()
如果没有声明enum的数据类型,则Suit.Hearts将通过全称被引用给hearts变量。
在使用swich时,枚举值可以省略枚举类型,按上面的例子,可直接用.hearts。
4、struct声明一个结构类型
struct和class类似,都有方法和初始化器。最重要的区别在于,赋值时struct是整个值复制过去,而class是增加引用。struct是值类型,而class是引用类型。
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()
5、Associated values和Raw Values
同一个枚举值可能有不同的Associated value,当创建枚举实例时才提供Associated value。
而对于同一个枚举的所有实例而言,它们的raw value都是一样的,当定义枚举时就提供了Raw Values.
例如:
(String,String)是success的Raw value,而("6:00 am", "8:09 pm")是success的Associated value。
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)"
}
六、协议和扩展
1、protocol关键字声明一个协议
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
2、类、枚举和结构都可以实现协议
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A very simple class."
var anotherProperty: Int =
func adjust() {
simpleDescription += " Now 100% adjusted."
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "A simple structure"
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
注意,mutating关键字标记一个可以修改构造的方法。而类中的方法都可以修改类(自己),所以不必声明mutating。
3、使用extension来扩展一个已知类的功能,可以扩展一个协议或者你引用的类。
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self +=
}
}
print(.simpleDescription)
4、协议和其他声明的类型一样,可以用协议的名字来创建一个集合,集合中的对象类型不同但是都遵守同一个协议。
当你处理一个协议类型的变量时,协议外部定义的方法不可用。
let protocolValue: ExampleProtocol = a
print(protocolValue.simpleDescription)
// print(protocolValue.anotherProperty) // Uncomment to see the error
尽管protocolValue运行时的类型为SimpleClass,编译器把它当做ExampleProtocol变量,这意味着你无法使用这个类中实现协议的代码之外的变量和属性。
七、处理错误
1.可以用任何实现ErrorProtocol协议的类型来表征error。
enum PrinterError: ErrorProtocol {
case outOfPaper
case noToner
case onFire
}
2.用throw抛出错误。用throws表示函数可能会抛出错误。
func send(job: Int, toPrinter printerName: String) throws -> String {
if printerName == "Never Has Toner" {
throw PrinterError.noToner
}
return "Job sent"
}
3.用do-catch来捕捉错误并进行处理。在可能抛出错误的函数前加try关键字。可以在catch后面加上指定的error类型。
do {
let printerResponse = try send(job: , toPrinter: "Bi Sheng")
print(printerResponse)
} catch {
print(error)
}
可以捕捉多种类型的error:
do {
let printerResponse = try send(job: , toPrinter: "Gutenberg")
print(printerResponse)
} catch PrinterError.onFire {
print("I'll just put this over here, with the rest of the fire.")
} catch let printerError as PrinterError {
print("Printer error: \(printerError).")
} catch {
print(error)
}
4.可以用try?将结果转换为optional类型,如果函数发生error,则执行结果为nil,否则,就是一个包含函数返回值的optional值。
let printerSuccess = try? send(job: , toPrinter: "Mergenthaler")
let printerFailure = try? send(job: , toPrinter: "Never Has Toner")
5.用defer在函数返回之前写一个代码块。这个代码块无论函数是否抛出错误,都会执行。
这样可以在setup后紧接着写cleanup代码:
var fridgeIsOpen = false
let fridgeContent = ["milk", "eggs", "leftovers"]
func fridgeContains(_ food: String) -> Bool {
fridgeIsOpen = true
defer {
fridgeIsOpen = false
}
let result = fridgeContent.contains(food)
return result
} fridgeContains("banana")
print(fridgeIsOpen)
八、泛型
1、创建一个泛型函数或类型
func repeatItem<Item>(item: Item, numberOfTimes: Int) -> [Item] {
var result = [Item]()
for _ in ..<numberOfTimes {
result.append(item)
}
return result
}
repeatItem("knock", numberOfTimes:)
2、也可以构造泛型的枚举、类、结构和方法。
// Reimplement the Swift standard library's optional type
enum OptionalValue<Wrapped> {
case None
case Some(Wrapped)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some()
3、在类型名字后面用where来指定一些必要元素,来获得实现一定协议的类型、类型相同或者有某个特定子类的类型。
func anyCommonElements <T: SequenceType, U: SequenceType where T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, _ rhs: U) -> Bool {
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
anyCommonElements([, , ], [])
<T: Equatable>和<T where T: Equatable>是等效的。
Swift语法入门的更多相关文章
- Swift翻译之-Swift语法入门 Swift语法介绍
目录[-] Hello world - Swift 简单赋值 控制流 函数与闭包 对象和类 枚举与结构 协议和扩展 泛型 2014.6.3日,苹果公布最新编程语言Swift,Swift是一种新的编程语 ...
- Swift轻松入门——基本语法介绍和详细地Demo讲解(利用WebView打开百度、新浪等网页)
转载请务必注明出处(all copyright reserved by iOSGeek) 本文主要分为两个部分,第一部分介绍Swift的基本语法,第二部分讲解一个利用WebView来打开百度.sina ...
- Swift语法基础入门三(函数, 闭包)
Swift语法基础入门三(函数, 闭包) 函数: 函数是用来完成特定任务的独立的代码块.你给一个函数起一个合适的名字,用来标识函数做什么,并且当函数需要执行的时候,这个名字会被用于“调用”函数 格式: ...
- Swift语法基础入门四(构造函数, 懒加载)
Swift语法基础入门四(构造函数, 懒加载) 存储属性 具备存储功能, 和OC中普通属性一样 // Swfit要求我们在创建对象时必须给所有的属性初始化 // 如果没办法保证在构造方法中初始化属性, ...
- Swift语法基础入门二(数组, 字典, 字符串)
Swift语法基础入门二(数组, 字典, 字符串) 数组(有序数据的集) *格式 : [] / Int / Array() let 不可变数组 var 可变数组 注意: 不需要改变集合的时候创建不可变 ...
- Apple Swift编程语言入门教程
Apple Swift编程语言入门教程 作者: 日期: 布衣君子 2015.09.22 目录 1 简介 2 Swift入门 3 简单值 4 控制流 5 函数与闭包 6 对象与类 ...
- Swift语言入门之旅
Swift语言入门之旅 学习一门新的计算机语言,传统来说都是从编写一个在屏幕上打印"Hello world"的程序開始的.那在 Swift,我们使用一句话来实现它: printl ...
- swift新手入门视频教程-08-枚举
我自己录制的swift菜鸟入门,大家拍砖,有什么问题能够在这里留言. 主要内容: 枚举语法(Enumeration Syntax) 匹配枚举值与Swith语句(Matching Enumeration ...
- Swift高速入门之函数
函数 看一个函数的样例: func addNumbers( let a:Int,let b:Int)->Int{ return a+b; } 实现两个数相加.函数必须以func开头,后面是函数名 ...
随机推荐
- C++ essentials 之 union
Extraction from The C++ Programming Language 4th. edition, Bjarne Stroustrup [8.1] A struct is a seq ...
- hdu 2034 - 集合操作
题意:集合A,B,计算集合差A-B(求只在集合A内的数) 解法: 选用STL内的集合set 1.建立set 1: #include<set> 2: 3: set<int> ...
- uC/OS-II汇编代码
;*************************************************************************************************** ...
- python设计模式之--单例模式
python的单例模式就是一个类的实例只能自始自终自能创建一次.应用场景比如说数据库的连接池. #!/usr/bin/env python # coding=utf- class Foo(object ...
- MySQL的mysqldump工具的基本用法
导出要用到MySQL的mysqldump工具,基本用法是: shell> mysqldump [OPTIONS] database [tables] 如果你不给定任何表,整个数据库将 ...
- Java数据库——JDBC 2.0操作
可滚动的结果集 让结果集滚动起来 //================================================= // File Name : JDBC20_demo //-- ...
- Android学习笔记——Bundle
该工程的功能是实现不同线程之间数据的传递 以下代码是MainActivity.java中的代码 package com.example.bundle; import android.app.Activ ...
- ecshop 后台【左侧新增菜单】
模板文件admin/template/menu.htm admin/includes/inc_menu.php 菜单排序(链接) langagues/zh_cn/admin/common.php 语 ...
- return columns.All(new Func<string, bool>(list.Contains));
internal static bool VerifyColumns(SqlConnection conn, string table, params string[] columns) ...
- JavaWeb学习总结(三)——Tomcat服务器学习和使用(二) 包含https 非对称秘钥 NB
JavaWeb学习总结(三)--Tomcat服务器学习和使用(二) 一.打包JavaWeb应用 在Java中,使用"jar"命令来对将JavaWeb应用打包成一个War包,jar命 ...