Swift编程高级教程 变量与常量

常量与变量

常量和变量是某个特定类型的值的名字,如果在程序运行时值不能被修改的是一个常量,反之是一个变量。

一、常量和变量的声明

Swift中的常量和变量在使用前必须先声明。其中let关键字声明常量,var关键字声明变量:

//声明一个名为maximumNumberOfLoginAttempts的整型常量,并且值为10let maximumNumberOfLoginAttempts = 10//声明一个名为currentLoginAttempt的整型变量,并且值为0var currentLoginAttempt = 0

可以在同一行声明多个变量,中间用逗号,隔开:

var x = 0.0, y = 0.0, z = 0.0

提示
如果在程序运行的时候值不需要发生改变,应该将它们声明为常量,否则声明为变量

变量的值可以进行修改:

var friendlyWelcome = "Hello!"friendlyWelcome = "Bonjour!" //friendlyWelcome的值发生改变

常量的值一旦设置后就不能在修改:

let languageName = "Swift"languageName = "Swift++" //编译时出错

类型说明

在Swift中声明常量或者变量可以在后面用冒号:指定它们的数据类型。

//声明一个String类型的变量,可以存放String类型的值var welcomeMessage: String

提示
实际应用中很少需要指定变量数据类型,Swift会根据所设置的值的类型进行推导。

命名规则

Swift中可以使用任意字符给常量和变量命名,包括Unicode编码,比如中文、Emoji等:

let π = 3.14159let 你好 = "你好世界"let dog = "dogcow"

名字里面不能包含数学运算符、箭头、非法的Unicode字符以及不能识别的字符等,并且不能以数字开头。同一个作用域的变量或者常量不能同名。

提示
如果想用关键字作为变量的名字,要用(`)包裹起来。为了方便理解,如果不是万不得已,不应该使用关键字作为变量的名字。

打印变量的值

println函数可以打印常量或者变量的值:

println(friendlyWelcome) //打印出“Bonjour!”

println是一个全局函数,输出时自动在结尾添加换行。print函数与它的功能类似,只是不会在结尾添加换行符。printlnNSLog类似,可以用来输出复杂的日志信息。Swift使用字符串插值来输出变量和常量。

println("The current value of friendlyWelcome is \(friendlyWelcome)")//打印“The current value of friendlyWelcome is Bonjour!”

注释

注释是用来帮助理解和记忆代码功能的,并不会参与编译。Swift有两种注释形式,单行注释和多行注释:

//这是单行注释,用两个斜线开头,直到改行的结尾/*这是多行注释,
可以横跨很多行,
/*比C语言更加NB的是,*/它竟然还支持嵌套的注释!*/

分号

Swift中语句结尾的分号;不是必须的,不过如果想要在同一行中写多个语句,则需要使用;进行分隔。

let cat = "cat"; println(cat)//打印“cat”

二、属性

属性是依赖于某个特定的类、结构体或者枚举类型的值。Swift有两种属性:存储类型和计算类型。其中存储类型可以作为实例的一部分存放变量或者常量的值,而计算类型的属性值是通过运算的来的。计算类型的属性可以在类、结构体和枚举类型中出现,但存储类型只可能出现在类和结构体类型中。

属性一般依赖于一个特定类型的实例,但是也可以依赖于类本身。依赖于类型本身的属性称为类型属性。

可以定义属性观察者来监督属性值的改变,从而作出响应。

存储属性

常量属性let的值在初始化后不能在改变,而变量属性var的值可以随时更改。

struct FixedLengthRange {    var firstValue: Int
    let length: Int
}var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
rangeOfThreeItems.firstValue = 6

结构体常量的存储属性

如果一个结构体实例被赋值给一个常量,则这个实例所拥有的存储类型的属性都不能在改变,包括变量属性在内。

let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
rangeOfFourItems.firstValue = 6//编译错误,firstValue的值不能改变

延时存储属性

延时存储属性的初始值直到第一次使用的时候才进行计算,在声明时通过@lazy进行标记。

提示
一定要将延时存储属性声明为变量(var),因为它的初始值可能会在实例初始化完成后才有,而常量属性一般在实例初始化完成之前就会有值。

当属性的初始值依赖于外部银子,并且该因子的值在实例初始化完成之前不确定时,延时属性非常有用。如果属性初始化时需要进行大量的计算,也可以考虑使用延时属性。

下面是延时属性的示例:

class DataImporter {    /*
    DataImporter是一个从外部文件导入数据的类。假设它需要花费较多的时间进行初始化
    */
    var fileName = "data.txt"
    //DataImporter类的数据导入功能}

class DataManager {
    @lazy var importer = DataImporter()    var data = String[]()    //DataManager类提供数据管理功能}

let manager = DataManager()
manager.data += "Some data"manager.data += "Some more data"//DataImporter实例还没有创建

只有访问DataManagerimporter属性时才会去创建这个对象。

println(manager.importer.filename)//创建importer属性并打印“data.txt"

存储属性与实例变量

Objective-C类的对象可以使用属性或者实例变量来存储值。Swift中并没有所谓的实例变量,而是将它们统一为属性了,这样使得属性的声明更加简化。

计算属性

除了存储属性外,类、结构体和枚举类型还可以定义计算属性。这些计算属性并不能够存储值,而是通过getter方法和可选的setter方法来间接的获取和设置其它属性和值。

struct Point {    var x = 0.0, y = 0.0}struct Size {    var width = 0.0, height = 0.0}struct Rect {    var origin = Point()    var size = Size()    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)            return Point(x: centerX, y: centerY)
        }

        set(newCenter) {
            origin.x = newCenter.x - (size.width / 2)
            origin.y = newCenter.y - (size.height / 2)
        }
    }
}var square = Rect(origin: Point(x: 0.0, y: 0.0),
                    size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)println("square.origin is now at (\(square.origin.x), \(square.origin.y))")//打印”square.origin is now at (10.0, 10.0)“

这个例子定义了三个结构体来表示几何形状:

  • Point封装了(x, y)坐标。
  • Size封装了宽度和高度。
  • Rect用坐标原点和大小定义一个矩形。

其中Rect结构体还提供了一个center的计算属性。这个属性的值是由矩形的originsize属性决定的,它本身并不需要存储信息。但是改变center的值,会间接的修改矩形的其它属性。

三、简化setter的声明

如果没有为计算属性的setter的新值指定名字,则默认使用newValue。下面是Rect结构体的另外一种写法:

struct AlternativeRect {    var origin = Point()    var size = Size()    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)            return Point(x: centerX, y: centerY)
        }
        set {
            origin.x = newValue.x - (size.width / 2)
            origin.y = newValue.y - (size.height / 2)
        }
    }
}

只读的计算属性

如果一个计算属性只有getter而没有声明setter,则它是一个只读的计算属性。只读属性只能通过点语法返回一个值,而不能对它进行设置。

提示
必须使用var 声明计算属性,包括只读的计算属性在内,因为它们的值是可能改变的。而let只能用于常量的声明,表示它们的值不能发生改变。

还可以省略只读计算属性声明中的get关键字。

struct Cuboid {    var width = 0.0, height = 0.0, depth = 0.0
    var volume: Double {        return width * height * depth
    }
}

let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")//打印“the volume of fourByFiveByTwo is 40.0”

属性观察者

属性观察者用来观察和响应属性值的变化。每次设置属性的值都会调用相应的观察者,哪怕是设置相同的值。

可以给除延时存储属性以外的任何存储属性添加观察者。通过重写属性,可以在子类中给父类的属性(包括存储属性和计算属性)添加观察者。

提示
不需要给类本身定义的计算属性添加观察者,完全可以在计算属性的setter中完成对值的观察。

通过下面两个方法对属性进行观察:

  • willSet在属性的值发生改变之前调用。
  • didSet在设置完属性的值后调用。

如果没有给willSet指定参数的话,编译器默认提供一个newValue做为参数。同样,在didSet中如果没有提供参数的话,默认为oldValue

提示
willSetdidSet观察者在属性进行初始化的时候不会被调用。

class StepCounter {    var totalSteps: Int = 0 {
        willSet(newTotalSteps) {            println("About to set totalSteps to \(newTotalSteps)")
        }
        didSet {            if totalSteps > oldValue {                println("Added \(totalSteps - oldValue) steps")
            }
        }
    }
}

let stepCounter = StepCounter()
stepCounter.totalSteps = 200//About to set totalSteps to 200//Added 200 stepsstepCounter.totalSteps = 360//About to set totalSteps to 360//Added 160 stepsstepCounter.totalSteps = 896//About to set totalSteps to 896//Added 536 steps

提示
如果在didSet中给属性设置新值,最终结果就是最后设置的这个值。

全局变量与局部变量

上面关于计算属性和属性观察对全局变量和局部变量同样成立。全局变量定义在任意的方法、函数、闭包或者类型定义之外。而局部变量则定义在方法、函数或闭包之内。

之前遇到的全局变量或者局部变量都跟存储属性类型,都是用来存储值的。但实际上它们也能像计算属性有计算变量。

提示
全局变量和常量与延时属性类似,总是延时进行计算。但是它们并不需要使用@lazy标记。
局部常量和变量一定不是延时计算的。

类型属性

实例属性属于某个特定类型的实例。每次创建的实例,它都拥有自己的一组独立的属性值,不受其它实例对象影响。

你还可以定义属于类型本身的属性。这些属性是与具体的实例无关的,不管创建多少个实例都只有一份。这种属性称之为类型属性。

可以给值类型(结构体和枚举类型)定义存储和计算类型的类属性,但是只能给类定义计算类型的类属性。值类型的存储属性可以是变量或常量。

提示
一定要给存储类型的类属性设置初始值。

类型属性语法

在C/Objective-C中只能使用全局静态变量来定义依赖与某个属性的变量或常量。但是在Swift中可以直接将它们定义为类型的一部分。其中结构体和枚举类型中使用static关键字,而在类类型中则使用class关键字。

struct SomeStructure {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {        //return an Int value here
    }
}

enum SomeEnumeration {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {        //return an Int value here
    }
}

class SomeClass {
    class var computedTypeProperty: Int {        //return an Int value here
    }
}

提示
上面的计算属性都是只读的,但实际上可以定义为可读可写

使用类型属性

类型属性通过类型名字和点操作符进行访问和设置,而不是通过实例对象:

println(SomeClass.computedTypeProperty)//print "42"println(SomeStructure.storedTypeProperty)//prints "Some value"SomeStructure.storedTypeProperty = "Another value."println(SomeStructure.storedTypeProperty)//prints "Another value."

下面演示了如何使用一个结构体来对声道音量进行建模,其中每个声道音量范围为0-10。

struct AudioChannel {
    static let thresholdLevel = 10
    static var maxInputLevelForAllChannel = 0
    var currentLevel: Int = 0 {
        didSet {            if currentLevel > AudioChannel.thresholdLevel {
                currentLevel = AudioChannel.thresholdLevel
            }            if currentLevel > AudioChannel.maxInputLevelForAllChannels{
                AudioChannel.maxInputLevelForAllChannels = currentLevel
        }
    }
}var leftChannel = AudioChannel()var rightChannel = AudioChannel()

leftChannel.currentLevel = 7println(leftChannel.currentLevel)//prints "7"println(AudioChannel.maxInputLevelForAllChannels)//prints "7"

当修改其中一个声道的值时,整个声道的音量最大值就可能发生改变。而每个声道都有自己的当前音量水平。

时间: 2024-10-01 06:59:28

Swift编程高级教程 变量与常量的相关文章

Swift编程高级教程(三)集合类型-数组

集合类型-数组 Swift语言提供了两种集合数据类型:数组和字典,数组是一系列相同类型的变量值有序存储:字典是一系列相同类型的变量值的无序存储,可以通过一个唯一标识符(键)来引用和查找. 数组和字典总是能识别自己所能够存储的键值的类型,就是说,我们不能够往这两个容器内插入错误的类型.显式类型声明的集合能确保我们的代码总是能识别其所能存储的变量类型,并能够让我们在实际编码中捕捉到出现的任何类型错误. 提示Swift的数组类型的变量在常量,变量赋值或者给函数和方法传参的时候会表现出和其他类型不一样的

Swift研究之编程高级教程(二)属性,存储属性详解

 属性 属性是依赖于某个特定的类.结构体或者枚举类型的值.Swift有两种属性:存储类型和计算类型.其中存储类型可以作为实例的一部分存放变量或者常量的值,而计算类型的属性值是通过运算的来的.计算类型的属性可以在类.结构体和枚举类型中出现,但存储类型只可能出现在类和结构体类型中. 属性一般依赖于一个特定类型的实例,但是也可以依赖于类本身.依赖于类型本身的属性称为类型属性. 可以定义属性观察者来监督属性值的改变,从而作出响应.对集合不明白的看集合类型-数组详解 存储属性 常量属性let的值在初始

泊学Swift系列之Swift Up and Running——变量和常量

Swift Up and Running——变量和常量 泊学原文 泊学技法视频 当我们学习一门语言的时候,无论是说还是写,也无论是外语或者编程语言,我们都会用自己已经掌握的语言中的元素去理解新语言中对应的部分.学习Swift也一样,作为一种编程语言,它有着和Objective-C,JavaScript或C#等其它编程语言共通的概念和类似的表达方式.如果你或多或少了解过一些编程语言,学习Swift将会是一个非常轻松的过程. Playground Playground是Apple在2014年WWDC

Net并行编程高级教程--Parallel

Net并行编程高级教程--Parallel 一直觉得自己对并发了解不够深入,特别是看了<代码整洁之道>觉得自己有必要好好学学并发编程,因为性能也是衡量代码整洁的一大标准.而且在<失控>这本书中也多次提到并发,不管是计算机还是生物都并发处理着各种事物.人真是奇怪,当你关注一个事情的时候,你会发现周围的事物中就常出现那个事情.所以好奇心驱使下学习并发.便有了此文. 一.理解硬件线程和软件线程 多核处理器带有一个以上的物理内核--物理内核是真正的独立处理单元,多个物理内核使得多条指令能够

【读书笔记】.Net并行编程高级教程--Parallel

一直觉得自己对并发了解不够深入,特别是看了<代码整洁之道>觉得自己有必要好好学学并发编程,因为性能也是衡量代码整洁的一大标准.而且在<失控>这本书中也多次提到并发,不管是计算机还是生物都并发处理着各种事物.人真是奇怪,当你关注一个事情的时候,你会发现周围的事物中就常出现那个事情.所以好奇心驱使下学习并发.便有了此文. 一.理解硬件线程和软件线程 多核处理器带有一个以上的物理内核--物理内核是真正的独立处理单元,多个物理内核使得多条指令能够同时并行运行.硬件线程也称为逻辑内核,一个物

《从零开始学Swift》学习笔记(Day58)—— Swift编码规范之变量或常量声明规范

原创文章,欢迎转载.转载请注明:关东升的博客 声明是在声明变量.常量.属性.方法或函数和自定义类型时候需要遵守的规范. 首先变量或常量时每行声明变量或常量的数量推荐一行一个,因为这样以利于写注释.示例代码如下. 推荐使用: let level = 0 var size = 10 不推荐使用: let level = 0; var size =10 变量或常量的数据类型,如果有可能应尽可能采用类型推断,这样代码很简洁.示例代码如下. 推荐使用: let level = 0 var size = 1

Swift学习笔记_变量和常量

1 标识符 给程序中的变量.常量.函数.结构体.类.枚举.方法.协议等命名的名字 可使用任意的字符作为命名标识符,但有如下的命名规则: (1)区分大小写 (2)不能以数字开头,但可在其他地方包含数字 (3)不能包含空格.数学符号.箭头.保留或非法的Unicode码位.连线与制表符 (4)不能是关键字,但可以使用反引号(`)将关键字包围的方式将其作为名字使用, 应当避免使用关键字作为标识符 var tmpInt = 1 var tmpint = 2 var tmpString = "Hello W

Windows客户端C/C++编程规范“建议”——变量和常量

8 变量和常量 8.1 尽量不要使用全局变量 等级:[要求] 说明:全局变量的滥用和goto的滥用一样,都是一种灾难.它将使得逻辑变得难以调试和控制. 8.2 不涉及外部使用的全局变量需要使用static关键字修饰 等级:[要求] 说明:这样可以避免冲突. 8.3 变量需初始化后才能使用 等级:[必须] 说明:变量最好在定义时初始化.如果定义时无法初始化,那就应该在定义后立即初始化. 以下我们来分析下变量未初始化而被使用的场景: 在debug环境下,我们声明一个变量,编译器会使用0xCC填充变量

(二)C#编程基础复习——变量和常量

今天要复习一下C#基础中的变量和常量,所谓变量,就是用来存储特定类型的数据,分为值类型和引类型,可以根据需要随时改变变量中所村存储的数据值,变量必须先声明,然后才能赋值:常量就是固定不变的值,常量的变量值是唯一的,标志const. 1.变量类型有两种,分别是值类型和引类型 值类型,主要包含整数类型(sbyte.short.int.long.byte.ushort.uint.ulong).浮点类型(float.double.decimal)以及布尔类型(bool)等,主要有以下特性:A.值类型变量