![Flutter从0基础到App上线](https://wfqqreader-1252317822.image.myqcloud.com/cover/259/33831259/b_33831259.jpg)
3.3 基本数据类型
在Dart中,有几种内置的数据类型:数值型、字符串、布尔、集合、键值对等。
3.3.1 数值型
Dart的数值包含Int和Double两种类型,分别表示整数和小数。
Int:用于表示整数的int类型,长度为64位,因此,可以表示的数值范围是-263~263-1。编译为JavaScript语言的Dart使用JavaScript的数值范围-253~253-1。
Double:用于表示小数的double类型,提供长度为64位的双精度,其范围是-1.7E308~1.7E308。
从Dart 2.1版本开始,如果声明是double类型的变量,而值却是一个整数,那么这个变量就会自动转换成double类型(在Dart 2.1之前的版本中,这样的写法将会报错)。比如:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_19.jpg?sign=1738938242-llVA89pHgTdkVTnobke581lk0pbYCxem-0-971b9a48a12c05ca7aee9314c7dc2ca5)
输出结果:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_20.jpg?sign=1738938242-CoUcgpeM5Ixpr8LmsncK8JQnxOm4HkqQ-0-f1f958a5303004e243c3e9485a630d96)
由此可见,之前作为int类型的值(1)自动转换成了double类型的值。
3.3.2 字符串
Dart中的字符串表示一个由多个字符组成的序列,采用UTF-16编码。在声明字符串时,可以用单引号也可以用双引号,但要注意其中的区别。示例如下:
使用单引号声明的字符串:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_21.jpg?sign=1738938242-F2zN1q02GIggB2ECH7v7QzfI1OBy1qIc-0-b1cc26cba4c2e1d128a50495fbadae9a)
使用双引号声明的字符串:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_22.jpg?sign=1738938242-QRd8Wizj3m8BpxcB96MLvLCdjiM8lYMM-0-60723195ae2dfb5da074208e0b64fc5d)
你可能会发现,在使用单引号声明的字符串中,有一个反斜杠(\),这个反斜杠称为转义字符。其目的是区分字符串中的单引号是作为值的内容存在的,而不是代表字符串值的结束。类似地,如果使用双引号来声明字符串,当字符串值中包含双引号时,也要在双引号前加反斜杠,意思是这个双引号是其值的一部分,而非意味着字符串的结束。
接下来,想象这样一个真实情况。当用户成功登录后,给出一条欢迎信息,如“张先生,欢迎您的使用”。在这里,无论是哪位用户登录系统,后面的欢迎词都不变,变的只是前面的称呼。对于这样的情况,可以使用类似于下面的代码片段简化代码量,提取不变的部分:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_23.jpg?sign=1738938242-B8DXRbNPzySPYsTy4e3JvZPzTlM5oYJl-0-7b0a2221837da87798b9f181b01e2375)
输出结果如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_24.jpg?sign=1738938242-IGt4hjhlv9X8xrneJve8jlc0Se7xKnnH-0-2367c8ec0ba227c0c31391c77d0bc699)
在这段代码中,使用了{表达式}。如果表达式是一个变量,则可省略大括号来插入另一个变量值,最后组成一句话。在这段代码中,welcome变量的值是不变的,可以将其声明为final。
当然,对于上例,也可以使用加号(+)联结它们,具体写法如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_25.jpg?sign=1738938242-rggUDqfGtXjRqAmn7Y4QizZ2fLP7oBCE-0-f46eabec2b1ed54ac82208e3805ed1de)
输出结果相同。
要想判断两个字符串(或其他对象)的内容是否完全一致,可以使用连等号(==),如下例所示:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_26.jpg?sign=1738938242-PdYMSQI9saHfCMqtgl3SS7RiU5T0TOX7-0-e33ed079d72acdfc878ac19e30f1622e)
输出结果如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_27.jpg?sign=1738938242-EfKg5Zlq7odwezBfbe6LuXhquNuJZ9Le-0-0b0f4fc8d55b36190a502337d404a4f5)
接下来看下面这段代码:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_28.jpg?sign=1738938242-1QLZoCUbYoC4F5MA4772T8wmzAWumPHo-0-06dd3864363f7159c98eb90adbd30fe3)
其中,“\n”是换行符。想象一下,如果几十道菜的菜单这样延续下去,可读性就非常差。因此,我们可以使用三个单引号或三个双引号将上面的变量声明改为如下所示:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_29.jpg?sign=1738938242-ynzvM0i60bAWqLnSpGNnjSc76gOxJQ0c-0-4464df0cfe8ffc48c5098fad1ec68b24)
这样的代码更易读、整洁,而且也不需要再手动添加换行符,引号内的所有内容将以原样输出。然后使用print()方法在控制台输出longStr的值,将得到如下结果:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_30.jpg?sign=1738938242-hSAoEQrJL1lE6ucXUKeGOugu7OVNGY8S-0-e4826e8117fc807d2691e6fc0f96e22e)
在某些特定的情况下,我们还需要在数字和字符串之间进行转换。比如,一个字符串的内容是1000,如果想得到其乘以5的结果,由于字符串是无法直接参与算术运算的,所以就需要先将其转换为int类型。代码片段如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_31.jpg?sign=1738938242-CdUwXrU8tiaafG6C3AZOx1khFjS99pEM-0-947e0b79b4e95efd532117813fc8019b)
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_32.jpg?sign=1738938242-lsTRJrST7lOobuKcnLNSfnNOAmgss2vA-0-d5f9d9f48725036394e0f0f72cdca200)
输出结果如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_33.jpg?sign=1738938242-25my3pEOmqVO1Bomr1cw27DIjnE2tIt3-0-c6f9b91cf4b06e9aa23e9fcd227258ae)
int类型转换为String类型,代码如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_34.jpg?sign=1738938242-NFj2QFq2A2cNJrKquxXt5jQwkVRbhUSz-0-c66d5f06d09139099324f09c09fe9239)
输出结果如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_35.jpg?sign=1738938242-4pQOEORcBsETzXrmKS3GqYe3U0YwkNwZ-0-7f2550d003f1e57fb1798f2c4e38d6ff)
注意,虽然输出的结果看上去一样,但类型不同。类似地,对于double类型的转换也可采用同样的方式。
字符串值和带有一个或多个表达式插值的字符串都属于编译时常量。
3.3.3 布尔
布尔类型有两个结果值:true和false,用于表示真和假或作为条件判断的依据,可以使用var声明,也可以使用bool,如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_36.jpg?sign=1738938242-mkP8EpCXjlSBBP5BoSbnHLPZzAdwzBcx-0-90eae184bb68297bb3eb626e1645c741)
输出结果如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_37.jpg?sign=1738938242-3uD2svhzbSKDA4rhGNROgSOyZxogjxmR-0-e37f607e5ae9a3a20efe34dc57e7a211)
3.3.4 集合
Dart 2.0版本提供了三种核心集合类型,分别是列表(List)对象、集合(Set)对象和映射(Map)对象。
1.列表对象
在Dart中,使用数组表示列表对象。可以像如下所示,声明一个列表对象:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_38.jpg?sign=1738938242-38docB7PiIiQz9Xzyd0FJlM9gJhb6YAs-0-041eba5b7dab7178dd15a00ef7eee007)
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_39.jpg?sign=1738938242-909Q7a7syGz76yFJ1Nb9woN7GG5oBfEg-0-0dc9daba5ba50b80ccb70207284cc888)
当然,也可以用列表来声明。列表中的元素可以包含其他类型,如double类型和String类型,甚至可以将它们混合使用,如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_40.jpg?sign=1738938242-lXgGWxwEcNwiJIaxanpKNxZhECw8AJ6a-0-28a023f5c85a680d642d0d40b9c55264)
输出结果如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_41.jpg?sign=1738938242-2CvS2EFT9WKojRGzcleszTh6wE4XtKPn-0-32e6fffc27cbebbcc43b1450bfe17aac)
此外,与其他的编程语言类似,Dart中的列表也支持获取长度,即元素个数。调用length()方法即可获取某个列表的元素个数,如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_42.jpg?sign=1738938242-EQtFQKCM5Q7LewDTmUyvE2ZPOR3jerBB-0-d8a021b81e517175ebb3f4543e8d1b0e)
其中,listExp变量是上面例子中的列表对象。
运行代码片段结果如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_43.jpg?sign=1738938242-IZm4E8SOxTknLUiPx1P5LTDACy7syppw-0-ad54c3dfc34dcad8b1a789a5e3dda87e)
列表中的元素索引下标从0开始到list.length-1结束,总长度是list.length。如果要取出第2个元素,对上例而言,就应写成listExp[1]。
为什么要使用这样的方法获取长度呢?通常来讲,当需要遍历某个列表中的所有对象时,会使用列表的长度作为重要的结束依据。换言之,取出列表中的每个元素需要进行遍历,到最后一个元素结束遍历。如果这个列表的长度可能发生改变,就不能把长度写成一个定值。而在上例中,获取到的长度却总是正确的,从而保证了代码逻辑既不会落下该遍历的元素,又不会产生下标越界的错误。
2.集合对象
集合对象是Dart编程语言中的第二种集合类型,和t列表对象不同,它没有顺序且不允许重复。声明集合对象很简单,如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_44.jpg?sign=1738938242-GO1kATNCba2h7RlddrgFsP7yAehKVdyC-0-d9a8ffd0f936bb8f00929e5629c024b6)
和列表对象类似,我们也可以使用集合来声明集合对象,并且也支持不同类型的混合使用,代码片段如下所示:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_45.jpg?sign=1738938242-r5A2ztKhM3x7Lg0ZVWe6mhsTOuhSDvYB-0-c485860810f0d455133c5e3ed5426f5a)
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_46.jpg?sign=1738938242-auTYRCfvaNiFSfqdqC5g0GjJ3pY2axEJ-0-9a080b02ffd5f907d2a37df432462074)
输出结果如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_47.jpg?sign=1738938242-klxp9Xh5ArubYJDZp9UK5Wf5SU9Vu1MO-0-7f660fcc93e0f2af80c967565723751b)
从输出结果来看,似乎集合是有序的,但实际上,其内部是无序的,而且也不能像列表对象那样通过下标来取值;但是集合仍能通过set.length()方法获取集合大小,即元素个数。
除此之外,集合还提供了add(),remove(),contains(),clear()等方法。
add()方法为动态添加元素提供了方便。通过add()方法可以随时向集合对象中添加元素。当然,由于集合本身不具有包含重复对象的特性,因此添加一个重复的元素将是无效的代码片段,如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_48.jpg?sign=1738938242-zTXPpCInvEzwCWxrGmrBRPhJLh1mLzcl-0-124931459d86e7769191b80193370e71)
运行结果如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_49.jpg?sign=1738938242-yQG2PI9fzf01pA2rIvrlTytoyoT1E7BZ-0-065945b063c2cc03f8b7db1f3530fd04)
其中,Elan作为新添加的值被追加到名为setExp的集合对象中,而setExp已经含有Bob,因此新添加的Bob无效。
remove()方法提供了删除某个元素的功能,现在将Bob从集合中删除,参考下面的代码:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_50.jpg?sign=1738938242-idbkaaK6WBb46skK1t5zrIKKw90EsFa8-0-96a6c034854b9796666d018e50f7f677)
运行结果如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_51.jpg?sign=1738938242-cXJfHIJ7MWVuwY5ZsWldx4HYBAmToSNs-0-7c7f961fd988b0794a338cca2985dd51)
可以看到,Bob已经从集合中移除了。
那么,我们怎么来确定集合中是否已经包含了某个元素呢?这时,就要用到contains()方法了。现在,分别测试Alice和Fiona是否包含在集合中,具体代码如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_52.jpg?sign=1738938242-bzRB0VOlBi2t6hfRShnUfZ98jZv67lt0-0-32d16f5bf1616e262ae8411caf55da25)
输出结果:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_53.jpg?sign=1738938242-PFZxF7WDfQ5k2Ps9jXHkdnIs7dSsedxo-0-95b1c532400879e3589e8c179c380919)
由此可见,Alice在集合中,Fiona不在集合中。
如果我们想一次性清空整个集合,就可以调用clear()方法。彻底清空setExp集合,如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_54.jpg?sign=1738938242-1L1SI9L9fzyLH8CXqX04ILIT378KcclG-0-70929b5db5a96a7339f3999fa8d46f47)
运行结果:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_55.jpg?sign=1738938242-djrAhFfGs9SsQjssFXwMyziM9dHjkmcU-0-d7d580b24c6ffb0efe42e8e2243743f3)
到此,整个集合被清空了。
实际上,集合对象提供的实用和方便的方法还有很多。比如,一次性追加多个元素可以使用addAll()方法;类似地,还有removeAll()方法和containsAll()方法等。在实际开发中,这些方法提供了很多便利,掌握并灵活运用它们,可以提高开发效率。
3.映射对象
通常意义上讲,映射对象由一个或多个key(键)- value(值)对组成,每个键值对是一个元素,键和值可分别为任意类型。其中,相同的键在映射对象中不支持重复,相同的值可以和不同的键对应。比如,我们要送新年礼物给每个人,代码片段如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_56.jpg?sign=1738938242-JOcY8CFk5bL6KVsqZITLq0Ck2HM6litZ-0-6f881dc841f4464ff33ef0638805c34c)
运行结果:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_57.jpg?sign=1738938242-aEiaqzUHso6n7BO7GqupkYMN1XvZ9UkL-0-c8ad72d1f34dc53e87e54753a2ad0d81)
在上面的代码中,冒号左侧是键,右侧是值。而左侧的人(键)是不会重复的,右侧的礼物(值)是可以重复的。因为前文限定了每个人只能有一件礼物,也就意味着,一旦决定送给某人某件礼物,如果他想得到其他的,就只能用另一件礼物来替代。代码如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_58.jpg?sign=1738938242-iKFBfOvt0gcbvEmbCfmUAFHh82fmkLNv-0-9474a770c42fc6480373fd4ba774ac19)
运行结果:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_59.jpg?sign=1738938242-bdx83IwihxN02lMa19Gqx3JEYbCnh4bH-0-61edae38280680916cd2953ee5bb531a)
因此,童童得到了乐高玩具,不再是精装书。这里要特别注意,在修改某个键对应的值时,务必要把键写对。上例代码如果写成如下所示:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_60.jpg?sign=1738938242-1khP6ROm7dXWhIfMXA7s2hyYUjiXQydk-0-19d09e53c646aaad29f031600a358682)
运行结果:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_61.jpg?sign=1738938242-zVkwagC8witntinCKjFaYytXLjIsv0kS-0-8c6e51139ff244778fe1c4d47668ed52)
可见,童童依然会得到精装书,而乐高玩具送给了彤彤。除此之外,如果想要知道送给某人的礼物是什么,也可以凭借键去获取,代码如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_62.jpg?sign=1738938242-jIDcaPMSLucXN1BmJRPiRy4sSqneDtWV-0-6ad66863364f9e96e1bd465eb198237d)
运行结果:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_63.jpg?sign=1738938242-Ro4BNNNtpuWQ7qqgnF8j6dOy2qLKVgiL-0-1f545e2d555b830e9e83a48c6775a934)
和集合对象类似,要想删除某个元素可使用remove()方法,只是要用键来删除。再回到这个案例中,删掉刚刚错误添加进去的彤彤,操作如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_64.jpg?sign=1738938242-fvIYRxTrekIVWN5yNtWWexYZMh9RCtEB-0-0f406171a1b50ae12ac37ef92f7cde1c)
运行结果:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_65.jpg?sign=1738938242-hXcSBnlyNJAqjdU9NAGb6jjXXYFpxS6y-0-b3520f18d30cc067a096753ca9d58589)
到此,由于失误添加进去的彤彤已被移除。那么,能不能避免这种加入新人的错误呢?
答案是肯定的。我们在对某个键值操作前,可以先判断这个键是否存在。比如,先判断一下有没有彤彤这个人,如果有,再进行操作;如果没有,就是找错人了。这样一来,就成功地避免了出现的失误。具体代码如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_66.jpg?sign=1738938242-x7ydtKSzfWr5NEyGBQd2aP9ymP8lY2Af-0-875b1236a2bffb4a33eb7f2f8d218bf9)
运行结果:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_67.jpg?sign=1738938242-bYLzKjinYfieC0o2b0iGVMTNIxZsvQhS-0-85ef0e41dc7da04af716b8a1f8c02241)
和列表、集合类似,映射同样支持使用length()方法获取整个映射对象的长度,即元素个数。
3.3.5 UTF-32编码表示法
前面提到在Dart中字符串是UTF-16编码的,那么对于超过16位编码的情况怎么处理呢?此时,就要借助Runes类型,利用它可以处理高达32位Unicode编码的字符串。在一般情况下,要表示一个32位Unicode字符,写法是“\uXXXX”,其中X代表一个十六进制数。比如,要输出一个心形(♥)的图案,可以参照如下的写法:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_68.jpg?sign=1738938242-6Ero7sNG68JOhUKlUSlNkYo1RIv8K0cO-0-d4b92905482a49b9f29cdf709ca27429)
运行结果:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_69.jpg?sign=1738938242-R2PVEzEBYiMTKili3UfyJh3NG4qytKH0-0-10482e237c991e5cf5be59ad0a66ff12)
除此之外,还有一些特殊的不是4个数字的情况,就需要使用大括号将数字部分括起来。比如要输出一个表情:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_70.jpg?sign=1738938242-COOcfb7Qj95ycmZ4qc0TDCpK7cXnXzpO-0-3dd78a9ca6ca499f5e0a913ac11806bc)
运行结果:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt003_71.jpg?sign=1738938242-PVt7Wrr4eNkgVP8IY9mQo0v5wGlJNZ1g-0-a5fdca5638c46517a953e13f365af741)
由此可见,我们可以简单地使用var来声明,也可以使用Runes来创建Runes对象,然后输出结果。