在本教程中,您将学习如何处理Swift编程语言中的不同类型。您将学习如何在类型之间进行转换,并且还将介绍类型推断,这使您作为程序员的生活变得更加简单。
最后,您将学习元组,它可以存储多个类型的值。
入门
尝试把小数类型的值赋值给一个整数类型的变量:
var integer: Int = 100
var decimal: Double = 12.5
integer = decimal
Swift会抱怨:
Cannot assign value of type 'Double' to type 'Int'
有些编程语言(如php)并不严格,会自动转换。经验表明,这种自动转换是软件漏洞的根源,并且经常会损害性能。Swift阻止您将一种类型的值分配给另一种类型,这可以避免这些问题。
请记住,计算机依靠程序员告诉他们该做什么。
在Swift中,您需要转换类型,而不是简单地赋值:
var integer: Int = 100
var decimal: Double = 12.5
integer = Int(decimal)
现在,第三行的赋值告诉Swift,你想要从原始类型Double
转换为新类型Int
。
注意:在这种情况下,将十进制值分配给整数会导致精度损失:integer
变量最终会变成12
而不是12.5
。这就是标注类型的重要性。Swift希望确保您知道自己在做什么,并且可能会因执行强制类型转换而丢失数据。
混合类型的运算符
整数乘以小数的情况怎么办:
let hourlyRate: Double = 19.5
let hoursWorked: Int = 10
let totalCost: Double = hourlyRate * hoursWorked
如果这样做,您将得到一个错误:
Binary operator '*' cannot be applied to operands of type 'Double' and 'Int'
这是因为,在Swift中,您不能将*
运算符应用于两个不同的类型。此规则也适用于其他算术运算符。看起来可能令人惊讶,但这相当有帮助。
当你想要一个Int
乘以一个Double
,Swift需要你表明你的意思,因为结果只能是一种类型。你想要结果是一个 Int
,在执行乘法之前将Double
转换为 Int
?或者您希望结果是一个 Double
,在执行乘法之前将Int
转换为Double
?
在此示例中,您希望结果为一个 Double
。你不想要一个Int
,因为在这种情况下,Swift会将hourlyRate
常量转换为一个Int
来执行乘法,将向下取舍为19。
您需要告诉Swift您希望它将hoursWorked
常量视为一个 Double
:
let hourlyRate: Double = 19.5
let hoursWorked: Int = 10
let totalCost: Double = hourlyRate * Double(hoursWorked)
类型推断
每次你声明变量或常量时,它都需要标注一个类型:
let integer: Int = 42
let double: Double = 3.14159
你可能会问自己:“为什么我必须写的: Int
和: Double
,需要赋的值已经是一个Int
或一个Double
了”。
事实证明,Swift编译器也可以推断出这一点。它不需要你一直告诉它类型 - 它可以自己解决它。这就是类型推断。
因此,您可以在大多数地方不需要申明类型。例如:
let typeInferredInt = 42
有时,检查变量或常量的推断类型很有用。您可以通过按住Option键并单击变量或常量的名称。Xcode将弹出窗口:
类型推断让代码更简洁。
有时:
let wantADouble = 3
Swift推断出wantADouble
的类型是Int
。但如果你想要的是Double
呢?
可以这样:
let actuallyDouble = Double(3)
这是之前使用过的类型转换。
另一个选择:
let actuallyDouble: Double = 3
第三种选择:
let actuallyDouble = 3 as Double
as
关键字也可以类型转换。
注意:像3
这样的字面值一开始是没有类型的。只有在表达式中,或者将它们分配给常量或变量时,Swift才会为它们推断出类型,单独写一个3
的话,swift会推断为Int
所以如果想让swift直接类型推断为小数的话,直接这样:
let wantADouble = 3.0
字符串
字符串也是一种非常常见的数据类型,例如人名,地址。
接下来首先介绍字符串的概念,然后向您展示如何在Swift中使用它们。
计算机如何表示字符串
计算机将字符串视为单个字符的集合。无论使用何种编程语言,所有代码都可以简化为原始数字。字符串也不例外!
这可能听起来很奇怪。字符怎么可能是数字?在它的基础上,计算机需要能够将字符翻译成计算机自己懂的语言,并且通过为每个字符分配不同的数字来实现。这形成了从字符到数字的双向映射,称为字符集。
当您按键盘上的字符键时,实际上是将字符编号传送给计算机。您的文字处理器应用程序将该数字转换为角色的图片,最后将该图片呈现给您。
统一
计算机可以自由选择它喜欢的任何字符集映射(一对一的关系)。如果计算机希望字母a等于数字10,那就这样吧。但计算机之间相互通信时,他们需要使用一个共同的字符集。如果两台计算机使用不同的字符集,那么,当一台计算机将字符串传输到另一台计算机时,它们最终会认为是不同的字符串。
最现代的标准是Unicode。它定义了几乎所有计算机今天都使用的字符集映射。
注意:您可以在其官方网站http://unicode.org上阅读有关Unicode的更多信息。
如cafe一词。Unicode标准告诉您这个单词的字母应该映射到这样的数字:
与每个字符关联的数字称为代码点。因此,在上面的示例中,c使用代码点99,a使用代码点97,依此类推。
Unicode不仅适用于英语,它还允许您映射世界各地的语言字符。
这里有一个汉字的例子:
您可能已经听说过颜文字,它们是可以在文本中使用的小图片。事实上,这些图片只是普通字符,也是由Unicode映射的。例如:
注:“颜文字”一词来自日语:“e”表示图片,“moji”表示字符。
Swift中的字符串
像任何优秀的编程语言一样,Swift可以直接使用字符和字符串。它分别通过数据类型Character
和数据类型String
来实现。在本节中,您将了解这些数据类型以及如何使用它们。
字符和字符串
该Character
数据类型可以存储一个字符。例如:
let characterA: Character = "a"
这存储了字符a。它可以容纳任何字符 - 甚至是表情符号:
let characterDog: Character = ""
但是这种数据类型只能容纳单个字符。数据类型String
可以存储多个字符。例如:
let stringDog: String = "Dog"
这个表达式的右边被称为字符串字面量
当然,这里也可以用类型推断。
let stringDog = "Dog" // 类型推断为String
注意:如果要赋的值只有一个字符,Swift会推断为String
类型。如果要明确表示该值的类型是Character
,则必须显式申明类型为Character
。
字符串拼接
就是把字符串连在一起。使用加法运算符:
var message = "Hello" + " my name is "
let name = "Lebus"
message += name // "Hello my name is Lebus"
您需要声明message
为变量而不是常量,因为之后要修改它。
也可以拼接字符和字符串。但需要先把字符转化为字符串:
let exclamationMark: Character = "!"
message += String(exclamationMark) // "Hello my name is Lorenzo!"
插值
您还可以使用插值来构建字符串,这是一种特殊的Swift语法,可以让您以易于阅读的方式构建字符串:
let name = "Lebus"
let messageInOne = "Hello my name is \(name)!" // "Hello my name is Lebus!"
以上内容比上一节中的示例更具可读性。它是字符串文字语法的扩展,您可以使用其他值替换字符串的某些部分。将要包含的字符串括在括号中,前面加一个反斜杠。
多行字符串
Swift有一种简洁的方式来表达包含多行的字符串。当您需要在代码中放入一个非常长的字符串时,这将非常有用:
let bigString = """
You can have a string
that contains multiple
lines
by
doing this.
"""
print(bigString)
输出:
You can have a string
that contains multiple
lines
by
doing this.
请注意,字符串前的缩进空格没有被输出。Swift会看最后三个双引号行前面的空格数。用它作为基线。
元组
有时,一次要保存两个或多个数据。如:2D网格上的(x,y)坐标。类似地,3D网格上的一组坐标,由x值,y值和z值组成。
在Swift中,您可以使用元组表示此类数据。
元组是一种表示由多个任何类型的值组成的数据的类型。您可以根据需要在元组中包含尽可能多的值。例如,您可以定义一对2D坐标,其中每个轴值都是一个整数,如下所示:
let coordinates: (Int, Int) = (2, 3)
coordinates
的类型是包含两个Int
值的元组。在这种情况下,元组中值的类型Int
由括号括起来,用逗号分隔。创建元组的代码大致相同,每个值用逗号分隔并用括号括起来。
也可以用类型推断来推断元组类型:
let coordinatesInferred = (2, 3) // 推断类型为 (Int, Int)
也可以创建一个Double
值元组,如下所示:
let coordinatesDoubles = (2.1, 3.5) // 推断类型为 (Double, Double)
也可以混合:
let coordinatesMixed = (2.1, 3) // Inferred to be of type (Double, Int)
如何访问元组内的数据:
let coordinates = (2, 3)
let x1 = coordinates.0
let y1 = coordinates.1
您可以通过元组中的位置获取元组中的每个项目,从零开始。所以,在这个例子中,x1
等于2
,y1
等于3
。
注意:从零开始是计算机编程中的常见做法,称为zero index。
单纯的用index表示元祖中的某个元素并不太表意。
幸运的是,Swift允许您命名元组的各个部分,并且明确的说明每个部分代表什么。例如:
let coordinatesNamed = (x: 2, y: 3) // 推断类型为 (x: Int, y: Int)
当需要访问元组的每个部分时,可以:
let x2 = coordinatesNamed.x
let y2 = coordinatesNamed.y
这样更容易理解。
也可以一次性获取元祖中的所有值:
let coordinates3D = (x: 2, y: 3, z: 1)
let (x3, y3, z3) = coordinates3D
这声明三个新常量x3
,y3
并且z3
,元组把每个值一一分配给他们。代码等同于:
let coordinates3D = (x: 2, y: 3, z: 1)
let x3 = coordinates3D.x
let y3 = coordinates3D.y
let z3 = coordinates3D.z
如果要忽略元组的某个元素,可以用下划线替换。如,现在只做2D计算,想要忽略coordinates3D
的z坐标:
let (x4, y4, _) = coordinates3D
这行代码只声明x4
和y4
。_
是表示现在不需要这个值
注意:在Swift中经常使用下划线(也称为通配符操作符)来忽略一个值。
一大堆数字类型
我们到现在为止一直Int
类型表示整数。一个Int
在64位计算机占64bit,在32位中占32bit。Swift提供了更多使用不同存储量的整数类型。Int的signed类型:Int8
,Int16
,Int32
和Int64
。Int后面的数字代表位,也就是bit(计算机最小单位) 1byte=8bit,所以这些类型分别消耗1,2,4和8个字节(byte)的存储空间。
如果您只处理非负值,则可以使用Int的unsigned类型。UInt8
,UInt16
,UInt32
和UInt64
。允许存储的值是signed类型的两倍。
以下是不同整数类型可以存储的最大值,最小值,所占容量。大多数时候,我们只用Int
。
如果需用更精确与的其他软件进行交互,或者需要对存储大小进行优化,才会用到。
关于小数。Float
比Double
范围和精度要小,只占Double
一半的存储空间。现代计算机已经过优化Double
,所以推荐用Double
来表示小数。
假设需要将Int16
,UInt8
,Int32
类型的整数相加。可以这样:
let a: Int16 = 12
let b: UInt8 = 255
let c: Int32 = -100000
let answer = Int(a) + Int(b) + Int(c) // Answer is an Int