Swift语言学习笔记(4)

本文介绍了Swift中的类型转换操作,包括is和as运算符的使用,并深入探讨了访问控制的概念,包括不同访问级别的定义及其在类、枚举、结构体等中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

类型转换(Type Casting)

  • 类型转换在 Swift 中被实现为 is 和 as 运算符。
    其中 is 运算符用于类型检查(判断某个值的类型)。
    而 as 运算符用于类型转换(将某个值转换成别的类型)。
    class MediaItem {
        var name: String
        init(name: String) {
            self.name = name
        }
    }
    class Movie: MediaItem {
        var director: String
        init(name: String, director: String) {
            self.director = director
            super.init(name: name)
        }
    }
    class Song: MediaItem {
        var artist: String
        init(name: String, artist: String) {
            self.artist = artist
            super.init(name: name)
        }
    }
    let library = [
        Movie(name: "Casablanca", director: "Michael Curtiz"),
        Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
        Movie(name: "Citizen Kane", director: "Orson Welles"),
        Song(name: "The One And Only", artist: "Chesney Hawkes"),
        Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
    ]
    // the type of "library" is inferred to be [MediaItem]
    var movieCount = 0
    var songCount = 0
    for item in library {
        if item is Movie {
            movieCount += 1
        } else if item is Song {
            songCount += 1
        }
    } 
    print("Media library contains \(movieCount) movies and \(songCount) songs")
    // Prints "Media library contains 2 movies and 3 songs"
    for item in library {
        if let movie = item as? Movie {
            print("Movie: \(movie.name), dir. \(movie.director)")
        } else if let song = item as? Song {
            print("Song: \(song.name), by \(song.artist)")
        }
    }
    // Movie: Casablanca, dir. Michael Curtiz
    // Song: Blue Suede Shoes, by Elvis Presley
    // Movie: Citizen Kane, dir. Orson Welles
    // Song: The One And Only, by Chesney Hawkes
    // Song: Never Gonna Give You Up, by Rick Astley
    
  • 为了处理不确定的类型,Swift 提供了两种特殊的类型:
    AnyObject 可以表示任何类类型的实例。
    Any 可以表示任何类型(包括函数类型)的实例。
    var things = [Any]()
    things.append(0)
    things.append(0.0)
    things.append(42)
    things.append(3.14159)
    things.append("hello")
    things.append((3.0, 5.0))
    things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
    things.append({ (name: String) -> String in "Hello, \(name)" })
    for thing in things {
        switch thing {
        case 0 as Int:
            print("zero as an Int")
        case 0 as Double:
            print("zero as a Double")
        case let someInt as Int:
            print("an integer value of \(someInt)")
        case let someDouble as Double where someDouble > 0:
            print("a positive double value of \(someDouble)")
        case is Double:
            print("some other double value that I don't want to print")
        case let someString as String:
            print("a string value of \"\(someString)\"")
        case let (x, y) as (Double, Double):
            print("an (x, y) point at \(x), \(y)")
        case let movie as Movie:
            print("a movie called \(movie.name), dir. \(movie.director)")
        case let stringConverter as (String) -> String:
            print(stringConverter("Michael"))
        default:
            print("something else")
        }
    }
    // zero as an Int
    // zero as a Double
    // an integer value of 42
    // a positive double value of 3.14159
    // a string value of "hello"
    // an (x, y) point at 3.0, 5.0
    // a movie called Ghostbusters, dir. Ivan Reitman
    // Hello, Michael
    

访问控制(Access Control)

  • Swift提供了5种访问级别(Access Levels):
    open(模块间可访问可扩展级别,最高)
    public(模块间可访问但不可扩展级别,较高)
    internal(模块内访问级别,中等,缺省)
    file-private(文件内访问级别,较低)
    private(外围声明访问级别,最低)
    注:这里模块是指作为独立单元来构建并发布,可以使用import关键字导入到其他模块的框架(Framework)或者应用程序(Application)。
    // 类的访问级别
    public class SomePublicClass {}
    internal class SomeInternalClass {}
    fileprivate class SomeFilePrivateClass {}
    private class SomePrivateClass {}
    // 常量,变量,函数的访问级别
    public var somePublicVariable = 0
    internal let someInternalConstant = 0
    fileprivate func someFilePrivateFunction() {}
    private func somePrivateFunction() {}
    // 缺省的访问级别
    class SomeInternalClass {}              // implicitly internal
    let someInternalConstant = 0            // implicitly internal
    
  • 单一模块的应用通常只需要使用缺省的 internal 访问级别。
    框架的 API 应该使用 open 以及 public 访问级别。
    单元测试模块可以访问应用程序模块中所有 internal 访问级别的实体。
    (需要@testable特性声明该实体并且使用testing enabled编译设置来编译product模块)
  • 访问控制原则:任何实体都不能用低于自己的访问级别的其他实体来定义。
  • 类型的访问级别会影响其成员(属性,方法,构造器,下标)和嵌套类型的访问级别。
    file-private 以及 private 类型的成员和嵌套类型的缺省访问级别分别为 file-private 和 private。
    public 或者 internal 类型的成员和嵌套类型的缺省访问级别为 internal。
    // 缺省访问级别
    public class SomePublicClass {                  // explicitly public class
        public var somePublicProperty = 0            // explicitly public class member
        var someInternalProperty = 0                 // implicitly internal class member
        fileprivate func someFilePrivateMethod() {}  // explicitly file-private class member
        private func somePrivateMethod() {}          // explicitly private class member
    }
     
    class SomeInternalClass {                       // implicitly internal class
        var someInternalProperty = 0                 // implicitly internal class member
        fileprivate func someFilePrivateMethod() {}  // explicitly file-private class member
        private func somePrivateMethod() {}          // explicitly private class member
    }
     
    fileprivate class SomeFilePrivateClass {        // explicitly file-private class
        func someFilePrivateMethod() {}              // implicitly file-private class member
        private func somePrivateMethod() {}          // explicitly private class member
    }
     
    private class SomePrivateClass {                // explicitly private class
        func somePrivateMethod() {}                  // implicitly private class member
    }
    
  • 元组的访问级别会被自动推导为元组成员中最低的访问级别。
  • 函数的访问级别不得高于该函数的参数类型和返回类型的访问级别。
    private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
        // ...
    }
    
  • 枚举中成员的访问级别继承自该枚举,不能单独指定。
    枚举的原始值和关联值的访问级别不能低于枚举的访问级别。
  • 子类的访问级别不得高于父类的访问级别。
    但是子类成员的访问级别可以高于它所覆盖的父类成员的访问级别。
    只要符合访问控制原则,子类成员甚至可以调用具有较高访问级别的父类成员。
    public class A {
        private func someMethod() {}
    }
    internal class B: A {
        override internal func someMethod() {}
    }
    
    public class A {
        private func someMethod() {}
    }
     
    internal class B: A {
        override internal func someMethod() {
            super.someMethod()
        }
    }
    
  • 常量,变量,属性不能拥有比自身类型更高的访问级别。
    下标的访问级别不得高于该下标的索引类型和返回类型的访问级别。
    常量,变量,属性,下标的Getters和Setters的访问级别继承自它们所属的常量,变量,属性,下标的访问级别。
    struct TrackedString {
        private(set) var numberOfEdits = 0
        var value: String = "" {
            didSet {
                numberOfEdits += 1
            }
        }
    }
    var stringToEdit = TrackedString()
    stringToEdit.value = "This string will be tracked."
    stringToEdit.value += " This edit will increment numberOfEdits."
    stringToEdit.value += " So will this one."
    print("The number of edits is \(stringToEdit.numberOfEdits)")
    // Prints "The number of edits is 3"
    public struct TrackedString {
        public private(set) var numberOfEdits = 0
        public var value: String = "" {
            didSet {
                numberOfEdits += 1
            }
        }
        public init() {}
    }
    
  • 自定义构造器的访问级别可以低于或等于它所属类型的访问级别。
    但是必要构造器的访问级别必须和所属类型的访问级别相同。
    private类型的缺省构造器的访问级别为private。
    public或者internal类型的缺省构造器的访问级别为internal。
  • 如果结构体中的任一存储属性的访问级别为private,那么它缺省的成员逐一构造器访问级别就是private。
    否则该成员逐一构造器的访问级别为internal。
  • 协议中的所有需求(方法及属性)都具有和该协议相同的访问级别,不能单独指定。
    与其它类型不同的是,public访问级别的协议中的所有需求也将是public访问级别。
    继承了别的协议的协议所拥有的访问级别最高也只能与被继承协议的访问级别相同。
    采纳了协议的类型的访问级别取决于类型本身的访问级别以及该类型所采纳的任何协议的访问级别中最低的一方。
  • 扩展成员缺省具有和原始类型成员相同的访问级别。
    采纳了协议的扩展的成员的访问级别与所采纳协议的访问级别相同,不能单独指定。
  • 泛型类型或泛型函数的访问级别取决于以下访问级别中最低的一方。
    该泛型类型或泛型函数本身的访问级别
    任何施加于该泛型类型或泛型函数的类型参数之上的类型约束的访问级别
  • 一个类型别名的访问级别不可高于它所指向类型的访问级别。

高级运算符(Advanced Operators)

  • 位运算符
    // 按位取反运算符(~)
    let initialBits: UInt8 = 0b00001111
    let invertedBits = ~initialBits  // equals 11110000
    // 按位与运算符(&)
    let firstSixBits: UInt8 = 0b11111100
    let lastSixBits: UInt8  = 0b00111111
    let middleFourBits = firstSixBits & lastSixBits  // equals 00111100
    // 按位或运算符(|)
    let someBits: UInt8 = 0b10110010
    let moreBits: UInt8 = 0b01011110
    let combinedbits = someBits | moreBits  // equals 11111110
    // 按位异或运算符(^)
    let firstBits: UInt8 = 0b00010100
    let otherBits: UInt8 = 0b00000101
    let outputBits = firstBits ^ otherBits  // equals 00010001
    // 按位左移运算符(<<)和按位右移运算符(>>)
    let shiftBits: UInt8 = 4   // 00000100 in binary
    shiftBits << 1             // 00001000
    shiftBits << 2             // 00010000
    shiftBits << 5             // 10000000
    shiftBits << 6             // 00000000
    shiftBits >> 2             // 00000001
    let pink: UInt32 = 0xCC6699
    let redComponent = (pink & 0xFF0000) >> 16    // redComponent is 0xCC, or 204
    let greenComponent = (pink & 0x00FF00) >> 8   // greenComponent is 0x66, or 102
    let blueComponent = pink & 0x0000FF           // blueComponent is 0x99, or 153
    
  • 溢出运算符:
    溢出加法 &+
    溢出减法 &-
    溢出乘法 &*
    var potentialOverflow = Int16.max
    // potentialOverflow equals 32767, which is the maximum value an Int16 can hold
    potentialOverflow += 1
    // this causes an error
    var unsignedOverflow = UInt8.max
    // unsignedOverflow equals 255, which is the maximum value a UInt8 can hold
    unsignedOverflow = unsignedOverflow &+ 1
    // unsignedOverflow is now equal to 0
    var unsignedOverflow = UInt8.min
    // unsignedOverflow equals 0, which is the minimum value a UInt8 can hold
    unsignedOverflow = unsignedOverflow &- 1
    // unsignedOverflow is now equal to 255
    var signedOverflow = Int8.min
    // signedOverflow equals -128, which is the minimum value an Int8 can hold
    signedOverflow = signedOverflow &- 1
    // signedOverflow is now equal to 127
    
  • 运算符的优先级和结合性
  • 运算符函数
    struct Vector2D {
        var x = 0.0, y = 0.0
    }
    func + (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y + right.y)
    }
    let vector = Vector2D(x: 3.0, y: 1.0)
    let anotherVector = Vector2D(x: 2.0, y: 4.0)
    let combinedVector = vector + anotherVector
    // combinedVector is a Vector2D instance with values of (5.0, 5.0)
    
    // 前缀和后缀运算符
    prefix func - (vector: Vector2D) -> Vector2D {
        return Vector2D(x: -vector.x, y: -vector.y)
    }
    let positive = Vector2D(x: 3.0, y: 4.0)
    let negative = -positive
    // negative is a Vector2D instance with values of (-3.0, -4.0)
    let alsoPositive = -negative
    // alsoPositive is a Vector2D instance with values of (3.0, 4.0)
    
    // 复合赋值运算符
    func += (inout left: Vector2D, right: Vector2D) {
        left = left + right
    }
    var original = Vector2D(x: 1.0, y: 2.0)
    let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
    original += vectorToAdd
    // original now has values of (4.0, 6.0)
    
    // 等价运算符
    func == (left: Vector2D, right: Vector2D) -> Bool {
        return (left.x == right.x) && (left.y == right.y)
    }
    func != (left: Vector2D, right: Vector2D) -> Bool {
        return !(left == right)
    }
    let twoThree = Vector2D(x: 2.0, y: 3.0)
    let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
    if twoThree == anotherTwoThree {
        print("These two vectors are equivalent.")
    }
    // Prints "These two vectors are equivalent."
    
    // 自定义运算符
    prefix func +++ (inout vector: Vector2D) -> Vector2D {
        vector += vector
        return vector
    }
    var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
    let afterDoubling = +++toBeDoubled
    // toBeDoubled now has values of (2.0, 8.0)
    // afterDoubling also has values of (2.0, 8.0)
    
    // 自定义中缀运算符的优先级和结合性
    infix operator +- { associativity left precedence 140 }
    func +- (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y - right.y)
    }
    let firstVector = Vector2D(x: 1.0, y: 2.0)
    let secondVector = Vector2D(x: 3.0, y: 4.0)
    let plusMinusVector = firstVector +- secondVector
    // plusMinusVector is a Vector2D instance with values of (4.0, -2.0)
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值