zoukankan      html  css  js  c++  java
  • Swift学习笔记二

    Swift是苹果公司开发的一门新语言,它当然具备面向对象的许多特性,现在开始介绍Swift中类和对象的语法。

    对象和类

    用"class"加上类名字来创建一个类,属性声明和声明常量或者变量是一样的,只是它是在类里边声明的而已。方法和函数声明也是一样的:

    class Shape {
        var numberOfSides = 0
        func simpleDescription() -> String {
            return "A shape with (numberOfSides) sides."
        }
    }

    创建类对象也很简单,注意这里没有用new关键字,类对象的属性和方法的访问方式是通过.实现的

    var shape = Shape()
    shape.numberOfSides = 7
    var shapeDescription = shape.simpleDescription()

    类的声明里边,通常都会有初始化方法init,

    class NamedShape {
        var numberOfSides: Int = 0
        var name: String
        
        init(name: String) {
            self.name = name
        }
        
        func simpleDescription() -> String {
            return "A shape with (numberOfSides) sides."
        }
    }

    注意这里用self来指代当前类对象,这样就区分了属性name和传入init方法的参数name。

    每个属性都需要被赋值,要么在声明它的时候,或者在初始化方法中。

    用deinit方法来创建解构函数,在类对象被释放之前做一些清理工作。

    类的继承语法也很简单,用冒号加上父类名称就可以了。没有约定子类必须要继承自哪些根类,因此继承不是必须的。子类通过override标识覆盖父类方法。如果子类中有与父类同名的方法而没有override,则编译器会报错。编译器也会探测标识了override但是父类中又没有同名的方法。

    class Square: NamedShape {
        var sideLength: Double
        
        init(sideLength: Double, name: String) {
            self.sideLength = sideLength
            super.init(name: name)
            numberOfSides = 4
        }
        
        func area() ->  Double {
            return sideLength * sideLength
        }
        
        override func simpleDescription() -> String {
            return "A square with sides of length (sideLength)."
        }
    }
    let test = Square(sideLength: 5.2, name: "my test square")
    test.area()
    test.simpleDescription()

    简单属性可以直接保存,属性也可以有存取器:

    class EquilateralTriangle: NamedShape {
        var sideLength: Double = 0.0
        
        init(sideLength: Double, name: String) {
            self.sideLength = sideLength
            super.init(name: name)
            numberOfSides = 3
        }
        
        var perimeter: Double {
            get {
                return 3.0 * sideLength
            }
            set {
                sideLength = newValue / 3.0
            }
        }
        
        override func simpleDescription() -> String {
            return "An equilateral triangle with sides of length (sideLength)."
        }
    }
    var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
    println(triangle.perimeter)
    triangle.perimeter = 9.9
    println(triangle.sideLength)

    在setter中,新值的名称隐式地是newValue,也可以在set后显示地指明别的名称。

    如果你的属性不需要计算,但是在设定值之前或者之后仍然需要写一些逻辑,可以用willSet和didSet,比如,下边的类就确保它的三角形的边长和正方形的边长始终相等:

    class TriangleAndSquare {
        var triangle: EquilateralTriangle {
            willSet {
                square.sideLength = newValue.sideLength
            }
        }
        var square: Square {
            willSet {
                triangle.sideLength = newValue.sideLength
            }
        }
        init(size: Double, name: String) {
            square = Square(sideLength: size, name: name)
            triangle = EquilateralTriangle(sideLength: size, name: name)
        }
    }
    var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
    println(triangleAndSquare.square.sideLength)
    println(triangleAndSquare.triangle.sideLength)
    triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
    println(triangleAndSquare.triangle.sideLength)

    类的方法和一般函数有一个很重要的区别。一般函数的参数名只在函数内部被用到,但是类方法的参数名在你调用方法的时候也被用到了(第一个参数除外)。默认情况下,当你调用某个方法的时候,该方法与其内部都有相同的参数名。你可以指定另外的名称,这个名称将在方法内部使用:

    class Counter {
        var count: Int = 0
        func incrementBy(amount: Int, numberOfTimes times: Int) {
            count += amount * times
        }
    }
    var counter = Counter()
    counter.incrementBy(2, numberOfTimes: 7)

    当处理可省略变量的时候,可以在运算比如属性、方法、下标操作之前加上问号。如果问号之前的值是nil,问号之后的所有表达式被忽略掉,整个表达式的值也是nil。否则,可省略值被展开,问号之后的所有表达式都基于展开的可省略值。无论如何,整个表达式的值都是可省略值。

    let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
    let sideLength = optionalSquare?.sideLength

    枚举类型和结构体

    用enum来创建枚举类型变量。像类和其他类型一样,枚举类型也可以有与之相应的方法:

    enum Rank: Int {
        case Ace = 1
        case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
        case Jack, Queen, King
        func simpleDescription() -> String {
            switch self {
            case .Ace:
                return "ace"
            case .Jack:
                return "jack"
            case .Queen:
                return "queen"
            case .King:
                return "king"
            default:
                return String(self.rawValue)
            }
        }
    }
    let ace = Rank.Ace //Enum Value
    let aceRawValue = ace.rawValue //1

    在上边的例子里,枚举类型变量Rank的原始类型(raw-type)是Int类型,因此只需要给第一个值赋值,剩下的值会一次自动赋予。也可以把枚举变量的原始类型设定为字符串或者浮点数,用rawValue来获取枚举变量的原始值。用init?(rawValue:)初始化器从一个原始值创建一个枚举类型的实例。

    if let convertedRank = Rank(rawValue: 3) {
        let threeDescription = convertedRank.simpleDescription()
    }

    枚举类型的成员值就是实际的值,并不是原始值(raw value)的另一种书写方式,事实上,并没有所谓的真正意义上的原始值,并不需要为每个枚举类型成员赋原始值

    enum Suit {
        case Spades, Hearts, Diamonds, Clubs
        func simpleDescription() -> String {
            switch self {
            case .Spades:
                return "spades"
            case .Hearts:
                return "hearts"
            case .Diamonds:
                return "diamonds"
            case .Clubs:
                return "clubs"
            }
        }
    }
    let hearts = Suit.Hearts
    let heartsDescription = hearts.simpleDescription()

    注意这里用了两种引用枚举类型实例的成员值的方式:当把它作为值复制给常量hearts时,是用的显示地指明全称Suit.Hearts,因为常量没有隐式地指明类型;而在switch内部,枚举类型的成员值是用简写方式.Hearts被引用的,这是因为self的类型已经是已知合适的类型了。在任何变量类型已知并且合适的时候,都可以使用这种简写方式。

    结构体

    用struct关键字来创建结构体,结构体支持很多类的行为,包括方法和初始化器。结构体和类最大的区别在于当在代码里传递的时候,结构体永远是被拷贝的,而类只传递了引用。

    struct Card {
        var rank: Rank
        var suit: Suit
        func simpleDescription() -> String {
            return "The (rank.simpleDescription()) of (suit.simpleDescription())" //在字符串中直接引用表达式或者变量
        }
    }
    let threeOfSpades = Card(rank: .Three, suit: .Spades) //注意这种简写形式,是因为rank和suit的变量类型都已经确定了
    let threeOfSpadesDescription = threeOfSpades.simpleDescription()

    枚举类型成员的实例可以拥有和实例关联的值(associated value),枚举类型成员的不同实例可以有不同的值和它们相关联,这些关联值是在创建实例的时候提供的。

    关联值(associated value)和原始值(raw value)是不同的:枚举类型成员的原始值对所有实例而言是相同的,在定义该枚举类型的时候就需要给出原始值。

    举个栗子,在向一个服务器请求日出和日落时间的数据,服务器的返回分为两种情况:返回相应的时间或者返回一个错误

    enum ServerResponse {
        case Result(String, String)
        case Error(String)
    }
     
    let success = ServerResponse.Result("6:00 am", "8:09 pm")
    let failure = ServerResponse.Error("Out of cheese.")
     
    switch success {
    case let .Result(sunrise, sunset):
        let serverResponse = "Sunrise is at (sunrise) and sunset is at (sunset)."
    case let .Error(error):
        let serverResponse = "Failure...  (error)"
    }

    注意sunrise和sunset是如何作为匹配switch的case的一部分从ServerResponse中被取出的。

  • 相关阅读:
    Python正则表达式re模块
    time,datetime,calendar模块
    Python的特殊属性和魔法函数
    Django环境搭建
    第十二篇 os模块
    第十一篇 logging模块
    Page Object设计模式
    实现自动发邮件功能
    cs61a Mutable Data 2 学习笔记和补充
    Lambda Expressions and Higher-Order Functions 学习笔记和习题解答
  • 原文地址:https://www.cnblogs.com/dson/p/4551705.html
Copyright © 2011-2022 走看看