swift语法学习

第六章 高级运算符与枚举

6.1 运算符的重载与自定义

重载运算符和自定义运算符都是开发者自定义运算符功能的手段,二者的差别在于重载运算符是给系统已经存在的运算符追加新的功能,而自定义运算符是完全自定义一个系统存在的运算符,以实现特定的功能。

6.1.1 重载运算符

重载的概念最初是针对函数的,对同一个函数名设置不同的参数类型以实现不同的功能被称为函数的重载。

//=====================函数重载=====================//
func addFuncInt(param1:Int,param2:Int)->Int{
    return param1+param2
}

addFuncInt(param1: 3, param2: 4)
func addFuncDouble(param1:Double,param2:Double)->Double{
    return param1+param2
}
addFuncDouble(param1: 0.5, param2: 0.3)
//通过对同一个函数名设置不同的参数类型以实现函数重载
//创建整型的加法函数
func addFunc(param1:Int,param2:Int) -> Int {
    return param1+param2
}
//重载addFunc实现浮点型数据的加法
func addFunc(param1:Double,param2:Double) -> Double {
    return param1+param2
}
//再次重载addFunc,实现字符串类型的加法
func addFunc(param1:String,param2:String)->String{
    return param1+param2
}

类比于函数重载,运算符的重载是指在系统已经存在的运算符上扩展新的功能。实际上运算符的重载就是通过函数的方式定义的。

class Circle{
    //圆心
    var center:(Double,Double)
    //半径
    var radius:Double
    init(center:(Double,Double),radius:Double){
        self.center = center
        self.radius = radius
    }
}
func +(param1:Circle,param2:Circle) -> Circle {
    return Circle(center: param1.center, radius: param1.radius+param2.radius)
}
func myFunc(closure:(Circle,Circle)->Circle) {
    var circle1 : Circle = Circle(center: (2,1), radius: 1)
    var circle2 : Circle = Circle(center: (2,2), radius: 2)
    var circle3 : Circle = closure(circle1,circle2)
    print("圆的圆心是\(circle3.center),圆的半径是\(circle3.radius)")
}
myFunc(closure: +)

注意:覆写是指子类对父类中的属性和方法进行适合自身的重新实现,和重载的概念不相同。

6.1.2 自定义运算符

重载运算符是为已经存在的系统运算符扩展新的功能,开发者同样可以通过自定义系统的运算符来实现特殊的需求。

//自定义前缀运算符++
prefix operator ++
//进行自定义运算符实现
prefix func ++(param:Int)->Int{
    return param+1
}
//将返回6
++5
//自定义中缀运算符
infix operator ++
func ++(param1:Int,parma2:Int)->Int{
    return param1*param1+parma2*parma2
}
//将返回41
5++4
//自定义后缀运算符
postfix operator ++
postfix func ++(param1:Int) -> Int {
    return param1+param1
}
//将返回10
5++

自定义运算符分为两个步骤,首先开发者需要对要定义的运算符进行声明,在声明运算符的结构中,prefix声明为前缀运算符,使用infix关键字将其声明为中缀运算符,使用postfix关键字将其声明为后缀运算符。在进行运算符的实现时,后缀和前缀运算符只能有一个参数,参数在func关键字前需要表明要实现的运算符类型,而中缀运算符需要两个参数且func关键字前不需要额外标明。

注意:如果“.”出现在自定义运算符的开头,则运算符中可以出现多个“.”,例如“.+.”;如果自定义运算符中的“.”不在开头,那么这个自定义运算符中只允许出现一次“.”。

6.2 运算符的优先级与结合性

任何运算符都有默认的优先级,开发者自定义的运算符也是如此,优先级越高的运算符越优先执行。对于结合性而言,由于前缀运算符与后缀运算符都只有一个操作数,因此它只对中缀运算符有意义。

当系统内置的优先级组不能满足我们的要求时,即可使用precedencegroup关键字来自定义优先级组,其中higerThan用来设置当前优先级组的优先级比哪个优先级组高;lowerThan用来定义当前优先级组比哪个优先级组低;assignment用来设置是否会影响可选链赋值运算中的优先级判定规则;associativity用来设置可以选择left或者right来定义成左结合性或者右结合性,设置为none则为默认结合性。

precedencegroup customGroup{
    higherThan:AdditionPrecedence//当前优先级组的优先级比哪个优先级组高
    lowerThan:MultiplicationPrecedence//当前优先级组比哪个优先级组低
    assignment:true//用来设置是否会影响可选链赋值运算中的优先级判定规则
    associativity:left//用来设置可以选择left或者right来定义成左结合性或者右结合性,设置为none则为默认结合性
}

6.3 枚举类型的创建与应用

//创建一个姓氏类型枚举
enum Surname {
    //使用case进行枚举值的设置
    case 张
    case 王
    case 李
    case 赵
}

//创建一个姓氏枚举类型
enum Surname {
    //在一条case语句中定义多个枚举值
    case 张,王,李,赵
}

//创建一个姓氏枚举类型的变量
var sur:Surname
//对sur变量进行复制
sur=Surname.张
//对sur进行修改
sur = .王
//对枚举类型的变量进行switch选择结构
switch sur {
    case .张:
        print("姓氏张")
    case .王:
        print("姓氏王")
    case .李:
        print("姓氏李")
    case .赵:
        print("姓氏赵")
}

6.4 枚举的原始值与相关值

枚举的原始值特性可以将枚举值与另一种数据类型进行绑定,相关值则可以为枚举值关联一些其他数据。通过相关值,开发者可以实现复杂的枚举类型。

6.4.1 枚举的原始值

上述中创建的枚举并没有声明一个原始值类型,swift语言中的枚举支持开发者声明一个原始值类型,并将某个已经存在的类型的值与枚举值进行绑定,枚举指定原始值类型的语法与继承的语法有些相似。

//为枚举类型指定一个原始值类型
enum CharEnum:Character{
    //通过赋值的方式来为枚举值设置一个原始值
    case a = "a"
    case b = "b"
    case c = "c"
    case d = "d"
}

如果开发者要指定枚举的原始值类型为Int类型,那么可以只设置第一个枚举值的原始值,其后的枚举值的原始值会在第一个枚举值原始值的基础上依次递增。

enum IntEnum:Int {
    //第一个枚举值的原始值设置为1
    case 一 = 1
    //默认原始值为2
    case 二
    //默认原始值为3
    case 三
    //默认原始值为4
    case 四
}

通过枚类型中的rawValue属性来获取枚举的原始值,在枚举变量初始化时,开发者可以使用枚举类型加点语法的方式,如果这个枚举有指定的原始值,也可以通过枚举值的原始值来完成枚举实例的构造。

//创建枚举变量
var char = CharEnum.a
//获取char枚举变量的原始值 "a"
var rawValue = char.rawValue

//通过原始值构造枚举变量 一
var intEnum = IntEnum(rawValue: 1)

需要注意的是,通过原始值进行枚举实例的构造时,是有可能失败的,因为开发者传入的原始值不一定会对应某一个枚举值,因此这个方法实际上返回的是一个Optioal类型的可选值,如果构造失败,则会返回nil。

6.4.2 枚举的相关值

枚举类型的设计思路是帮助开发者将一些简单的同类数据进行整和。面对不同的数据需要有不同的参数。因此在定义枚举值的时候,开发者可以为其设置一个参数列表,这个参数列表被称为枚举的相关值。

//定义形状枚举
enum Shape {
    //圆形 设置圆心和半径 为相关值
    case circle(center:(Double,Double),radius:Double)
    //矩形 设置中心 宽 高 为相关值
    case rect(center:(Double,Double),width:Double,height:Double)
    //三角形 设置3个顶点 为相关值
    case triangle(point1:(Double,Double),point2:(Double,Double),point3:(Double,Double))
}

//创建圆形枚举实例 此圆的圆心为(0,0),半径为3
var circle = Shape.circle(center: (0, 0), radius: 3)
//创建矩形枚举实例 此矩形的中心点为(1,1),宽度10,高度15
var rect = Shape.rect(center: (1, 1), width: 10, height: 15)
//创建三角形枚举实例 此三角形的3个顶点为(2,2),(3,3),(2,5)
var triangle = Shape.triangle(point1: (2, 2), point2: (3, 3), point3: (2, 5))

//写一个匹配函数 参数为Shape枚举类型
func shapeFunc(param:Shape){
    switch param {
        //进行参数捕获
    case let .circle(center,radius):
        print("此圆的圆心为:\(center),半径为:\(radius)")
    case let .rect(center,width,height):
        print("此矩形的中心为:\(center),宽为:\(width),高为:\(height)")
    case let .triangle(point1,point2,point3):
        print("此三角形的3个顶点分别为:\(point1),\(point2),\(point3)")
    }
}
shapeFunc(param: circle)
shapeFunc(param: rect)
shapeFunc(param: triangle)

6.4.3 递归枚举

递归就是程序调用自身的编程技巧。针对函数来说,递归函数就是在函数内部进行了此函数的调用。

//使用递归算法来实现计算正整数的阶乘
func mathsFunc(param:Int)->Int{
    let tmp = param-1
    if tmp>0 {
        //递归
        return mathsFunc(param: tmp) * param
    }else{
        return 1
    }
}
mathsFunc(param: 5)

函数的功能是进行数据的计算,递归函数只是使用递归的算法来进行数据的计算。而枚举则不同,枚举的功能是数据的描述。

在面对复合表达式时,可以将一个枚举值的相关值类型设置为这个枚举本身的类型,通过这种递归的方式就可以实现复合表达式的描述。

//使用枚举来模拟加减乘除四则运算
indirect enum Expression {
    //描述单个数字
    case num(param:Int)
    //表示加法运算 将Expression作为相关值参数类型
    case add(param1:Expression,param2:Expression)
    //表示减法运算
    case sub(param1:Expression,param2:Expression)
    //表示乘法运算 
    case mul(param1:Expression,param2:Expression)
    //表示除法运算
    case div(param1:Expression,param2:Expression)
}
表示表达式5+5
//var exp1 = Expression.add(param1: 5, param2: 5)
表示表达式10-5
//var exp2 = Expression.sub(param1: 10, param2: 5)
表示表达式5*5
//var exp3 = Expression.mul(param1: 5, param2: 5)
表示表达式10/2
//var exp4 = Expression.div(param1: 10, param2: 2)

//创建单值5
var num5 = Expression.num(param: 5)
//进行表达式5+5描述
var exp1 = Expression.add(param1: num5, param2: num5)
//创建单值2
var num2 = Expression.num(param: 2)
//进行表达式(5+5)*2的描述
var exp2 = Expression.mul(param1: exp1, param2: num2)
//创建单值8
var num8 = Expression.num(param: 8)
//进行表达式(5+5)*2-8的描述
var exp3 = Expression.sub(param1: exp2, param2: num8)
//进行表达式((5+5)*2-8)/2的描述
var expFinal = Expression.div(param1: exp3, param2: num2)

//这个递归函数的作用是将Expression描述的表达式进行运算 结果返回
func expressionFunc(param:Expression) -> Int {
    switch param {
        //单值直接返回
    case let .num(param):
        return param
    case let .add(param1, param2):
        //返回加法运算结果
        return expressionFunc(param: param1)+expressionFunc(param: param2)
    case let .sub(param1, param2):
        //返回减法运算结果
        return expressionFunc(param: param1)-expressionFunc(param: param2)
    case let .mul(param1, param2):
        //返回乘法运算结果
        return expressionFunc(param: param1)*expressionFunc(param: param2)
        //返回除法运算结果
    case let .div(param1, param2):
        return expressionFunc(param: param1)/expressionFunc(param: param2)
    }
}
//进行((5+5)*2-8)/2运算 结果6
expressionFunc(param: expFinal)

练习:模拟设计一个交通工具枚举 将速度与乘坐价钱作为枚举的相关值


enum Transport{
    case car(price:Int,speed:Float)
    case boat(price:Int,speed:Float)
    case airport(price:Int,speed:Float)
}
//创建一个汽车交通工具 价钱2 速度80
var car = Transport.car(price: 2, speed: 80)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值