SWIFT入门

接上次数组后面

1集合

集合也是一种容器,集合内数字没有顺序,是直接通过哈希码来查找

//集合通过哈希码找值
//哈希码(hash code)/散列码
//例子 MD5(数据库存储密码) /SHA-1 (是摘要而不是加密)
//1.1创建一个集合
var a :Set<Int> = [5,5,66,4,54,86,45,4,56,4]
print(a)
//1.2集合的遍历
for x in a {
    print(x)
}
a.insert(1) //1.3在集合中插入一个数
a.remove(5)//1.4.1删除集合某个数
//a.removeAll()1.4.2全部删除
var b :Set<Int> = [64,6,45,64,6,4,64,6,4,6,4]
print(a.intersect(b))//1.5.1交集
print(a.union(b))//1.5.2并集
print(a.subtract(b))//1.5.3差集
print(a.isDisjointWith(b))//1.5.4判断2个集合是否相交,返回Bool(ture or false)
print(a.isSupersetOf(b))//1.5.5a是否是b的超集(a完全包含于b)返回Bool

2字典

字典:存放键值对组合的容器,字典中每个元素有2部分构成,冒号前面是键,后面是值

//2.1创建一个字典
var dict:[String: String] = ["thy":"你好","abs":"阿巴瑟"]
print(dict["abs"])
//字典元素可空,通过键获取对应的值(可空类型,因为给的键有可能没有与之对应的值)
//key ->value
dict["yld"] = "伊利丹"//2.2添加
print(dict)
//dict.removeValueForKey("thy")//2.3删除
//print(dict["thy"])
//或者doct["thy"] = nil同样删除
dict["thy"] = "好"
print(dict)
//2.4遍历
//2.4.1查找值
for value in dict.values {
    print(value)
}
//2.4.2查找键
for key in dict.keys{
    print("\(key)")
}
//2.4.3直接通过一个元组获得字典中的键和值(原始类型)
for(key,value) in dict {
    print("\(key)-->\(value)")
}

函数

1关于函数的构建

完整的函数构建是:
func 函数名(外部参数名 内部参数名 :参数类型)->返回值类型{
函数执行
}
外部参数名是函数外使用的名称,内部参数名是在函数内使用的名称

func myMin(a x:Int, b y:Int)->Int{
    //x,y为内部名
    return x<y ? x:y
}
//a,b外部参数名
print(myMin(a:3,b:5))

tip:1如果参数名只有一个,说明内外参数名一样
tip:2从第二个参数开始,如果外部参数名为空,在调用函数时就可以直接输入

func hello(personname:String, _ alreadyGreeted:Bool = false) ->String {
    var greet:String
    if alreadyGreeted {
     greet = "hello"+personname+"!"
    }else{
        greet = "怎么又是你"+personname+"!"
    }
    return greet
}
//调用函数
//函数名(参数值)
print("\(hello("古尔丹",true))")
//或者
//没有赋值默认为FALSE
let hel = hello("伊利丹")
print(hel+"噢,不好意思我看错了")

tip:3函数的参数可以是任意多个,使用可变参数列表,也可以不含参数

//使用函数求和
func sum(nums:Int...)->Int{
    var total = 0
    for num in nums {
        total += num
    }
    return total
}
print(sum())
print(sum(1,2,3,4))
print(sum(231,51,5,4135,153,13,5,1435,435,43,541,53,1,231,351,30))

tip:4函数也可以使用元组返回多个值,也可以返回空值,如果为空,可以省略,也可以写->void

//使用函数求最大值和最小值
func minMax(array: [Int]) -> (min: Int, max: Int)? {
    if array.isEmpty { return nil }
    var currentMin = array[0]
    var currentMax = array[0]
    //循环输出array内的值
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}
if let b = minMax([1,5,45,4,534,534,4561,21,2,15,4,21]){
print(b.min)
print(b.max)
}else{
    print("空的")
}

tip:5关于inout,函数的另一种输入输出方法

//交换值
func swap (inout x:Int,inout _ y:Int) -> Void {
    let temp = x
    x=y
    y=temp
}
var x=5,y = 10
//函数调用的传参都是传值
//正常情况调用函数时,你不能传进去改变再拿出来的
//所有使用INOUT的参数都要加&
swap(&x, &y)
print("x=\(x),y=\(y)")

关于函数的几个练习
1.输入年月日,计算它是这年的第几天

func dayofyear(year:Int,_ mouth:Int,_ day:Int)->Int{
    //数组传入12个值
    var dayofmouth = [31,28,31,30,31,30,31,31,30,31,30,31]
    if isLeapYear(year) {
        //如果为闰年,2月为29天
        dayofmouth[1] = 29
    }
    var sum = 0
    for days in dayofmouth[0..<mouth - 1]{
        sum += days
    }
    return sum + day
}
//判断平闰年 ,true为闰年,fasle为平年
func isLeapYear(year:Int)->Bool{
    return year % 4 == 0 && year % 100 != 0 || year % 400 == 0
}
print("请输入某年某月某日,用空格隔开如:2016 8 8")
let y = inputInt()
let m = inputInt()
let r = inputInt()
print("\(y)年\(m)月\(r)日是\(y)年的第\(daysOfYear(y,m,r))天")
print("\(y)年\(m)月\(r)日是\(y)年的第\(dayofyear(y,m,r))天")

2.输入三个值,判断是否能构成三角形

func isvaildForTringle(a:Double,_ b:Double,_ c:Double)->Bool{
    //assert 断言,如果满足条件,则继续往下执行,否则执行ASSert的内容,但只能用于打印错误信息,并不能参与计算
    assert(a>0&&b>0&&c>0, "三角形的边长必须大于0")
    return a+b>c&&a+c>b&&b+c>a
}
print(isvaildForTringle(2, 3, 4))
print(isvaildForTringle(1,2,3))
print(isvaildForTringle(3, 3, 3))

3.根据一个函数传入2个整数m,n计算m加到n

func reAdd(m:Int,_ n:Int)->Int {
    let (m,n) = m > n ? (n,m):(m,n)
    var sum = 0
    for m in m...n{
        sum+=m
    }
    return sum
}
print(reAdd(5,10))

4.根据不同时间,提示不同的问候语


func sayhello(name:String)->String{
   //定义时间date类型为NSDATE()
    let date = NSDate()
    //拿到当前的日历
    let cal = NSCalendar.currentCalendar()
    //拿到Date类型的小时
    let hour = cal.component(.Hour, fromDate: date)
    var greet : String
    //区间可以重叠,执行第一个满足条件的
    switch hour {
    case 0...5:
        greet = "怎么还没睡啊"
        //fallthrough,无条件执行下一条且不会去其他分支
    case 6...10:
        greet = "早起的鸟儿有虫吃"
    case 11...13:
        greet = "中午好"
    case 14...18:
        greet = "下午好"
    default:
        greet = "晚上好"
    }
    return name + "," + greet + "!"
}
print("\(sayhello("丹丹"))")

tip:5关于递归:递归是一个函数直接或者间接的调用函数自身
关键点:1.递归公式
2.收敛条件(什么时候停止)
3.一般用于循环难以解决的问题
例如:哈尼塔数

//几何倍数增长
var current = 1
func hanoi(n:Int,_ a:String,_ b:String,_ c:String){
    if n > 0 {
    //据说等人手动完成n=64时,地球就毁灭了
    hanoi(n-1,a,c,b)
    print("\(current),\(a)-->\(b)")
        current += 1
    hanoi(n-1, c, b, a)
    }
}
print(hanoi(8,"a","b","c"))

2关于函数闭包

一个函数可以将另一函数作为参数,而在数学中我们称这为复合函数,而在传入函数时,调用无名函数即闭包函数,我们有多种表现方式

//使用加减乘除
func sum(a:Int,b:Int) -> Int {
    return a+b
}
func mul(a:Int,b:Int) -> Int {
    return a*b
}
func hello(x:Int,y:Int)->Int{
    return 0
}
func foo(Array: [Int]) -> Int{
    var sum = 0
    for x in Array[0..<Array.count]{
        sum += x
    }
    return sum
}
func fortoo(array: [Int],fn:(Int,Int)->Int)->Int{
    var sum = 0
    for x in (array) {
        sum += x
    }
    return sum
}
//在Swift中函数是一种类型,这意味着函数可以作为变量或者常量的类型
//同理函数可以作为另一个函数的参数,也可以返回另一个函数
var fn = sum
fn = mul
fn = hello
let a = [2,31,15,4,5,45,4]
//当调用foo函数时第二个参数可以传什么?

//1.所有有自定义类型的(Int,Int) ->Int类型的函数
print(fortoo(a, fn: sum))
//2.传入二元运算符:+-*/%(因为运算符也是函数)
print(fortoo(a , fn: +))
//3.传入匿名函数(闭包)
//3.1完整闭包写法
print(fortoo(a, fn: {(a:Int,b:Int)->Int in
     return a+b}))
//3.2省略掉类型个不必要的括号
print(fortoo(a, fn: {a,b in a+b}))
//3.3省略参数名
print(fortoo(a, fn: {$0+$1}))
//3.4尾随闭包
print(fortoo(a) { (a,b) -> Int in
    return a + b })
print(fortoo(a) { $0+$1})

例子:根据字符串长短进行排序

var array = ["game","lol","cf","wow","dnf","pal","internationlization"]
//array.sortInPlace()
//array.sortInPlace(>)
//array.sortInPlace() { $0 > $1}
//如果函数的最后一个参数是闭包可以写成尾随闭包的形式
//也就是将闭包放到函数参数的圆括号外面写在一堆花括号中
//如果函数后面有尾随闭包且函数的括号中没有参数,那么函数的圆括号也可以省略(仅限于有尾随闭包的场景)
array.sortInPlace { $0 > $1}
print(array)
//字符串长短排序
array.sortInPlace { (one, two) -> Bool in//省略return
    one.characters.count < two.characters.count
}
//极简版
array.sortInPlace{
    $0.characters.count<$1.characters.count
}
//多条语句不能省略return
//根据字符串长短排序
array.sortInPlace{
    if $0.characters.count == $1.characters.count {
     return $0 < $1
    }
    return $0.characters.count<$1.characters.count
}
print(array)

3关于过滤,映射,合并

tip:$0表示取第一个参数的值,$1表示取第二个参数
1.过滤Filter

let array = [23,37,96,55,40,92,68,88]
//取得所有大于50的数
let newarray1 = array.filter {
    $0 > 50
}
print(newarray1)
//取得所有偶数
let newarray2 = array.filter {
    $0%2 == 0
}
print(newarray2)

2.映射Map

let array = [23,37,96,55,40,92,68,88]
let newarray3 = array.map { (x:Int) -> Int in
    return x*x
}
print(newarray3)
//所有有数除2取整
let newarray4 = array.map {
    $0/2
}
print(newarray4)

3.缩减、合并、规约

let array = [23,37,96,55,40,92,68,88]
//将所有数以加法合并,0表示开始值
let newarray5=array.reduce(0, combine: +)
print(newarray5)
//将所有数以乘法合并,1表示开始值
let newarray6=array.reduce(1, combine: *)
print(newarray6)
//找出数组的最大数
let newarray7 = array[1..<array.count].reduce(array[0]) {
    $0 > $1 ? $0 : $1
}
print(newarray7)
//字符串数组和并成一个字符串
let strarray = ["strom","gold","water","tree"]
let newarray8 = strarray.reduce("") {
    //在每个字符串间用空格隔开,当和成一个类后再与后面的类合并
    $0+" "+$1
}
print(newarray8)

关于类

个人觉得类就是从现实世界中选择某类东西,然后在电脑上给其命名,然后从现实中抽象出它的属性,它的行为等等,然后写进电脑,这样电脑就可以自己模拟现实中的这类事物。
感觉新建类,就有点自己是创世者一样,我可以创建我已知的,也可以创建我未知,但是幻想的事物,我只要赋予它我希望他有的属性,那它就是存在的了。
总之,新建类就是摆脱之前的虚无的逻辑,开始具体的搭建一个世界。

新建类

新建类:首先,一般来说,要新建类,首先需要新建一个SWIFT文件,将这个类的所有属性和动作都在里面以常量,变量,或者函数的形式表达清楚,而调用类,用来完成某件事则在main.swift内完成。
新建好文件后在里面定义类,创建新的类型,而变量在类内就该叫属性,函数在类内就叫动作。而这些都源于都现实事物的抽象。
定义好类后,就可以在main函数内创建对象,然后通过给对象发消息来解决问题,而这也就是我们所熟识的面向对象的编程。
举个栗子:
首先在新建一个Student.swift

class student {
    //变量定义到类的外面就叫变量 - varliable
    //变量定义到类的里面就叫属性 - property
    //数据抽象,找到和学生相关的属性(找名词,和学生相关)
    var name : String
    var age : Int
    //初始化方法(构造方法/构造器)-constructor,创建对象要使用的方法
    //自己理解:给定义的类赋值
    init (name:String,age:Int){
        //self是自身属性
        self.name = name
        self.age = age
    }
    //函数写到类的外面就叫函数 - function
    //函数写到类的里面就叫方法 - method
   //行为抽象,找到和学生相关的方法(找动词),以动词命名
    func eat()->Void{
        print("\(name)正在吃饭")
            }
            
    func study(courName:String) {
        print("\(name )正在学习\(courName).")

    }
    
    func playComputer(playname:String){
        if age >= 13 {
            print("\(name)正在玩\(playname)")
        }else {
            print("亲爱的\(name),我们建议你玩连连看")
        }
    }
}

然后在main.swift内创建,并发送信息

//步骤2:创建对象(调用初始化方法)
let stu1 = student(name: "玛法里奥", age: 100000)
//步骤3:给对象发消息(通过给对象发消息来解决问题)
stu1.eat()
stu1.study("德鲁伊之道")
stu1.playComputer("炉石传说")
let stu2 = student(name: "安度因", age: 12)
stu2.eat()
stu2.study("论如何偷牌")
stu2.playComputer("炉石传说")

这就是一次简单的面向对象的编程。然后,开始尝试使用面向对象的方法解决一些稍复杂的问题。例如:之前的求泳池的造价问题,通过抽象,我们可以知道,这个问题关键在于解决同心圆的问题,那么我们需要新建一个类,它叫圆,它有一个对我们很有用的主要属性半径,也有一个对同心圆不怎么重要的属性:圆心;还有2个通过计算得到的属性周长和面积。知道这些,开始新建类:
Circle.swift内

//0.发现类
//-在对问题的描述中找名词和动词
//-名词会成为类或者类中的属性,动词会成为类中的方法
//1.定义类
//2.数据抽象(属性)
//3.行为抽象
//4.初始化方法

//public (公开)
//internal(内部的)-默认
//-private(私有的)
import Foundation
public class Circle {
    //建议写成私有
    //存储属性(保存和圆相关的数据属性)-stord property
    private var radius:Double
    var center : point
    //定义类要求所有的属性都要有值
    init(center:point,radius:Double){
        self.center = center
        self.radius = radius
    }
    //要公开方法要先公开类
    //Swift和oc一般用名词表示得到某值
    //通常获得某个值得方法都可以设计成计算属性
    //计算属性(通过对存储属性做运算得到的属性)-computational property
    var perimeter:Double {
        //圆的周长只是一个只读属性
        //所以此处只有get{}没有set{}
        get {return 2 * M_PI * radius}
    }
    
    var area : Double {
        get{return M_PI * radius * radius}
    }
}

然后在main.swift内解决问题:

//2创建对象
 let r = 5.5
let small = Circle(radius: r)
let big = Circle(radius: r+3)
//3.对对象发消息(调用对象方法)
let fancePrice = big.perimeter*1.5
//%。1f是保留小数
print(NSString(format: "围墙造价为:¥%.1f元",fancePrice))
let aislePrice = (big.area-small.area)*3.5
print(NSString(format: "过道造价为:¥%.1f元", aislePrice))

再使用该方法解决猜数字游戏的问题:
首先顶一个一个机器人类,它能产生随机数,它能计算回合数,它能对你输的数字进行判断,并给出回应。
Robot.swift

class Robot {
    var answer : Int//正确答案
    var counter:Int = 0//猜的次数
    var hint:String//提示信息
    //初始化方法(如果不初始化,在开始定义是添加自定义值)目的是保证所有的存储属性都有初始值
    init () {
        answer = Int(arc4random_uniform(100))+1
        //counter = 0
        hint = ""
    }
    //行为抽象
    //判断
    func judge(thyAnswer:Int) -> Bool {
        counter += 1
        if thyAnswer < answer{
            hint = "大一点"
        }
        else if thyAnswer > answer {
            hint="小一点"
        }
        else {
            hint = "恭喜你猜对了!你总共猜了\(counter)次"
            return true
        }
        return false
    }
}

main.swift内我们来玩这个游戏

//创建一个机器人
let r = Robot()
//定义一个参数
var isgameover = false
repeat{
print("请输入一个数")
//输入方法前上一篇有详细介绍
    let thyAnswer = inputInt()
    isgameover = r.judge(thyAnswer)
    print(r.hint)
}while !isgameover

if r.counter>7 {
    print("智商捉急")
}

猜数字的游戏就这样完成了。接下来完成一个稍复杂的网页上面的回合制自动攻击的小游戏,奥特曼打怪兽。
首先定义奥特曼类:

//随机数类,可以全局调用
func randomInt(min: UInt32, _ max: UInt32) -> Int {
    return Int(arc4random_uniform(max - min + 1) + min)
}

class Ultraman {
    //名称
    private var _name: String
    //血量
    private var _hp: Int
    //蓝量
    private var _mp: Int
    //存活属性
    var isAlive: Bool {
        get { return _hp > 0 }
    }
    //获取数据
    var name: String {
        get { return _name }
    }
    
    var hp: Int {
        get { return _hp }
        set { _hp = newValue > 0 ? newValue : 0 }
    }
    
    var mp: Int {
        get { return _mp }
        set { _mp = newValue > 0 ? newValue : 0}
    }
    
    init(name: String, hp: Int, mp: Int) {
        _name = name
        _hp = hp
        _mp = mp
    }
    //攻击行为
    func attack(monster: Monster) {
        let injury = randomInt(15, 20)
        monster.hp -= injury
        if _mp >= 100{
            _mp = 100
        }else {
           _mp += 5
        }
    }
    //大招行为
    func hugeAttack(monster: Monster) {
        let injury = monster.hp * 3 / 4 >= 50 ? monster.hp * 3 / 4 : 50
        monster.hp -= injury
        
    }
    //魔法攻击行为
    func magicalAttack(monsters: [Monster])->Bool {
        if _mp >= 30 {
        for monster in monsters {
        //对敌方全体造成伤害
            if monster.isAlive {
                let injury = randomInt(5, 15)
                monster.hp -= injury
            }
        }
             _mp -= 30
            return true
        }
        return false
    }
}

怪兽类

class Monster {
     //名称
    private var _name: String
    //血量
    private var _hp: Int
    //存活
    var isAlive: Bool {
        get { return _hp > 0 }
    }
    //获取初始值
    var name: String {
        get { return _name }
    }
    
    var hp: Int {
        get { return _hp }
        set { _hp = newValue > 0 ? newValue : 0 }
    }
    
    init(name: String, hp: Int) {
        _name = name
        _hp = hp
    }
    //攻击
    func attack(ultraman: Ultraman) {
        let injury = randomInt(5, 10)
        ultraman.hp -= injury
    }
}

main内进行对打:

// 奥特曼打小怪兽
func pickOneMonster(mArray:[Monster])->Monster{
    var monster:Monster
    repeat {
    let randomIndex = randomInt(0, UInt32(mArray.count-1))
    monster = mArray[randomIndex]
    }while !monster.isAlive
    return monster
}
//判断小怪兽是否全部死光
func isAllDead(mArray:[Monster])->Bool{
    for monster in mArray {
        if monster.isAlive{
            return false
        }
    }
    return true
}
//创建一个奥特曼
let u = Ultraman(name: "艾斯", hp: 300, mp: 80)
//创建多个怪兽
let mArray = [Monster(name: "巴尔塔星人", hp: 120),
Monster(name: "哥斯拉", hp: 250),
Monster(name: "艾蒙", hp:180),
Monster(name: "萨格拉斯", hp:200)]
//回合数
var round = 1
repeat {
     print("========第\(round)回合========")
    let m = pickOneMonster(mArray)
    let factor = randomInt(1, 10)
switch factor {
case 1...7:
    print("\(u.name)奥特曼使用了普通攻击")
    u.attack(m)
    if m.isAlive {
        m.attack(u)
    }

case 8,9:
    print("\(u.name)奥特曼使用了激光扫射")
    if u.magicalAttack(mArray){
    for m in mArray{
        if m.isAlive{
            m.attack(u)
        }
    }
    }else{
        u.attack(m)
        if m.isAlive {
        m.attack(u)
    }
    }
default:u.hugeAttack(m)
    print("\(u.name)奥特曼使用七彩光")
     if m.isAlive {
     m.attack(u)
    }
    }
    print("\(u.name)奥特曼生命值: \(u.hp)")
    print("\(u.name)奥特曼魔法值: \(u.mp)")
    for m in mArray{
    print("\(m.name)小怪兽生命值: \(m.hp)")
    }
    round += 1
} while u.isAlive && !isAllDead(mArray)

if u.isAlive {
    print("\(u.name)奥特曼获胜!!!")
}
else {
    print("小怪兽获胜!!!")
}

做完这个,来说下关于类的注释
例如:之前的学生类

//存储属性通常是PRIVATE的,因为数据要保护起来
//方法一般是PUBLIC的,因为方法是对象接受的消息
//如果自定义的类没有打算在其他项目中使用,可以不写访问修饰符
//直接使用默认的internal修饰符表示在本项目中公开对其他项目私有

func <(one:Student,two:Student)-> Bool {
    return one.age < two.age
}
///学生类
public class Student {
    private var _name:String
    private var _age : Int
    ///姓名隐去最后一个字符
    public var name:String {
        get{
            let value = _name.characters.count>2 ? -2:-1
            //取出字符串的部分
            let displayName = _name.substringToIndex(_name.endIndex.advancedBy(value))
        return displayName+"x" }
    }
    public var age :Int {
        get{return _age}
    }
    /**
     初始化方法
     - parameter name :姓名
     - parameter age : 年龄
*/
    public init(name:String,age:Int){
        self._name = name
        self._age = age
    }
    /**
     吃饭
     
     - parameter food : 吃的什么
    */
    func eat(food:String){
        print("\(_name)正在吃\(food))")
    }
    /**
     学习
     
     - parameter courseName: 课程名称 如果有返回值
     
     - returns: 学会了返回true 没有返回false
*/
    public func study(courseName:String){
        print("\(_name)正在学习\(courseName).")
    }
    /**
     看电视
     
     - parameter tv:电视名
*/
    public func watchJapaneseAV(tv:String){
        if _age > 18 {
            print("\(_name)正在看\(tv)")
        }else {
        print("请看熊出没")
        }
    }
}

通过这样的注释,自己或者别人在使用该类时,会看到注释内的字符提示,这极大的提高了类的可读性,方便别人理解。
在计算机中,它没办法自己计算分数,那么我们来设计一个分数的计算类,来进行分数计算。
创建分数类

func gcd(x:Int,_ y:Int)->Int{
//    var a = x < y ? x : y
//    while a > 1 {
//        if x%a == 0 && y%a == 0{
//            return a
//        }
//        a -= 1
//    }
//    return 1
    //短除法优化求最大公约数(欧几里得算法)
    if x > y {
        return gcd(y,x)
    }
    else if y%x != 0 {
        return gcd(y%x, x)
    }
    else{
        return x
    }
}

class Ftaction {
    private var _numerator:Int
    private var _denominator:Int
    
    init (numerator:Int,denominator:Int){
        assert(denominator != 0)
        _numerator = numerator
        _denominator = denominator
        normalize()
        
    }
    var info:String {
        get{return _numerator == 0 || _denominator == 1 ? "\(_numerator)" : "\(_numerator)/\(_denominator)"}
    }
    
    func multiply(other:Ftaction)->Ftaction{
        let numerator1 = other._numerator * _numerator
        let denominator1 = other._denominator * _denominator
        return Ftaction(numerator: numerator1, denominator: denominator1).simplify()
        
    }
    
    func divide(other:Ftaction)->Ftaction{
        let numerator1 = other._denominator * _numerator
        let denominator1 = other._numerator * _denominator
        return Ftaction(numerator: numerator1, denominator: denominator1).simplify()
        
    }
    
    func addition(other:Ftaction)->Ftaction{
        return Ftaction(numerator: _numerator*other._denominator+other._numerator*_denominator, denominator: _denominator*other._denominator).simplify()
    }
    
    func subtraction(other:Ftaction)->Ftaction{
    return Ftaction(numerator: _numerator*other._denominator-other._numerator*_denominator, denominator: _denominator*other._denominator).simplify()
        //链式编程
    }
    func normalize() -> Ftaction{
        if _denominator < 0{
            _numerator = -_numerator
            _denominator = -_denominator
        }
        return self
    }
    func simplify() -> Ftaction {
        if _numerator == 0 {
            _denominator = 1
        }else {
            let x = abs(_numerator)
            let y = abs(_denominator)
            let g = gcd(x, y)
            _numerator /= g
            _denominator /= g
        }
        return self
    }
    
}
//运算符重载(为自定义的类型定义运算)
//+—*/是自带的函数,而我们可以通过重载的方式对它们进行修改
func +(one: Ftaction,two:Ftaction)->Ftaction{
    return one.addition(two)
}

func -(one: Ftaction,two:Ftaction)->Ftaction{
    return one.subtraction(two)
}

func *(one: Ftaction,two:Ftaction)->Ftaction{
    return one.multiply(two)}

func /(one: Ftaction,two:Ftaction)->Ftaction{
    return one.divide(two)
}

main.swift内

let a = Ftaction(numerator:4, denominator:-5)
print(a.info)
let b = Ftaction(numerator: 5, denominator:4)
print(b.info)
let c=a+b
print(c.info)
let d = a/b
print(d.info)
let e = a.multiply(b)
print(e.info)
let f = a.subtraction(b)
print(f.info)

这样我们就可以在里面进行分数的计算了。

关于类的继承

我们发现很多事物有许多共同的属性,比如:学生和老师,他们都是人,不同之处是一个学,一个教,他们的共有属性太多,而我们为了代码避免重复这个坏味,所以选择在他们之前新建一个人类。而让,学生和老师通过继承人类,来获得人的属性。
tip:
继承:从已有的类中创建出新类的过程,提供继承信息的类父类(超类/基类)
得到继承信息的称为子类(派生类/衍生类)
通常子类除了得到父类的继承信息还会增加一些自己特有的东西
所有子类的能力一定比父类更强大
继承的意义在于子类可以复用父类的代码并且增强系统现有的功能

首先,创建一个人类:

//我们经常通过枚举的方式来创建新的类型
enum Gender{
    case Male
    case Female
}

class Person {
    var name:String//姓名
    var age:Int//年龄
    var gender:Gender//性别
    //初始化
    init(name:String,age:Int,gender:Gender){
        self.name = name
        self.age = age
        self.gender = gender
    }
    //吃饭
    func eat(){
        print("\(name)正在吃饭")
    }

}

学生类继承人类


//学生继承人
class Student:Person {
    //专业
    var major:String
    
    init(name:String,age:Int,major:String,gender:Gender){

        self.major = major
        //超类:继承他的父类
     super.init(name: name, age: age, gender: gender)
    }
    
    //学习
    func study(courseName:String) {
        print("\(name)是\(major)专业的学生")
        print ("\(gender == .Male ? "他":"她")正在学习\(courseName)")
    }
}

老师类继承人类

class Teacher:Person {
     //职称
    var title:String

    
    init(name:String,age:Int,title:String,gender:Gender){

        self.title = title
        super.init(name: name, age: age, gender: gender)
        }
    
    //教
    func teach(courseName:String){
        print("\(name)\(title)正在教\(courseName)")
        
    }
    
}

main.swift内:

let p1 = Person(name: "金", age: 15, gender:.Male)
p1.eat()
let p2 :Person = Student(name: "木", age: 18, major: "计算科学与技术", gender: .Female)
p2.eat()
(p2 as!Student).study("万物生")
//tip:
//我们可以将子类型的对象赋给父类型的变量(因为子类和父类之间是IS-A关系)
//学生是人,老师是人,所以学生老师的对象都可以赋值给人类型的变量
//如果要将父类型的变量转换为子类型需要用AS运算符进行类型转换
//如果确认父类型的变量中就是某 子类型的对象可用AS!转换
//如果不确定父类型的变量中是哪种子类型可用as?尝试转换
//不知道是什么类型时用as?转换
//如果确定知道类型时as!转换
if let temp = p2 as? Teacher {
    temp.teach("java")
}else {
    print("\(p2.name)不是老师!")
}
let p3 = Teacher(name: "水", age: 21, title: "灵", gender: .Female)
p3.eat()
p3.teach("冲浪术")

关于多态

多态:同样的对象类型(pet类型)接受相同的消息(调用相同的方法),但做了不同的事这就叫做多态(polymorhpism),目的是解耦合,
关键1.为方法重写(子类在继承父类的过程中对父类已有的方法进行重写。而且不同的子类给出各种不同的实现版本)
2.对象造型(将子类型对象当成父类型来使用)

通过一个养宠物的例子说明:
宠物

enum Gender {
    case Male
    case Female
}
import Foundation
class Pet {
    var nickName:String
    var gender :Gender
    var age :Int

    init (nickName:String,gender:Gender,age:Int){
        self.nickName = nickName
        self.age = age
        self.gender = gender

    }
    func play() {
        print("\(nickName)正在玩")
    }
    func eat() {
        print("\(nickName)正在吃东西")
    }
    func shout(){
        print("\(nickName)发出了叫声")    }

}

class Cat: Pet {
    var hairColor:String
    
    init(nickName: String, gender: Gender, age: Int,hairColor:String) {
      self.hairColor = hairColor
        super.init(nickName: nickName, gender: gender, age: age)
    }
    
    func catchTheMouse(){
        print("\(nickName)正在抓老鼠")
    }
    //父类有的方法,子类要重新实现,要使用方法重写override
    //在方法前添加override
    //重写有时也被翻译为置换,覆盖,覆习
    override func shout() {
        print("\(nickName):喵喵...")
    }
    override func play() {
        //play()自己调自己,递归,错误
//        super.play()//调用父类
        print("\(nickName)正在玩毛线球。")
    }
    
    
}

class Dog: Pet {
    
    var hairColor :String
    var isLarge:Bool
    
    init(nickName: String, gender: Gender, age: Int,hairColor:String,isLarge:Bool) {
        self.hairColor = hairColor
        self.isLarge = isLarge
        super.init(nickName: nickName, gender: gender, age: age)
    }
    
    override func play() {
        super.play()
        print("\(nickName)正在追飞盘")
    }
    
    override func shout() {
        print("\(nickName):汪汪.....")
    }
    
    func lookDoor(){
        if isLarge{
            print("\(nickName)正在看门")
        }
        else{
            print("\(nickName)太小了谁也打不过")
        }
    }
}

main.swift内

let petsArray = [
    Cat(nickName: "花花", gender: .Female, age: 3, hairColor: "黄色"),
    Dog(nickName: "旺财", gender: .Male, age: 2, hairColor: "黑色", isLarge: true),
    Dog(nickName: "大黄", gender: .Male, age: 1, hairColor: "黄色", isLarge: false)
]
for pet in petsArray {
//    pet.eat()
//    pet.play()
    pet.shout()
    //可以通过if——as?将父类型安全的转换成子类型然后在调用子类特有的方法
    if let dog = pet as? Dog {
       dog.lookDoor()
    }
    else if let cat = pet as?Cat  {
        cat.catchTheMouse()
    }
}

就这些了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 141,390评论 1 297
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 60,682评论 1 254
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 93,205评论 0 211
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 40,718评论 0 171
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 48,406评论 1 250
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 38,590评论 1 170
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 30,271评论 2 267
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,052评论 0 163
  • 想象着我的养父在大火中拼命挣扎,窒息,最后皮肤化为焦炭。我心中就已经是抑制不住地欢快,这就叫做以其人之道,还治其人...
    爱写小说的胖达阅读 28,801评论 6 227
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 32,404评论 0 212
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,176评论 2 212
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 30,489评论 1 222
  • 白月光回国,霸总把我这个替身辞退。还一脸阴沉的警告我。[不要出现在思思面前, 不然我有一百种方法让你生不如死。]我...
    爱写小说的胖达阅读 24,156评论 0 31
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,031评论 2 210
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 31,402评论 3 201
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,583评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 25,927评论 0 163
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 33,352评论 2 228
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 33,478评论 2 229

推荐阅读更多精彩内容

  • Hello Word 在屏幕上打印“Hello, world”,可以用一行代码实现: 你不需要为了输入输出或者字符...
    restkuan阅读 1,782评论 0 5
  • 时 间:Day163 1-17作者:爬格子的兔子文集:且行且思主题:博恩崔西的时间管理 成甲讲的这本《博恩崔西的时...
    王大大来了吖阅读 242评论 0 1
  • 近来可好吧?!身材还那么苗条?一定要好好吃饭,爸爸就希望你长点肉…… 当爸爸在键盘上敲下上面几个字,这种写信的感觉...
    清君_18ca阅读 731评论 0 0
  • 爱,象一把锋利的刻刀,用它柔软的刃,在眼泪上完成美丽的微雕。--题记 人,总是不知道哪天会发生一生最重要的那件事,...
    海目青阅读 347评论 0 3
  • JanePlus阅读 87评论 0 0