在許多編程語言中都存在的枚舉類型,基本都是用于定義一個具有一組數據的值,且這些值是可以枚舉的。那么Swift中我們該如何定義并使用枚舉類型呢?我們從以下3個方面對Swift3中的枚舉進行梳理。
Swift3中枚舉的3種形式
1. 無raw value且無associated value
(1)定義無raw value且無associated value的枚舉
這種枚舉類型的定義非常簡單,例如:
enum SwitchState {
case ON
case OFF
}
它定義了開關的兩種狀態: ON, OFF。另外,它還有一種更簡潔的定義方式:
enum SwitchState {
case ON, OFF
}
(2)初始化及使用無raw value且無associated value類型的枚舉
示例:
var state = SWitchState.ON
switch state {
case .ON: print("This is ON state.")
case .OFF: print("This is OFF state.")
}
2. 有raw value
它用于給枚舉中定義的各個對象預先定義一個值。
(1)定義有raw value的枚舉
enum ASCIIControlCharacter: Character {
case tab = "\\t"
case lineFeed = "\\n"
case carriageReturn = "\\r"
}
它定義了一個包含一系列ASCII字符的枚舉類型,同時給其中的每個對象預先定義了一個字符串類型的值。如果預先定義的值的類型一致,那么我們可以用更簡潔的方式定義,例如:
enum CompassPoint: String {
case north, south, east, west
}
如果預先定義的值是Int類型,且值是遞增的,那么我們可以用如下方式定義:
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
(2)使用raw value 初始化有raw value的枚舉
let possiblePlanet = Planet(rawValue: 7)
// possiblePlanet is of type Planet? and equals Planet.uranus
(3)使用有raw value的枚舉的方式
let positionToFind = 11
if let somePlanet = Planet(rawValue: positionToFind) {
switch somePlanet {
case .earth:
print("Mostly harmless")
default:
print("Not a safe place for humans")
}
} else {
print("There isn't a planet at position \\(positionToFind)")
}
// Prints "There isn't a planet at position 11"
關于raw value需要注意的地方如下:
- 枚舉中定義的各值所對應的raw value均是常量,不可變化且互不相同;
- raw value對應的數據類型只能是String, Character, Int 或者Float類型。
3. 有associated value
在定義枚舉的時候注入一個與枚舉值相關聯的數據,這個數據以構造方法的形式注入到對象中。
(1)定義有associated value的枚舉
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
(2)初始化及使用有associated value的方式
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
switch productBarcode {
case let .upc(numberSystem, manufacturer, product, check):
print("UPC : \\(numberSystem), \\(manufacturer), \\(product), \\(check).")
case let .qrCode(productCode):
print("QR code: \\(productCode).")
}
// Prints "QR code: ABCDEFGHIJKLMNOP."
關于Associated value需要注意如下兩點:
- 關聯的數據變量可以是任意類型,且枚舉內定義的值的類型可以不同;
- 數據是變量而非常量。
Swift3中2個特殊的枚舉類型
1. Optional
(1)Optional的枚舉本質
要定義一個Optional類型的變量有兩種方式, 第一種方式,
let userName: Optional
第二種方式是第一種方式的語法糖形式,這也是最常用的定義optional的方式:
let studentName: String?
剝開事物看本質,對于Optional其實質就是枚舉類型??匆幌绿O果官方文檔對于optional的定義:
public enum Optional : _Reflectable, NilLiteralConvertible {
case None
case Some(Wrapped)
...
}
根據定義,我們可以看到Optional的本質就是枚舉類型。
(2)空虛的nil
nil是Optional枚舉實例的一個值,即上段代碼中的'None'值。nil有別于其它語言中的null值,以及OC中的nil值,它僅僅表示的是該對象不包含值,而并非指向一個不存在的對象。
關于nil的幾個注意點:
- 可以給任意類型的Optional對象設置為nil,而不僅僅是class類型;
- Optional對象的默認值為nil;
- 不能給非Optional類型的變量賦值為nil
(3)?與!兄弟
'?'和'!'兄弟是一對非常有趣的修飾符,用途非常普遍。在swift開發中,你可以經??吹剿鼈冃值茉诖a中出沒的身影,可以說哪哪都是。為什么說它們有趣呢?因為它們有著非常奇妙的功能,對于Optional類型的使用非常關鍵。'?'和'!'都可以用于變量聲明以及表達式中,但是有著各自的作用。
用途一:定義optional變量
'?'定義的變量是optional類型,如:let studentName: String?
'!'定義的變量也是optional類型,如:let studentName: String!
, 然而與'?'定義的變量不同的是,'?'定義的變量在使用時需要使用'!'進行解包,而使用'!'定義的變量無需解包就可以使用。總之,'!'定義變量的方式可以看成是使用'?'定義變量并使用'!'解包的快捷方式。需要注意的是我們應確保使用'!'定義的變量時刻有具體的值,否則使用時會造成crash。用途二:用于表達式中解包
'!'作用于表達時中時主要用于解包,例如:
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
let john = Person()
let roomCount = john.residence!.numberOfRooms
// this triggers a runtime error
'?'主要用于optional chain表達中,作用也是解包。如果當前值為nil時表達時返回nil,且不會造成crash,例如:
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
let john = Person()
//let roomCount = john.residence!.numberOfRooms
// this triggers a runtime error, the right way is as the following:
if let roomCount = john.residence?.numberOfRooms {
print("John's residence has \\(roomCount) room(s).")
} else {
print("Unable to retrieve the number of rooms.")
}
// Prints "Unable to retrieve the number of rooms."
(4)解包的三種方式
- 解包的方法一:'!'運算符
例如:
var userName: String? = "Mike"
print("The user name is \\(userName!)")
- 解包的方法二:optional binding:
if let {}
例如:
var userName: String? = "Mike"
if let name = userName {
print("The user name is \\(name)")
}
- 解包的方法三:optional chain:
如前所述,我們可以使用optional chain進行解包,這里不再具體闡述。
2. 迭代枚舉
迭代枚舉其實是具有associated value類型枚舉的一個特例。迭代枚舉是一個非常有意思的語法,類似于函數的嵌套迭代,它允許在枚舉定義Associated value的時候,將其值定義為與當前枚舉相同的數據類型,從而形成了一種迭代的特征。定義如下:
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression, ArithmeticExpression)
indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
迭代枚舉的使用方式如下:
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case let .number(value):
return value
case let .addition(left, right):
return evaluate(left) + evaluate(right)
case let .multiplication(left, right):
return evaluate(left) * evaluate(right)
}
}
print(evaluate(product))
// Prints "18"
Swift3中枚舉的面向對象
枚舉類型在swift中屬于一等類型,它和class以及struct共同組成swift的面向對象的三大數據類型。枚舉類型雖然是值類型,但是它還是具有很多面向對象的特征:
- 有構造方法,可以通過使用構造方法初始化。
- 可以定義computed屬性;
- 可以定義實例方法;
- 可以實現接口;
- 可以被擴展。
鑒于篇幅與內容的原因,具體的內容將會在之后的swift面向對象的各個專題中分別總結。下一篇文章將會總結元組類型,即:Swift3知識梳理(二):元組類型。