学习一门新的编程语言要多久?答案是随着你的经验的增加,学习花费的时间越来越短。当然,这也和新语言的不断演变进化有关系。
我利用周末两天时间,把《Swift Programming Language》中文版整整的细看了一遍,然后为了总结提取 Swift 的主要语言特性,又把这本书快速过了第二遍。
根据我的番茄钟粗略统计,我看书学习第一遍大约花了 5 小时(包括边学,边在 XCode 试验的时间),第二遍主要是快速过一遍主要特性,将主要示例代码提取出来,大约花了 3.5 小时。
连我自己都觉得有点难以置信,总共只需要 8 小时,就可以基本入门一门新语言了。
很多时候,我们想学习某个东西,但是却一直停留在想一想的状态,迟迟都未动手。究其原因,大概是如下几个原因吧:
-
恐惧未知。对未知的东西没有把握,怕太难,怕需要太长时间学,所以能拖就拖。
-
注意力不能集中。连续玩几个小时游戏一点不累,看半小时书就感觉身心俱疲。
番茄工作法在这个时候就起作用了,告诉自己,不想太多,开始一个番茄钟试试,在这 25 分钟内,只关注这 25 分钟内要看的内容。然后,很自然的,障碍被逐个击破,番茄钟一个接着一个。
以下是我学习 Swift 的代码总结,可用于之后速查。
代码:https://github.com/coderzh/CodeTips/blob/master/swift.swift
/*
swift.swift:
Swift 速学速查速用代码手册
Source: github.com/coderzh/CodeTips/blob/master/swift.swift
Author: coderzh(github.com/coderzh)
Blog: http://blog.coderzh.com
参考:《Swift Programming Language》
*/
import Cocoa
// 0. 注释
/*
块注释
行尾分号可不用
*/
// 1. Hello World
print("Hello Swift")
// 2. 常量变量类型
let constValue = 3.14
var variable = 18
variable += 1
// 指定类型
let age: Int = 18
// 多重赋值
var (a, b) = (1, 2)
// 匿名占位符
(_, b) = (3, 4)
// 类型会自动推导
let name = "It's a string"
let gravity = 0.98 // 默认 double
// 永远不做隐式转换,必须自己强转
let sum = Double(age) + gravity
// 运算:+, -, *, /, % 求余
// 比较:<, >, ==, >=, <=, !=
// === 恒等,是否为同一个对象
// !== 不恒等
// 位运算:~x 取反,& 与,| 或,^ 异或,<< 左移动,>> 右移
// 溢出运算符 &+ &- &* &/ &% ,这样溢出部分就会丢掉,不会出错,比如:
var willOverflow = UInt8.max
willOverflow = willOverflow &+ 1 // = 0
// 类型
let b1 = true
let i32: Int32 = 6
let f64: Float64 = 3.1415
// 字符串
let str = "swift"
// 字符串连接,使用\()
var hello = "hello \(str)"
let count = str.characters.count
let c = hello[hello.startIndex]
for i in hello.characters.indices {
print("\(hello[i])")
}
hello.insert("!", atIndex: hello.endIndex)
hello.insertContentsOf(" there".characters, at: hello.endIndex.predecessor())
hello.removeAtIndex(hello.endIndex.predecessor())
hello.hasPrefix("hello")
hello.hasSuffix("swift")
let unicode = "你好 swift"
unicode.characters.count // 8
for codeUnit in unicode.utf8 {
print("\(codeUnit)", terminator: "")
}
if hello == unicode{
}
// 数组
var shoppingList = ["test", "book", "bike"]
shoppingList[2] = "joke"
shoppingList.append("bus")
shoppingList.insert("foo", atIndex: 0)
shoppingList.removeAtIndex(0)
// 类似 slice
shoppingList[0..<2] // ["test", "book"]
shoppingList[0...2] // ["test", "book", "joke"]
for item in shoppingList {
print(item)
}
for (index, value) in shoppingList.enumerate() {
print("\(index): \(value)")
}
let emptyArray = [String]()
var someInts = [Int]()
var someInts2 = [Int](count: 3, repeatedValue: 8) // [8, 8, 8]
var someInts3 = [Int](count: 3, repeatedValue: 2)
// 任意类型数组
var anyArray = [Any]()
anyArray.append(1)
anyArray.append("book")
someInts = someInts2 + someInts3 // [8, 8, 8, 2, 2, 2]
// 元组
let httpResponse = (404, "Not Found")
print(httpResponse.0)
// 集合 Sets
var setBooks: Set<String> = ["book1", "book2"]
// 自动推导
var setBooks2: Set = ["book1", "book2", "book3"]
setBooks.intersect(setBooks2) // 交集
setBooks.exclusiveOr(setBooks2) // 非交集
setBooks.union(setBooks2) // 并集
setBooks.subtract(setBooks2) // 减集
setBooks.isSubsetOf(setBooks2)
setBooks2.isSupersetOf(setBooks)
setBooks.isStrictSubsetOf(setBooks2) // 被包含且不相等
// 字典
var map = [
"Malcolm": "hehe",
"Keylee": 123,
]
map["Keylee"] = 166
var namesOfInt = [Int: String]()
namesOfInt[10] = "ten"
if let oldValue = namesOfInt.updateValue("Ten", forKey: 10) {
print("\(oldValue)")
}
if let name = namesOfInt[8] {
print("\(name)")
} else {
print("not exist 8")
}
for (intKey, strValue) in namesOfInt {
print("\(intKey):\(strValue)")
}
// namsOfInt.values
for intKeys in namesOfInt.keys {
}
let intKeys = [Int](namesOfInt.keys)
// 可空变量,用 ?
var optionalString: String? = nil
if let name = optionalString {
print("hello \(name)")
}
// 3. 流程控制
// 循环
// [0, 4)
for i in 0..<4 {
print("print \(i)") // 4 times
}
// [0, 4]
for i in 0...4 {
print("print \(i)") // 5 times
}
var i = 0
while i < 2 {
print("\(i)")
i += 1
}
repeat {
print("\(i)")
i += 1
} while i < 5
// 判断
if i < 5 {
} else if i < 10 {
} else {
}
// 强大的 switch
// 不需要 break
switch i {
case 1, 2, 3:
print("123")
case 5:
print("5")
case 6..<10:
print("6-9")
default:
print("default")
}
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("0, 0")
case (_, 1):
print("y is 1")
case (-2...2, -2...2): // 区间
print("from (-2,-2) to (2, 2)")
case (let x, 0): // 值绑定
print("\(x)")
case let (x, y) where x == y: // where
print("x == y")
case (10, 11):
fallthrough // 贯穿,继续向下
default:
print("default")
}
// 控制转移
// continue break fallthrough retrun throw
// 带标签
i = 0
gameLoop: while i > -1 {
i = i + 1
if i > 3 {
break gameLoop
}
}
// 提前退出(提前返回)
func greet(person: [String:String]) {
guard let name = person["name"] else {
return
}
print("\(name)")
}
greet(["age":"18"])
// 4. 函数
func greet(name: String, day: String) {
print("Hello \(name), today is \(day)")
}
// 第二个参数默认需要指定名称
greet("tom", day: "2016")
func sum(a: Int, b: Int) -> Int {
return a + b
}
sum(1, b: 2)
// 多重返回值
func minMax(array: [Int]) -> (min: Int, max: Int) {
// ...
return (0, 1)
}
// 可选返回值加 ?
func minMax2(array: [Int]) -> (min: Int, max: Int)? {
if array.isEmpty { return nil }
return (0, 1)
}
// 指定外部参数名
func sayHello(to person: String, and anotherPerson: String) {
print("Hello \(person) and \(anotherPerson)")
}
sayHello(to: "coderzh", and: "tom")
// 忽略外部参数名,使用 _
func sayHello2(person: String, _ anotherPerson: String) {
print("Hello \(person) and \(anotherPerson)")
}
sayHello2("coderzh", "jack")
// 默认参数
func someFunction(p: Int = 10) {
print("\(p)")
}
someFunction()
// 可变参数
func sum(numbers: Int...) -> Int {
var total = 0
for n in numbers {
total += n
}
return total
}
sum(1, 2, 3, 4, 5)
// 参数默认是常量类型,如需指定变量类型,前面加 var(swift 3 将移除 var)
func alignRight(var string: String, totalLength: Int, pad: Character) -> String {
string = string + "!"
return string
}
// 传入传出参数 inout
func swap(inout a: Int, inout _ b: Int) {
let temp = a
a = b
b = temp
}
var someInt = 7
var anotherInt = 8
// inout 参数必须加 &
swap(&someInt, &anotherInt)
// 函数类型,函数变量
var sumFunc: (Int, Int) -> Int = sum
sumFunc(1, 2)
// 函数可做参数
func doSum(handler:(Int, Int) -> Int, _ a: Int, _ b: Int) {
handler(a, b)
}
// 函数可做返回值
func getSum() -> (Int, Int) -> Int {
// 函数可嵌套
func someFunc(a: Int, b: Int) -> Int { return a + b }
return someFunc
}
doSum(sum, 2, 3)
// 闭包
// 闭包是引用类型
let reversed2 = shoppingList.sort({a, b in a < b})
let r = shoppingList.sort({ $0 < $1 })
let r2 = shoppingList.sort(<)
let r3 = shoppingList.sort{ $0 < $1 }
// 非逃逸闭包(noescape closure)
// 闭包只能在函数内执行,不能「逃逸」出去
func someClosure(@noescape closure: () -> Void) {
closure()
}
// 自动闭包(这样不用写花括号了?)
func autoClosure(@autoclosure provider: () -> String) {
provider()
}
autoClosure(shoppingList.removeAtIndex(0))
// 5. 枚举(一等公民,十分强大)
// 值类型
enum Rank: Int {
case Ace = 1
case Two, Three
}
var ace = Rank.Ace // Ace
Rank.Ace.rawValue // 1
let ace1 = Rank(rawValue: 1) // Ace
ace = .Two
enum ServerResponse {
case Result(String, String)
case Error(String)
}
// 可失败构造器
enum TemperatureUnit {
case Kelvin, Celsius, Fahrenheit
init?(symbol: Character) {
switch symbol {
case "K":
self = .Kelvin
case "C":
self = .Celsius
case "F":
self = .Fahrenheit
default:
return nil
}
}
}
let success = ServerResponse.Result("6:00am", "6:00pm")
let failure = ServerResponse.Error("Out of cheese")
switch success {
case let .Result(sunrise, sunset):
let serverResponse = "sunrise at \(sunrise), sunset at \(sunset)"
case let .Error(error):
let serverResponse = "Error \(error)"
}
// 枚举递归...
enum ArithmeticExpression {
case Number(Int)
indirect case Addition(ArithmeticExpression, ArithmeticExpression)
indirect case Multiplication(ArithmeticExpression, ArithmeticExpression)
}
func evaluate(expression: ArithmeticExpression) -> Int {
switch expression {
case .Number(let value):
return value
case .Addition(let left, let right):
return evaluate(left) + evaluate(right)
case .Multiplication(let left, let right):
return evaluate(left) * evaluate(right)
}
}
// 计算 (5 + 4) * 2
let five = ArithmeticExpression.Number(5)
let four = ArithmeticExpression.Number(4)
let sum2 = ArithmeticExpression.Addition(five, four)
let product = ArithmeticExpression.Multiplication(sum2, ArithmeticExpression.Number(2))
print(evaluate(product)) // 输出 "18”
// 6. 类和结构体
// 结构体是值类型,类是引用类型
class SomeClass {
var width = 0
var height = 0
// class 不需要 mutating
func incrementWidth() {
self.width += 1
}
// 下标操作: [n]
subscript(index: Int) -> Int {
get {
return 0
}
set(newValue) {
// set from newValue
}
}
}
let s1 = SomeClass()
struct SomeStruct {
static var someValue = 100
static func staticFunc() -> Int {
return 1
}
var x = 0
var y = 0
var doubleX: Int {
get {
return x * 2
}
set {
x = newValue / 2
}
}
// readonly
var doubleY: Int {
return y * 2
}
var total: Int {
willSet(newTotal) {
print("will set \(newTotal)")
}
didSet {
print("old: \(oldValue), new: \(total)")
}
}
// 如果会改变类成员,比如声明 mutating
mutating func incrementX() {
self.x += 1
}
}
var s2 = SomeStruct(x: 2, y: 3, total: 10)
s2.doubleX = 10 // s2.x == 5
s2.total = 5
// 继承
class Animal {
// 构造函数
init() {
}
// 必要构造器,子类必须实现,而且声明为 required
required init(name: String, age: Int) {
}
func makeNoise() {
print("wowowo")
}
}
class Cat: Animal {
var name: String = ""
var nickName: String = ""
init(name: String) {
super.init()
self.name = name
}
init(fromNickName nickName: String) {
super.init(name: nickName, age: 18)
self.nickName = nickName
}
// 便利构造器:必须调用其他构造器
convenience override init() {
self.init(name: "UnKnown")
}
// 可失败构造器
init?(age: Int) {
super.init(name: "UnKnown", age: age)
if age < 0 { return nil }
}
required init(name: String, age: Int) {
self.name = name
super.init(name: name, age: age)
}
// 析构,默认会先调用父类的析构
deinit {
}
override func makeNoise() {
print("miaomiaomiao")
}
}
final class CannotInheirt {
}
// 7. 自动引用计数 ARC
// weak 弱引用
// unowned 无主引用
// 8. 可空链式调用
/* For example:
if let johnsStreet = john.residence?.address?.street {
print("John's street name is \(johnsStreet).")
} else {
print("Unable to retrieve the address.")
}
*/
// 如果确定有值,使用!
// let roomCount = john.residence!.numberOfRooms
// 9. 错误处理
enum CustomError : ErrorType {
case Invalid
case OutOfRange
}
func makeASandwich() throws -> String {
throw CustomError.Invalid
}
do {
try makeASandwich()
} catch CustomError.Invalid {
print("Invalid")
}
// 可空
let x = try? makeASandwich()
// 使错误传递失效,肯定不throw,否则 assert
// let y = try! makeASandwich()
// defer 和 Golang 里的 defer 一样,用来退出清理
/*
func processFile(filename: String) throws {
if exists(filename) {
let file = open(filename)
defer {
close(file)
}
while let line = try file.readline() {
// 处理文件
}
// 在这里,作用域的最后调用 close(file)
}
}
*/
// 10. 类型转换: is as (和 CSharp 类似)
// 任意类型:
// 1. AnyObject 任何 class 类型实例
// 2. Any 任何类型
// 11. 扩展(extension,类似 CSharp 里的扩展方法,但是貌似更强大)
// 比如:扩展内置类型 Double
// 几乎一切都可扩展,用到时再查用法吧
extension Double {
var km: Double { return self * 1_000.0 }
var m : Double { return self }
var cm: Double { return self / 100.0 }
var mm: Double { return self / 1_000.0 }
var ft: Double { return self / 3.28084 }
}
// 12. 协议(类似接口的东西)
// 当同时有继承时,先写继承,再写协议,协议可以有多个
protocol FullyNamed {
var fullName: String { get }
}
// 协议也可继承
protocol SubFullyNamed: FullyNamed {
var nickName: String { get }
}
struct Person: FullyNamed{
var fullName: String
}
// 专属协议,指定只能用在 class 上
protocol ClassOnlyProtocol: class, FullyNamed {
}
protocol Aged {
var age: Int { get set }
}
// 协议合成
func foo(pro: protocol<FullyNamed, Aged>, base: Any) {
// 协议判断
if let p = base as? Aged {
print(p.age)
}
}
// 可选协议(既然是协议,还可选,醉了)
// @objc protocol
// 13. 泛型
func swapTwoValues<T>(inout a: T, inout _ b: T) {
let temporaryA = a
a = b
b = temporaryA
}
// 泛型约束
func someFunction<T: SomeClass, U: FullyNamed>(someT: T, someU: U) {
// 这里是函数主体
}
// Where
/*
func allItemsMatch<
C1: Container, C2: Container
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
(someContainer: C1, anotherContainer: C2) -> Bool {
}
*/
// 14. 访问控制
// public internal(默认) private
// 加在 class var 等前
作者:CoderZh
微信关注:hacker-thinking (代码随想)
本文出处:https://blog.coderzh.com/2016/04/24/swift-tips/
文章版权归本人所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。