Swift傻傻分不清楚系列(二)数据类型
本页包含内容:
- 整数
- 整数范围
- Int
- UInt
- 浮点数
- 类型安全和类型推断
- 数值型字面量
- 数值型类型转换
- 整数转换
- 数整数和浮点数转换
- 类型别名
- 布尔值
整数
整数就是没有小数部分的数字,比如42
和-23
。整数可以是有符号
(正、负、零)或者无符号
(正、零)。
Swift 提供了8,16,32和64位的有符号和无符号整数类型。这些整数类型和 C 语言的命名方式很像,比如8位无符号整数类型是UInt8
,32位有符号整数类型是Int32
。就像 Swift 的其他类型一样,整数类型采用大写命名法。
整数范围
你可以访问不同整数类型的min
和max
属性来获取对应类型的最小值和最大值:
let minValue = UInt8.min // minValue 为 0,是 UInt8 类型
let maxValue = UInt8.max // maxValue 为 255,是 UInt8 类型
min
和max
所传回值的类型,正是其所对的整数类型(如上例UInt8, 所传回的类型是UInt8),可用在表达式中相同类型值旁。
Int
一般来说,你不需要专门指定整数的长度。Swift 提供了一个特殊的整数类型Int
,长度与当前平台的原生字长相同:
- 在32位平台上,
Int
和Int32
长度相同。 - 在64位平台上,
Int
和Int64
长度相同。
除非你需要特定长度的整数,一般来说使用Int
就够了。这可以提高代码一致性和可复用性。即使是在32位平台上,Int
可以存储的整数范围也可以达到-2,147,483,648
~2,147,483,647
,大多数时候这已经足够大了。
UInt
Swift 也提供了一个特殊的无符号类型UInt
,长度与当前平台的原生字长相同:
- 在32位平台上,
UInt
和UInt32
长度相同。 - 在64位平台上,
UInt
和UInt64
长度相同。
注意:
尽量不要使用UInt
,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况,最好使用Int
,即使你要存储的值已知是非负的。统一使用Int
可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推断,请参考类型安全和类型推断。
浮点数
浮点数是有小数部分的数字,比如3.14159
,0.1
和-273.15
。
浮点类型比整数类型表示的范围更大,可以存储比Int
类型更大或者更小的数字。Swift 提供了两种有符号浮点数类型:
Double
表示64位浮点数。当你需要存储很大或者很高精度的浮点数时请使用此类型。Float
表示32位浮点数。精度要求不高的话可以使用此类型。
注意:
Double
精确度很高,至少有15位数字,而Float
只有6位数字。选择哪个类型取决于你的代码需要处理的值的范围。
类型安全和类型推断
Swift 是一个类型安全(type safe)的语言。类型安全的语言可以让你清楚地知道代码要处理的值的类型。如果你的代码需要一个String
,你绝对不可能不小心传进去一个Int
。
由于 Swift 是类型安全的,所以它会在编译你的代码时进行类型检查(type checks),并把不匹配的类型标记为错误。这可以让你在开发的时候尽早发现并修复错误。
当你要处理不同类型的值时,类型检查可以帮你避免错误。然而,这并不是说你每次声明常量和变量的时候都需要显式指定类型。如果你没有显式指定类型,Swift 会使用类型推断(type inference)来选择合适的类型。有了类型推断,编译器可以在编译代码的时候自动推断出表达式的类型。原理很简单,只要检查你赋的值即可。
因为有类型推断,和 C 或者 Objective-C 比起来 Swift 很少需要声明类型。常量和变量虽然需要明确类型,但是大部分工作并不需要你自己来完成。
当你声明常量或者变量并赋初值的时候类型推断非常有用。当你在声明常量或者变量的时候赋给它们一个字面量(literal value 或 literal)即可触发类型推断。(字面量就是会直接出现在你代码中的值,比如42
和3.14159
。)
例如,如果你给一个新常量赋值42
并且没有标明类型,Swift 可以推断出常量类型是Int
,因为你给它赋的初始值看起来像一个整数:
let meaningOfLife = 42
// meaningOfLife 会被推测为 Int 类型
同理,如果你没有给浮点字面量标明类型,Swift 会推断你想要的是Double
:
let pi = 3.14159
// pi 会被推测为 Double 类型
当推断浮点数的类型时,Swift 总是会选择Double
而不是Float
。
如果表达式中同时出现了整数和浮点数,会被推断为Double
类型:
let anotherPi = 3 + 0.14159
// anotherPi 会被推测为 Double 类型
原始值3
没有显式声明类型,而表达式中出现了一个浮点字面量,所以表达式会被推断为Double
类型。
数值型字面量
整数字面量可以被写作:
- 一个十进制数,没有前缀
- 一个二进制数,前缀是
0b
- 一个八进制数,前缀是
0o
- 一个十六进制数,前缀是
0x
下面的所有整数字面量的十进制值都是17
:
let decimalInteger = 17
let binaryInteger = 0b10001 // 二进制的17
let octalInteger = 0o21 // 八进制的17
let hexadecimalInteger = 0x11 // 十六进制的17
浮点字面量可以是十进制(没有前缀)或者是十六进制(前缀是0x
)。小数点两边必须有至少一个十进制数字(或者是十六进制的数字)。十进制浮点数也可以有一个可选的指数(exponent),通过大写或者小写的 e
来指定;十六进制浮点数必须有一个指数,通过大写或者小写的 p
来指定。
如果一个十进制数的指数为exp
,那这个数相当于基数和10^exp的乘积:
1.25e2
表示 1.25 × 10^2,等于125.0
。1.25e-2
表示 1.25 × 10^-2,等于0.0125
。
如果一个十六进制数的指数为exp
,那这个数相当于基数和2^exp的乘积:
0xFp2
表示 15 × 2^2,等于60.0
。0xFp-2
表示 15 × 2^-2,等于3.75
。
下面的这些浮点字面量都等于十进制的12.1875
:
let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0
数值类字面量可以包括额外的格式来增强可读性。整数和浮点数都可以添加额外的零并且包含下划线,并不会影响字面量:
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
数值型类型转换
通常来讲,即使代码中的整数常量和变量已知非负,也请使用Int
类型。总是使用默认的整数类型可以保证你的整数常量和变量可以直接被复用并且可以匹配整数类字面量的类型推断。
只有在必要的时候才使用其他整数类型,比如要处理外部的长度明确的数据或者为了优化性能、内存占用等等。使用显式指定长度的类型可以及时发现值溢出并且可以暗示正在处理特殊数据。
整数转换
不同整数类型的变量和常量可以存储不同范围的数字。Int8
类型的常量或者变量可以存储的数字范围是-128
~127
,而UInt8
类型的常量或者变量能存储的数字范围是0
~255
。如果数字超出了常量或者变量可存储的范围,编译的时候会报错:
let cannotBeNegative: UInt8 = -1
// UInt8 类型不能存储负数,所以会报错
let tooBig: Int8 = Int8.max + 1
// Int8 类型不能存储超过最大值的数,所以会报错
由于每种整数类型都可以存储不同范围的值,所以你必须根据不同情况选择性使用数值型类型转换。这种选择性使用的方式,可以预防隐式转换的错误并让你的代码中的类型转换意图变得清晰。
要将一种数字类型转换成另一种,你要用当前值来初始化一个期望类型的新数字,这个数字的类型就是你的目标类型。在下面的例子中,常量twoThousand
是UInt16
类型,然而常量one
是UInt8
类型。它们不能直接相加,因为它们类型不同。所以要调用UInt16(one)
来创建一个新的UInt16
数字并用one
的值来初始化,然后使用这个新数字来计算:
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
现在两个数字的类型都是UInt16
,可以进行相加。目标常量twoThousandAndOne
的类型被推断为UInt16
,因为它是两个UInt16
值的和。
SomeType(ofInitialValue)
是调用 Swift 构造器并传入一个初始值的默认方法。在语言内部,UInt16
有一个构造器,可以接受一个UInt8
类型的值,所以这个构造器可以用现有的UInt8
来创建一个新的UInt16
。注意,你并不能传入任意类型的值,只能传入UInt16
内部有对应构造器的值。不过你可以扩展现有的类型来让它可以接收其他类型的值(包括自定义类型),请参考扩展。
整数和浮点数转换
整数和浮点数的转换必须显式指定类型:
let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
// pi 等于 3.14159,所以被推测为 Double 类型
这个例子中,常量three
的值被用来创建一个Double
类型的值,所以加号两边的数类型须相同。如果不进行转换,两者无法相加。
浮点数到整数的反向转换同样行,整数类型可以用Double
或者Float
类型来初始化:
let integerPi = Int(pi)
// integerPi 等于 3,所以被推测为 Int 类型
当用这种方式来初始化一个新的整数值时,浮点值会被截断。也就是说4.75
会变成4
,-3.9
会变成-3
。
注意:
结合数字类常量和变量不同于结合数字类字面量。字面量3
可以直接和字面量0.14159
相加,因为数字字面量本身没有明确的类型。它们的类型只在编译器需要求值的时候被推测。
类型别名
类型别名(type aliases)就是给现有类型定义另一个名字。你可以使用typealias
关键字来定义类型别名。
当你想要给现有类型起一个更有意义的名字时,类型别名非常有用。假设你正在处理特定长度的外部资源的数据:
typealias AudioSample = UInt16
定义了一个类型别名之后,你可以在任何使用原始名的地方使用别名:
var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound 现在是 0
本例中,AudioSample
被定义为UInt16
的一个别名。因为它是别名,AudioSample.min
实际上是UInt16.min
,所以会给maxAmplitudeFound
赋一个初值0
。
布尔值
Swift 有一个基本的布尔(Boolean)类型,叫做Bool
。布尔值指逻辑上的值,因为它们只能是真或者假。Swift 有两个布尔常量,true
和false
:
let orangesAreOrange = true
let turnipsAreDelicious = false
orangesAreOrange
和turnipsAreDelicious
的类型会被推断为Bool
,因为它们的初值是布尔字面量。就像之前提到的Int
和Double
一样,如果你创建变量的时候给它们赋值true
或者false
,那你不需要将常量或者变量声明为Bool
类型。初始化常量或者变量的时候如果所赋的值类型已知,就可以触发类型推断,这让 Swift 代码更加简洁并且可读性更高。
当你编写条件语句比如if
语句的时候,布尔值非常有用:
if turnipsAreDelicious {print("Mmm, tasty turnips!")
} else {print("Eww, turnips are horrible.")
}
// 输出 "Eww, turnips are horrible."
条件语句,例如if
,请参考控制流。
如果你在需要使用Bool
类型的地方使用了非布尔值,Swift 的类型安全机制会报错。下面的例子会报告一个编译时错误:
let i = 1
if i {// 这个例子不会通过编译,会报错
}
然而,下面的例子是合法的:
let i = 1
if i == 1 {// 这个例子会编译成功
}
i == 1
的比较结果是Bool
类型,所以第二个例子可以通过类型检查。类似i == 1
这样的比较,请参考基本操作符。
和 Swift 中的其他类型安全的例子一样,这个方法可以避免错误并保证这块代码的意图总是清晰的。
Swift傻傻分不清楚系列(二)数据类型相关推荐
- MySQL不同数据类型如何表示_MySQL系列(二)--数据类型
如何选择优化的数据类型: 当一个列有多种数据类型可以选择,选择顺序:数字类型.日期/二进制类型.字符类型,相同级别的数据类型,优先选择占用空间小的类型 1.通常更小的更好 相同级别的数据类型,选择占据 ...
- 数据库分库分表(sharding)系列(三) 关于使用框架还是自主开发以及sharding实现层面的考量...
当团队对系统业务和数据库进行了细致的梳理,确定了切分方案后,接下来的问题就是如何去实现切分方案了,目前在sharding方面有不少的开源框架和产 品可供参考,同时很多团队也会选择自主开发实现,而不管是 ...
- 数据库分库分表(sharding)系列(五) 一种支持自由规划无须数据迁移和修改路由代码的Sharding扩容方案...
为什么80%的码农都做不了架构师?>>> 版权声明:本文由本人撰写并发表于2012年9月份的<程序员>杂志,原文题目<一种支持自由规划的Sharding扩容方 ...
- 数据库分库分表(sharding)系列(四) 多数据源的事务处理
系统经sharding改造之后,原来单一的数据库会演变成多个数据库,如何确保多数据源同时操作的原子性和一致性是不得不考虑的一个问题.总体上看,目前对于一个分布式系统的事务处理有三种方式:分布式事务.基 ...
- 红米k30 android版本,红米K30系列机型众多,傻傻分不清楚?看完这篇你就懂了
红米K30系列机型众多,傻傻分不清楚?看完这篇你就懂了 2020-10-01 10:51:57 18点赞 33收藏 11评论 红米K30系列 不可否认的是,目前的手机厂商喜欢一次性发布几款新机型,以不 ...
- 云计算、大数据、人工智能傻傻分不清楚?本文详解这三者的关系
云计算.大数据.人工智能傻傻分不清楚?本文详解这三者的关系 提示: 今天跟大家讲讲云计算.大数据和人工智能.这三个词现在非常火,并且它们之间好像互相有关系. 一般谈云计算的时候会提到大数据.谈人工智能 ...
- (转)CPU/GPU/TPU/NPU傻傻分不清楚
刚开始接触深度学习概念时,基本大多数时候也就提到GPU,也基本是用GPU来进行深度学习算法训练或部署人脸识别系统的. 近几年,随着人工智能(尤其是人脸识别)的爆炸式发展,诞生了许多新的东西,其中这芯片 ...
- JS魔法堂:属性、特性,傻傻分不清楚
一.前言 或许你和我一样都曾经被下面的代码所困扰 var el = document.getElementById('dummy'); el.hello = "test"; con ...
- ASP.NET MVC涉及到的5个同步与异步,你是否傻傻分不清楚?[下篇]
关于ASP.NET MVC对请求的处理方式(同步或者异步)涉及到的五个组件,在<上篇>中我们谈了三个(MvcHandler.Controller和ActionInvoker),现在我们来谈 ...
最新文章
- 一句话反弹shell
- [转]为什么我们不用软件工程?软件工程能帮多大忙?
- mysql group where_[MySQL] 测试where group by order by的索引问题
- eclipse php xdebug,Eclipse for php + Xdebug搭建PHP的调试环境
- wordpress html页面缓存 cdn,WordPress 下老旧又高效的本地缓存插件 cos-html-cache
- senchaTouch 给组件传参的两种方式
- 内存条和SSD都要涨价了!日韩贸易战将引起NAND与DRAM双涨效应
- 对POSIX和SystemV消息队列优化:用户态消息队列
- 【转】常见面试之机器学习算法思想简单梳理
- 编译型语言VS解释型语言、动态语言、静态语言
- Mysql DBA 高级运维学习之路-DML语句之insert知识讲解
- Matlab多种群遗传算法
- c语言程序怎样输出一个图形,用c语言如何输出并显示一个序列图形
- 通往互联网架构师之路---全栈工程师
- 名企招聘面试考题集锦
- 电脑上复制、粘贴及剪切功能用不了是什么原因
- java-net-php-python-16jspm望奎县城郊所考勤系统计算机毕业设计程序
- 微信分享链接含敏感词被屏蔽的问题
- Oracle 闪回特性(FLASHBACK DROP RECYCLEBIN)
- 事件传播机制/事件委托/事件代理
热门文章
- springboot2.x 与 elasticsearch2.4.x整合出错:None of the configured nodes are available
- 这可能是关于Pytorch底层算子扩展最详细的总结了!
- 嵌入式基础之----C++
- [二叉树]序列化二叉树 (剑指offer61)
- 如何从零开始开发一款嵌入式产品(20年的嵌入式经验分享学习,来自STM32神舟系列开发板设计师的总结)
- 机器学习笔试面试超详细总结(四)
- TensorFlow(二)函数基础
- docker安装ubuntu镜像
- 网上看的几点人生建议
- 鹤峰:美丽的茶乡—— 舞狮篇