美文网首页
Swift基本数据类型以及控制循环

Swift基本数据类型以及控制循环

作者: a_只羊 | 来源:发表于2021-01-29 16:17 被阅读0次

    基本数据类型

    • 常见的数据类型:

      • 值类型(value type)
      1. 枚举
        enum / Optional
      2. 结构体
        Bool/Int/Float/Double/Character/String/Array/Dictionary/Set
      • 引用类型(reference type):
        类(class)
      • 整数类型
        在32位的平台中Int等价于Int32、64位平台Int等价于Int64
        Int8/Int16/Int32/Int64/UInt8/UInt16/UInt32/UInt64
      • 浮点类型:
        Float(32位,精度只有6位)
        Double(64位,精度至少15位)
     func valueFunc() {
            
            var floatDemo: Float? = 10
            var doubleDemo: Double? = 29
            
            enum TestEnum{
                case one,two,three
            }
            struct SomeStruct{
                var age = 10
                var height = 167
            }
        }
    
    • 字面量,直接赋值,编译器可以推断其类型的内容
            let bool = true
            let intDecimal = 17 //十进制
            let intBinary = 0b1001010 //二进制
            let intHexdecimal = 0x12 //十六进制
            let intOctal = 0o21 //八进制
            
            let doubleDecimal = 125.0 //十进制 等价于1.25e2
    
    • 类型转换
    func typeToChange() {
            //整数转换
            let int1: UInt16 = 2_000
            let int2: UInt8 = 1
            let int3 = int1 + UInt16(int2)
            
            //字面量可以直接相加,字面量本身没有明确的类型
            let int4 = 123 + 12.344
        }
    
    • 元组
    func tupleDemo() {
            //如何创建一个404错误的元组?如何取值?
            let http404Error = (404,"404 error, not found")
            print("The status is \(http404Error.0)")
            
            //如何对元组取值
            var firstValue = http404Error.0
            var secondValue = http404Error.1
            
            //取到元组内容
            let (status, message) = http404Error
            print("status code is \(status), message:\(message)")
            
            //忽略某个元组参数
            let (careStatus, _) = http404Error
            print("i only care status:\(careStatus)")
            
        }
    
    • 条件判定(if 后面只能是Bool类型,可以省略小括号,大括号不能省略)
    func loginJudge() {
            let age = 5
            if age >= 22 {
                print("ready to marry")
            }else if age > 18{
                print("just in adult")
            }else{
                print("just a child")
            }
    
    • while的使用
     /*
         循环
         while使用
         repeat...while 相当于OC中的do...while循环
         */
        func whileUse() {
            var num = 5
            while num > 0 {
                print("循环我...")
                num -= 1
            }
            
            var repeatTimes = 5
            repeat{
                print("look here ...")
                repeatTimes -= 1
            }while repeatTimes > 0
        }
    
    • for循环使用
    func forLoopUse() {
            let names = ["Zhang", "Lee", "Chen", "Gong"]
            //...是闭区间方法,返回闭区间
            for i in 0...3 {
                print(names[i])
            }
            //使用range遍历
            let range = 1...3
            for j in range {
                print(names[j])
            }
            
            var a = 1
            let b = 3
            for j in a...b {
                print(names[j])
            }
            
            for _ in 0 ..< names.count {
                print("for item")
            }
        }
    
    • 区间运算符
        /*
         区间运算符
         通过创建区间运算符判定指定数的范围类型
         */
        func rangeCreatAndUse() {
            let range = ...10
            print(range.contains(20))
            print(range.contains(11))
        }
    
        /*
         使用区间运算符遍历数组,区间运算符:[1...b]/[1...]/[...1]/[..<2]
         */
        func rangUseInArray() {
            
            let names = ["Zhang", "Lee", "Chen", "Gong"]
            for name in names[0...3] {
                print(name)
            }
            
            for name in names[...3] {
                print(name)
            }
            
            for name in names[..<4] {
                print(name)
            }
        }
    
    • 区间类型
      1. ClosedRange<T> 闭区间
      2. Range<T> 半开区间(前闭后开)
      3. PartialRangeThrough<T> 部分区间
    //练习:使用区间判断字符是否在字母范围,请利用区间特性
    func rangeType() {
            let _: ClosedRange<Int> = 1...3 //闭区间
            let _: Range<Int> = 1..<3 //半开区间(前闭后开)
            let _: PartialRangeThrough<Int> = ...5 //部分区间
            
            let character: ClosedRange<Character> = "a"..."z"
            print(character.contains("B"))
            
            let charRang: ClosedRange<Character> = "\0"..."~"
            print(charRang.contains("B"))
        }
    
    //从4开始累加2,不超过11,筛选出对应的数据值,可以使用stride方法来进行跳跃
     func rangeContainThrough() {
            let allRang:ClosedRange<Int> = 1...100
            
    //        var indexValue = 0
    //        switch allRang.startIndex {
    //        case .inRange(let preIndex):
    //            indexValue = preIndex
    //        default:break
    //        }
    //
    //        print("position [0] = \(indexValue)")
        
            for targetValue in stride(from: 4, through: 100, by: 2) {
                print(targetValue)
            }
        }
    
    • Switch 语句
      1. case/default后面不能够添加大括号
      2. Swift中的case不用添加break,默认会执行到下一个case到来

    注意点:
    1. case、default 后面至少需要跟一条语句
    2. 如果不想做任何事,可以在最后添加break语句结束

    func switchUse() {
            let num = 1
            switch num {
            case 1:
                print(num)
            case 2:
                print(num)
            default:
                print(num)
            }
        }
    
        /*
         连续执行多行case,如何操作?
         可以使用fallthrough操作
         */
        func mutiCaseExec() {
            let num = 1
            switch num {
            case 1:print(num); fallthrough
            case 2:print(num); fallthrough
            case 3:print(num); fallthrough
            case 4:print(num)
            case 5:print(num)
            default:break
            }
        }
    
        /*
         switch 自定义枚举的时候,如果保证所有的枚举都列举完成,
         那么可以不必使用default来处理默认情况
         */
        func associateEnumValue() {
            enum Answer{case right, wrong}
            let finishAnswer = Answer.right
            switch finishAnswer {
            case .right:print("answer result is \(finishAnswer)")
            case .wrong:print("answer result is \(finishAnswer)")
            }
        }
    
        /*
         switch case如何使用复合类型来判定
         */
        func moreTypeCase() {
            let string = "Jack"
            switch string {
            case "hello", "Lee", "Wang": print("rich man~")
            case "Jack": print("poor man~~")
            default: print("Not Found")
            }
        }
    
        /*
         Switch
         1. 使用区间Range进行值匹配
         2. 使用元组进行case匹配
         */
        func switchRangeCase() {
            let score = 45
            switch score {
            case 0..<60: print("Not Ok")
            case 60..<80: print("Just So So")
            case 80..<90: print("Good")
            case 90..<100: print("Woundful")
            default:print("So bad")
            }
            
            let infoMan = (84, "Good")
            switch infoMan {
            case let (cScore, cLevel): print("score\(cScore), level:\(cLevel)")
            case let (_, cLevel): print("level:\(cLevel)")
            default:break
            }
            
        }
    
    • 值绑定

    使用let = option case 进行值绑定

        /*
         值绑定
         使用let = option case 进行值绑定
         */
        func valueBind() {
            let point = (2, 0)
            switch point {
            case (let x, var y): print("x: \(x), y:\(y)")
            case (_, var y): print("x: -, y:\(y)")
            case (let x, _): print("x: \(x)")
            default:break
            }
        }
    
    • 条件过滤where
        /*
         where 条件过滤
         */
        func whereFiliterUse() {
            var point = (1, 2)
            switch point {
            case (let x, let y) where x == y: print("y=x line in dicarl line")
            case (_, let y) where y==0: print("y line in dicarl line")
            case (let x, let y) where (x>0 && y>0): print("location is in first part view")
            default:break
            }
        }
    
    • 标签语句 outer
        /*
         标签语句(通过outer标签语句能够简化跳转逻辑)
         outer:
         */
        func outerUse() {
            outer: for k in 1...4 {
                    for j in 8...16 {
                        if j == 10 {
                            continue outer
                        }
                        if k == 3 {
                            break outer
                        }
                        print("k == \(k), j=\(j)")
                    }
            }
        }
    

    函数的定义

    • 函数的隐式返回

    对于只有一行的语句,可以省略返回return关键字,这种省去返回return关键字的操作叫做隐式返回.

        class FuncUse {
            //带返回值
            static func pi() -> Double {
                return 3.14;
            }
            
            //加法
            static func sum(v1: Int, v2: Int) -> Int {
                return v1 + v2
            }
            
            //加法简化
            static func sumSlim(v1: Int, v2: Int) -> Int {v1+v2}
            
        }
        /*
         返回元组,实现多值返回
         */
        func tupleReturnUseTypeAlias() -> (userName: String, age: String, className: String) {
            (userName: "String", age: "String", className: "String")
        }
       
    
    • 函数默认参数值
      这里的方法参数设置与C++有点区别,
      C++中参数值有限制,必须从右向左设置
      对于没有设置默认值的方法参数是不能够省略的
      而Swift中由于存在参数标签,所以不用按顺序进行设置

    例如下面的方法调用:
    Swift:self.funcDefaultParamter(age: 28)
    c++: self.funcDefaultParamter("lcc",28,"workMan")

    func funcDefaultParamter(name: String = "lcc", age: Int, job: String = "none") {
            print("name:\(name), age:\(age), job:\(job)")
        }
    
    • 可变参数(...)
      1. 可变参数在取值的时候使用遍历取值
      2. 一个方法最多只有一个可变参数
      3. 紧跟可变参数后面的参数不能够省略标签
        func moreParameterIngoreTag(_ numbers: Int..., eachItem: (Int)->()) -> Int {
            var sum = 0
            for item in numbers {
                eachItem(item)
                sum += item
            }
            return sum
        }
        
        func moreParamterUse(_ numbers: Int...) -> Int {
            var sum = 0
            for number in numbers {
                sum += number
            }
            return sum
        }
    
    • 函数重载
      1. 返回值类型与函数重载没有关系
      2. 默认参数值与函数重载一起使用的时候如果产生歧义,编译器不会报错,优先调用匹配完全一致的方法
        func someFunc() {
            print("source func")
        }
        
        func someFunc(v1: Int, v2: Int) {
            print("change func use to sum: \(v1 + v2)")
        }
        
        func someFunc(v1: Int, v2: Int, v3 :Int = 20) {
            print("more parameter count: \(v1 + v2 + v3)")
        }
    
    • 输入输出参数 inout

    可以在函数内部调用外界的方法,比较典型的范例就是通过元组实现两个数字的交换

        //傻子方法
        func swapNum(numberOne: inout Int, numberTwo: inout Int) {
            let sourceTuple = (numberOne, numberTwo)
            let result = (sourceTuple.1, sourceTuple.0)
            numberOne = sourceTuple.1
            numberTwo = sourceTuple.0
            print("交换之前:\(sourceTuple), 交换之后\(result),numberOne:\(numberOne),numberTwo:\(numberTwo)")
        }
        
        //优雅方法,使用元组直接能够交互
        func swapNum(numberOne: inout Int, numberTwo: inout Int, des: String = "") {
            (numberOne, numberTwo) = (numberTwo, numberOne)
        }
    
    • 内联函数 @inline

    Swift编译器中默认是开启自动转换内联函数的功能的实质:将函数调用展开成函数体。
    注意:
    1. 函数体比较长的不会被转换成函数体
    2. 递归调用不会转换成函数体
    3. 包含动态派发不能够转换成函数体

        func buildToChange() {
            print("transform to me")
        }
        
        //关闭内联
        @inline(never) func inlineUse() {
            print("即使开启编译器优化,也不会被内联")
        }
        
        //强制内联
        @inline(__always) func inlineOnAlways() {
            print("即使代码段很长,也会被内联,除了动态派发的函数以及递归调用的函数外")
        }
    
    • 函数类型

    函数类型包含以下两个重要组成:

    1. 形式参数类型
    2. 返回值类型
     func funcTest(parameter: String...) -> (String) {
            var strUnition = ""
            for str in parameter {
                strUnition.append(str)
            }
            return strUnition
        }
    print(self.funcTest(parameter: "leo ", " is"," the", " best", " programmer"))
    
    • 使用函数类型作为函数的参数进行传递
    1. @autoclosure的使用,对于没有参数的函数作为参数的话可以添加@autocclosure关键字让函数的调用更加简洁高效
    2. 正常函数调用,如果将函数作为参数进行传递的话,可以考虑使用$符获取参数内容
        func printSumResult(n1: Int, n2: Int, sumAdd: @autoclosure()->(Int)) {
            print(sumAdd())
        }
        
        func printSumResult(n1: Int, n2: Int, sumAdd: (Int, Int)->Int) {
            print(sumAdd(n1, n2))
        }
    
    self.printSumResult(n1: 1, n2: 2, sumAdd: 3)
    self.printSumResult(n1: 32, n2: 29) {$0+$1}
    self.printSumResult(n1: 32, n2: 11) { (num1, num2) -> Int in num1 + num2}
    
    • 使用函数作为返回值进行传递操作
      返回值是函数类型的函数,也叫做高阶函数
        func returnFunUse() -> (Int, Int) -> Int {
            return {$0+$1}
        }
    
    • 类型别名 typealias
    typealias LCInt = Int
    typealias LCFloat = Float
    func typealiasUse(age: LCInt, score: LCFloat) {
        print("age:\(age), score:\(score)")
    }
    
    • 嵌套函数
      在函数中嵌套一个函数。
        func funcInFunc() -> ((String, Int) -> () , (Int, Int) -> (Int)) {
            func result(usrName: String, age: Int){
                print("I get your name:\(usrName), and your age:\(age)")
            }
            func countTwoSum(num1: Int, num2: Int) -> Int{num1 + num2}
            return (result, countTwoSum)
        }
    
        
         var (funcOne, funcTwo) = self.funcInFunc()
         funcOne("lcc", 25)
         print("count result:\(funcTwo(24, 64))")
         
         self.funcInFuncSignal()(1,3)
    
    
    • 枚举的基本用法

      1. 值类型枚举
      2. 关联值类型

    将值类型成员与其他类型的值关联在一起,可以起到关联变量值存储的作用,在使用的枚举,抽象表达某些功能的时候会变得异常方便

    注意:值类型与关联值类型的空间存储区别
    1. 如果枚举是基本的值类型,那么枚举在内存空间的容量是固定的,因为本质存储的是原始值,默认分配1个字节的空间内容来进行存储
    2. 如果枚举是关联类型的存储,那么要根据枚举的类型来确定其内存空间的占用大小,通常选择枚举关联值最大的为存储空间,还要加上原始值的存储(1个字节),最终算出来的是其真实占用的空间大小

    占用空间大小与实际内存分配的大小区别

    占用空间大小是通过当前数据类型占用的空间大小累加的总和,而在实际分配过程中由于iOS系统通常会采用内存对齐的方式去分配真实的空间,通常是8个字节的整数倍。所以由于内存对齐的原因,在实际分配内存上,可能分配的空间大于实际所占用的内存空间

        //以下实际占用了 32+1 = 33 个字节的空间大小,实际分配了40个字节的空间大小
        enum Password {
            case number(Int, Int, Int, Int)
            case other
        }
        
        //值类型,仅分配1个字节存储原始值内容
        enum Direction {
            case top, left, bottom, right
        }
        
        //关联值类型
        enum LoadServerMethod {
            case LoadFirst(url: String)
            case LoadSecond(url: String)
            case LoadFinish(finish: (Any)->())
        }
        
        func testEnum() {
            let gogoUp = Direction.top
    //        let requestServer = LoadServerMethod.LoadFirst(url: "http://www.baidu.com")
            let finishClosure = LoadServerMethod.LoadFinish { (data) in
                print("server data:\(data)")
            }
            
            switch gogoUp {
            
            case .top: print("top")
            case .left: print("left")
            case .bottom: print("bottom")
            case .right: print("right")
            }
            
            switch finishClosure{
            case .LoadFirst(let url): print("请求的地址:\(url)")
            case .LoadSecond(let url): print("请求的地址:\(url)")
            case .LoadFinish(let finish): finish(["data":"nil"]);
            }
        }
        
    
    • 枚举的用法
      枚举成员可以使用相同的类型的默认值进行预先关联,默认设置的值叫做原始值,枚举原始值类型如果是Int、String,Swift会默认分配其原始值
    func enmuSourceValue() {
            
            enum DefaultIntEnum: String{
                case top, left, bottom, right
            }
            
            enum TypeSource: Int{
                case age = 18
                case birth = 19701010
                case idCard = 00000000000
            }
            //打印出原始值
            print(DefaultIntEnum.top.rawValue)
            print(DefaultIntEnum.top)
        }
    
    • 枚举递归
    1. 递归枚举类似于函数的递归,是枚举内容本身调用枚举本身
    2. 递归枚举可以用来按层级存储关联数值,在使用的时候结合业务
    3. 一般使用递归函数配合来进行switch..case的判定
    func indirectEnum() {
            enum AirthExpr {
            case number(Int)
            indirect case sum(AirthExpr, AirthExpr)
            indirect case difference(AirthExpr, AirthExpr)
            }
            
            func traverseEnum(airthNum: AirthExpr) -> Int {
                switch airthNum {
                case .number(let num): return num
                case let .sum(airthExpOne, airthExpTwo): return traverseEnum(airthNum: airthExpOne) + traverseEnum(airthNum: airthExpTwo)
                case let .difference(airthExpOne, airthExpTwo): return traverseEnum(airthNum: airthExpOne) - traverseEnum(airthNum: airthExpTwo)
                }
            }
            
            let five = AirthExpr.number(5)
            let four = AirthExpr.number(4)
            let sumAdd = AirthExpr.sum(five, four)
            let diffEnum = AirthExpr.difference(five, four)
            print("add result :\(traverseEnum(airthNum: sumAdd))")
            print("different result :\(traverseEnum(airthNum: diffEnum))")
        }
    
    • 可选类型
      声明某个变量为可选,直接在变量的类型后面添加?即可
      对于可选类型的变量或者常量,有两种方式可以拿到其原始值:
      1. 强制解包
      2. 可选链操作

    可选可以理解为一层包装盒子,盒子里装的是真实数据

    1. 如果为nil,那么它是一个空盒子
    2. 如果非nil,那么盒子装的就是被包装的数据

    !是强制解包的标识符,如果对nil的可选类型进行强制解包,将会产生运行时错误(Fatal error:...)

    注意:
    数组返回的数值不是可选类型的数值,因为当数组越界的时候就已经发生崩溃,并不能拿到带有歧义的数值(nil或者有数值),而字典获取的数值为可选数值

        func unwrappTypeUse() {
            var age: Int?
            //直接相加由于age是可选类型所以会报错
    //        age+=10
            //通过!来进行强制解包
            print(age!+=10)
        }
    
    • 解包之可选绑定
    1. 如果包含内容就自动解包,把可选内部包装的值赋值给一个临时变量 var 或者常量 let,并返回 true, 否则返回false
    2. 如果存在多个值,可选绑定可以通过逗号分开,注意不能使用&&分割
    func unwrappingBindUse() {
            let num: Int? = 10
            let addTo: Int? = nil
            if let tmpNum = num,
               let _ = addTo{
                print("含有内容:\(tmpNum)")
            }   
        }
    
    • while 使用可选绑定
        /*
         while中使用可选绑定
         遍历数组,将遇到的整数都加起来,如果遇到复数或者非数字,停止遍历
         */
        func bindLetWhileLoop() {
            let strs = ["10", "20", "abc", "-20", "30"]
            var index = 0
            var sum = 0
            
            while let num = Int(strs[index]), num > 0 {
                sum += num
                index += 1
            }
            
            print("运算结果:\(sum)")
        }
    
    • 合并空运算符 ??
    1. 被修饰的是可选类型
    2. 合并的备选常量或者变量与被修饰的类型要保持一致
    3. 如果备选不是可选类型,返回的时候会自动进行解包操作

    注意:
    空合并运算符(??)是如何实现的?为什么在返回默认值的时候要使用闭包来实现,直接返回默认内容不可以吗?
    1. 包装了一个函数里面实现的public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T
    2. 内部实现使用了switch判定类似于以下的操作,使用运算符重载操作

    运算符重载??实现可能如下:

        func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T{
            switch optional {
            case .some(let optional): return optional
            case .none: return try!defaultValue()
            }
        }
    
    
    • 多个空合并运算符??一起使用
        /*
         多个 ?? 一起使用
         */
        func mutiDefaultValueUse() {
            let a: Int? = 1
            let b: Int? = 2
            let c = a ?? b ?? 3 //c是Int,1
            
            let d: Int? = nil
            let e: Int? = 2
            let f = d ?? e ?? 3 //f是Int, 2
        }
    
    
    • ??if let配合使用
        /*
         ?? 与 if let 配合使用
         等同于 if a! = nil || n != nil
         */
        func defaultWithChooseBind() {
            let a: Int? = nil
            let b: Int? = 2
            if let c = a ?? b {
                print("result--->\(c)")
            }
        }
    
    • guard 语句
    1. guard语句条件为false时,会执行大括号里面的内容,否则正常执行
    2. guard时候提前过滤不满足当前方法或者函数执行的条件
    3. 当使用guard语句进行可选绑定的时候,绑定的常量let、变量var也会在外层作用域使用
        func guardUseStatement(age: Int, level: Int) {
            guard age > 18, level > 50 else {
                print("未成年人禁止浏览")
                return
            }
            print("一起看动画片啊~")
        }
    
    • 隐式解包
    1. 某些情况下,有些可选类型变量一开始设定就直接有值
    2. 在确定可选类型内容一直有值的情况下,可以通过在变量后面添加!的方法去除类型检查
    3. 去除类型检查之后,每次获取的可选类型变量将会隐式进行解包取出其中包含的数值
        func unwrappingValueUse() {
            var num: Int! = 10
            var choose: Int? = 20
            print("隐式解包\(num)")
            print("强制解包\(choose!)")
        }
    
    • 字符串查值
     func strDesprint() {
            let age: Int? = 10
            print("age:\(age ?? 0)") //这样打出来的内容是可选类型
            print("ageDes:\(String(describing: age))")
        }
    
    • 多重可选项
      多重可选项可以理解为多重可选的包装,在取值的时候需要格外注意,要分层取值。
        func moreUnwrappingValue() {
            let num: Int? = 10
            let userone: Int?? = 20 //被包装了两次,解包的时候需要解包两次才行
            let userTwo: Int??? = 30 //道理同上
            
            let numValue = num!
            let userOneValue = userone!!
            let userTwoValue = userTwo!!!
            print("当前内容:\(numValue), \(userOneValue), \(userTwoValue)")
            
        }
    
    

    相关文章

      网友评论

          本文标题:Swift基本数据类型以及控制循环

          本文链接:https://www.haomeiwen.com/subject/qvjqtltx.html