Swift 中的变量、常量、类型

2021-05-01  本文已影响0人  _浅墨_

a good building needs a good foundation

变量、常量、类型

变量是存储特定类型值的临时容器:

var count: Int
var shouldRemind: Bool
var text: String
var list: [ChecklistItem]

Swift 对类型校验非常严格,比其它许多语言都严格。如果变量的类型为 Int,则不能赋值给它 Float 类型。

即使两种类型都代表某种类型的数字,Swift 都不会自动在不同的数字类型之间进行转换。

eg.

var i = 10
var f: Float
f = i         // error
f = Float(i)  // OK

创建新变量时,我们不必总是指定类型。如果给变量一个初始值,Swift 将使用类型(type inference)推断来自动确定该变量的类型:

var i = 10              // Int
var d = 3.14            // Double
var b = true            // Bool
var s = "Hello, world"  // String

如果使用具有与实例变量同名的局部变量,则可能引起混淆。当你调用那个变量时,你得到的可能并不是你想要的那个值,代码一多,你自己可能都分不清哪个是哪个了:

class MyObject {
  var count = 7      // an instance variable

  func myMethod() {
    var count = 42   // local variable “hides” instance variable
    print(count)     // prints 42
  }
}

一些开发者喜欢在实例变量名称的前面加下划线(_),以避免出现此问题:比如实例变量写成_count 而不是 count。还有一种方法是,当访问实例变量时使用关键字 self:

  func myMethod() {
    var count = 42
    print(self.count)   // prints 7
  }
常量 Constants

有时,我们将计算或方法调用的结果存储到临时容器中,此后该值将永远不会更改,在这种情况下,我们最好使用常量而不是变量:

let pi = 3.141592
let difference = abs(targetValue - currentValue)
let message = "You scored \(points) points"
let image = UIImage(named: "SayCheese")

提示:一个大牛的建议是,90%的情况下使用 let 都是正确的解决方案。如果使用 let 发现错误,Swift 编译器会警告我们正在尝试更改常量。这种情况下,我们再将 let 更改为 var。

值类型(Value types) vs 引用类型(reference types)

当使用基本类型(例如整数和字符串)时,使用 let 创建的常量一旦被赋予值就无法更改:

let pi = 3.141592
pi = 3                // not allowed

但是,对于引用类型(reference types)的对象,只有对象的变量(如下面示例中的 item)是常量。对象本身仍然可以更改:

let item = ChecklistItem()
item.text = "Do the laundry"
item.checked = false
item.dueDate = yesterday

但是 item 变量不可更改:

let anotherItem = ChecklistItem()
item = anotherItem   // cannot change the reference

定义为 class 的对象是引用类型,而定义为 struct 或 enum 的对象是值类型。这意味着 iOS SDK 中的大多数对象都是引用类型,但是 Swift 语言中内置的内容(例如 Int,String 和 Array)都是值类型。

集合 Collections

数组存储对象列表,它包含的对象是按顺序排序的,我们可以通过索引检索它们。

// An array of ChecklistItem objects:
var items: Array<ChecklistItem>

// Or, using shorthand notation:
var items: [ChecklistItem]

// Making an instance of the array:
items = [ChecklistItem]()

// Accessing an object from the array:
let item = items[3]

我们可以将数组写为 Array<Type> or [Type] 。第一个是正式写法,第二个是“语法糖”(syntactic sugar),它更容易阅读。 与其它语言不同,在 Swift 中,不能写为 Type [],类型名称应放在方括号内。

词典(dictionary)存储键值对。一个对象(通常是字符串)是检索另一个对象的键。

// A dictionary that stores (String, Int) pairs, for example a
// list of people’s names and their ages:
var ages: Dictionary<String, Int>

// Or, using shorthand notation:
var ages: [String: Int]

// Making an instance of the dictionary:
ages = [String: Int]()

// Accessing an object from the dictionary:
var age = dict["Jony Ive"]

从字典中检索对象的方法与从数组中读取的表示法非常相似,它们都使用 [] 括号。为了索引数组,我们始终使用正整数作为 key ,但是对于字典,通常使用字符串。

也有其它类型的集合,但是数组和字典是最常见的集合。

泛型 Generics

数组和字典被称为泛型,这意味着它们与存储在这些集合中的对象的类型无关。

我们可以拥有一个 Int 对象数组,也可以具有一个 String 对象数组,或者实际上是任何类型的对象数组,甚至还有其他数组的数组。

因此,必须先指定要存储在数组中的对象的类型,然后才能使用它,所以,我们不能这样写:

var items: Array  // error: should be Array<TypeName>
var items: []     // error: should be [TypeName]

在 [] 括号内或 Array 一词之后 <> 的括号内,应始终有一个类型声明。如果您以前开发 Objective-C,请注意 OC 中的 <> 的含义与此处完全不同。

对于字典,则需要提供两个类型名称:一个标识键的类型,一个标识值的类型。

Swift 要求所有变量和常量都有一个值。我们可以在声明变量或常量时默认指定一个值,也可以通过在 init 方法内为其分配一个值。

可选变量 Optionals

有时,使用无值的变量会很有用,在这种情况下,我们需要将其声明为可选变量:

var checklistToEdit: Checklist?

我们不能立即使用此变量,而应该首先测试它是否具有值。这称为可选解包(unwrapping the optional):

if let checklist = checklistToEdit {
  // “checklist” now contains the real object
} else {
  // the optional was nil
}

在使用字典中的值之前,您需要先使用 if let 将其解包:

if let age = dict["Jony Ive"] {
  // use the value of age
}

如果我们确定字典中肯定包含给定的键,则还可以使用强制解包(force unwrapping)来读取相应的值:

var age = dict["Jony Ive"]!

! 告诉 Swift,“此值绝对不会为 nil” 。当然,如果为 nil ,则要 crash 了。

强制解包(force unwrapping)的一种较安全的替代方法是可选链接( optional chaining)。例如,如果navigationController 属性为nil,以下内容将使 app crash:

navigationController!.delegate = self

但是这样不会:

navigationController?.delegate = self

如果 navigationController 为 nil,则将被忽略。相当于如下写法:

if navigationController != nil {
  navigationController!.delegate = self
}

也可以使用感叹号代替问号来声明可选内容:

var dataModel: DataModel!

这样的值可能是不安全的,因为可以将其用作常规变量,而不必先对其进行拆包。

使用这种方式,有时显得更方便。当我们在声明或 init() 中无法为变量提供初始值时,可以使用这种方式。

但是,一旦给变量赋了一个值,就不应该再将其设置为 nil。 如果该值可以再次变为 nil,则最好使用带问号的 optional 。

方法(Methods)和函数(functions)

函数是独立的功能,与对象无关,需要显示的传递数据。
方法与对象和类相关,依赖对象而调用,可以直接处理对象上的数据,也就是隐式传递数据。

上一篇下一篇

猜你喜欢

热点阅读