系统化掌握Dart编程之数据类型

619 阅读7分钟

image.png

前言

数据——编程的核心驱动力

在编程中,数据是一切的基础。无论是构建简单的计算器应用,还是复杂的大型应用,数据都如同血液般贯穿整个程序的运行和逻辑处理。理解数据的本质、如何管理数据以及如何有效地操作数据,是每个编程者必须掌握的核心技能

数据是什么

简单说来,数据信息的载体,它可以是多种形式:

  • 数字:如用户的年龄、商品的价格。
  • 文本:如用户名、产品描述。
  • 图像和视频:如用户上传的照片、录制的视频。
  • 结构化或非结构化信息:如数据库记录、社交媒体帖子。

数据为什么如此重要

  • 驱动业务逻辑:应用程序根据数据做出决策,如电商平台根据库存调整商品可用性。
  • 提升用户体验:个性化推荐系统基于用户行为数据提供定制化的服务。
  • 支持分析和决策:数据分析帮助企业和开发者优化产品、改进服务。

数据的管理和操作

有效的数据管理确保了数据的准确性完整性安全性。而高效的数据操作则让程序能够快速响应用户需求,提供流畅的交互体验。通过选择合适的数据类型,设计合理的数据结构,并编写高效的算法,我们可以构建出性能优越且可靠的软件系统。

探索数据的世界

接下来,我们将深入探讨不同类型的数据它们的表示方法及如何在编程中有效管理和操作这些数据。无论你是初学者还是有经验的开发者,掌握数据的奥秘都将为你打开通往高效编程的大门。

千曲而后晓声,观千剑而后识器。虐它千百遍方能通晓其真意

一、基本数据类型

1.1、数字类型

1.1.1、数值类型(num)

Dart中,num是一个抽象类,用于表示数值类型。它有两个具体的子类:intdouble。分别用于表示整数浮点数num提供了许多有用的属性方法,使得数值操作更加方便灵活

void main() {
  num a = 42;        // 实际上是 int 类型
  num b = 3.14;      // 实际上是 double 类型
  print(a.runtimeType); // 输出: int
  print(b.runtimeType); // 输出: double
}
  • 1、基本运算
    • 整除取模
void main() {
 num a = 42;
 num b = 3.14;
 print(a.compareTo(b)); // 输出: 1
 print((-5).isNegative); // 输出: true
 print(4.isEven);       // 输出: true
 print(7.isOdd);        // 输出: true
}
  • 2、数值转换
    • toDouble():将数值转换为double类型
    • toInt():将数值转换为int类型
void main() {
  num a = 42;
  num b = 3.14;
  print(a.toDouble()); // 输出: 42.0
  print(b.toInt());    // 输出: 3
}
  • 3、比较和检查
    • compareTo(num other):比较两个数值,返回-101
    • isNegative:判断数值是否为负数
    • isEvenisOdd:判断整数是否为偶数奇数(仅使用于int)。
void main() {
  num a = 42;
  num b = 3.14;
  print(a.compareTo(b)); // 输出: 1
  print((-5).isNegative); // 输出: true
  print(4.isEven);       // 输出: true
  print(7.isOdd);        // 输出: true
}
  • 4、数值范围
    • abs():求绝对值。
    • clamp(num lowerLimit, num upperLimit):将数值限制在指定范围内。
void main() {
  num a = -10;
  num b = 15;
  print(a.abs()); // 输出: 10
  print(b.clamp(0, 10)); // 输出: 10
}
  • 5、数学函数
    • ceil():向上取整。
    • floor():向下取整。
    • round():四舍五入。
    • truncate():截断小数部分。
void main() {
  num a = 3.7;
  print(a.ceil());    // 输出: 4
  print(a.floor());   // 输出: 3
  print(a.round());   // 输出: 4
  print(a.truncate()); // 输出: 3
}
  • 6、精度问题
    • 由于 double 使用 IEEE 754 标准进行浮点数表示,某些情况下可能会出现精度丢失的问题。
    • 为了处理这种情况,可以使用 double.parse 或者第三方库来提高精度。
void main() {
  num a = 0.1 + 0.2;
  print(a); // 输出: 0.30000000000000004
}
  • 7、特殊数值
    • Dart支持一些特殊的数值,如正负零无穷大NaN非数字)。
void main() {
  print(-0.0 == 0.0); // 输出: true
  print(double.infinity); // 输出: Infinity
  print(double.negativeInfinity); // 输出: -Infinity
  print(double.nan); // 输出: NaN
}
  • 8、最佳实践
    • 类型安全:尽量使用具体的 intdouble 类型,而不是泛用 num,以提高代码的类型安全性。
    • 避免隐式转换:在混合使用 intdouble 时,明确地进行类型转换,以避免潜在的错误。
    • 处理精度问题:对于需要高精度的计算,考虑使用第三方库或手动处理浮点数精度问题。

1.1.2、 整数类型(int)

image.png

上帝创造了整数,其余都是人类的工作。—— Leopold Kronecker

int类由abstract final共同修饰,意味着不能定义int的子类,也不能用另一个类实现int。这些限制是一种妥协,以牺牲继承或实现为代价来实现高性能

int 用于表示整数值,如 42-7

  • 1、取值范围
    • 32 位平台上支持 32有符号整数-2^31 ~ 2^31 - 1),即-2,147,483,648 ~ 2,147,483,647之间的值。
    • 64 位平台上支持 64有符号整数-2^63 ~ 2^63 - 1),即-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807之间的值。
void main() {
  int a = 42;
  print(a); // 输出: 42
  // 边界值示例
  print(int.minValue); // 输出: -9223372036854775808 (64 位平台)
  print(int.maxValue); // 输出: 9223372036854775807 (64 位平台)
}
  • 2、常用方法和num提供的方法类似
  • 3、大整数支持
    • 支持大整数(BigInt),可以表示任意大小的整数。使用 BigInt 可以避免超出 int 范围的问题。
import 'dart:math';
void main() {
  BigInt bigInt = BigInt.parse('123456789012345678901234567890');
  print(bigInt); // 输出: 123456789012345678901234567890
}
  • 4、随机数生成:通过 Random 类可以轻松实现随机数生成
import 'dart:math';
void main() {
  Random random = Random();
  int randomNumber = random.nextInt(100); // 生成 0 到 99 之间的随机整数
  print(randomNumber);
}

1.1.3、 浮点数类型(double)

image.png

double类由abstract final共同修饰,意味着不能定义double的子类,也不能用另一个类实现double。这些限制是一种妥协,以牺牲继承或实现为代价来实现高性能

double 用于表示双精度浮点数,如 double pi = 3.1415926;

  • 1、取值范围double可以表示非常大或非常小的数值,包括正负无穷大以及 NaN非数字)。
void main() {
  double a = 3.14;
  print(a); // 输出: 3.14
  // 特殊值示例
  print(double.infinity); // 输出: Infinity
  print(double.negativeInfinity); // 输出: -Infinity
  print(double.nan); // 输出: NaN
}
  • 2、常用方法和num提供的方法类似
  • 3、精度问题
    • 由于 double 使用 IEEE 754 标准进行浮点数表示,某些情况下可能会出现精度丢失的问题。
    • 为了处理这种情况,可以使用 double.parse或者第三方库如 decimal来提高精度。
void main() {
  double a = 0.1 + 0.2;
  print(a); // 输出: 0.30000000000000004
  // 使用 dart:math 库中的功能来处理精度问题
  import 'dart:math';
  print((a * 10).round() / 10); // 输出: 0.3
}
  • 4、随机数生成:通过 Random 类可以轻松实现随机数生成
import 'dart:math';
void main() {
  Random random = Random();
  double randomNumber = random.nextDouble(); // 生成 0.0 到 1.0 之间的随机浮点数
  print(randomNumber);
}

1.2、字符串类型(String

  • 表示文本序列,它是UTF-16编码的字符序列。
  • 字符串可使用单引号双引号定义,支持多行字符串字符串插值
  • 字符串在Dart中是不可变的,一旦创建,其内容不能被更改

示例代码

// 1.多行字符串
String multiLine = '''
  这是一个
  多行字符串
''';
 //2.字符串插值
String greeting = 'Hello, ${name}!';

1.3、布尔类型

  • 表示布尔值,只有两个可能的值:truefalse
  • 示例:bool isStudent = true;

1.4、动态类型(dynamic

  • 表示任何类型的变量编译器不会进行类型检查
  • 可在运行时存储任何类型的值,但是会失去类型安全性的优势。
  • 使用 dynamic 可能会导致运行时错误,应谨慎使用
  • 示例:dynamic value = 42; value = "hello";

二、集合类型(Collections

2.1、列表(List

  • 有序集合,允许重复元素。
  • 列表可以是固定长度或可变长度,支持多种操作如添加、删除、查找等。

示例代码

List<int> numbers = [1, 2, 3];
List<String> names = ['Alice', 'Bob'];

2.2、集合(Set

  • 无序集合,不允许重复元素。
  • 集合提供了高效的成员检测和交集、并集等操作。

示例代码

Set<int> uniqueNumbers = {1, 2, 3, 2}; // 结果为 {1, 2, 3}

2.3、映射(Map

  • 键值对集合。
  • 映射中的键必须唯一,可通过键访问对应的值。

示例代码

Map<String, int> ages = {'Alice': 30, 'Bob': 25};

三、特殊类型

3.1、函数类型(Function)

Dart 中,函数本身也是一种类型,称为函数类型。理解函数类型对于编写灵活类型安全的代码至关重要。

  • 1、定义函数类型描述了一个函数的签名,包括返回类型参数列表。它允许在定义变量参数返回值时明确指定函数的结构。
// 定义一个函数类型  其返回值类型为int型  无返回值是为void
typedef Operation = int Function(int a, int b);

int sum(int a, int b){
  return a + b;
}

void main() {
// 使用add来指代sum函数
  Operation add = sum;
  print(add(3, 4)); // 输出: 7
}
  • 2、基本语法:使用 typedef 关键字来为复杂的函数类型创建别名,使代码更简洁。
//语法结构
typedef Comparator<T> = int Function(T a, T b);

3.2、枚举类型(enum

  • 定义一组命名的常量。
  • 枚举提供了一种安全的方式定义有限集合的常量。

示例代码

enum Color { red, green, blue }
Color myColor = Color.red;
print(myColor); // 输出: Color.red

3.3、符号类型(Symbol

  • 表示Dart代码中的标识符。
  • 主要用于反射(reflection)和元编程。

示例代码

Symbol symbol = #myVariable;
print(symbol); // 输出: Symbol('myVariable')

3.4、类型别名(Typedefs

  • 用于定义类型别名。

示例代码

typedef IntCallback = void Function(int);

void process(IntCallback callback) {
  callback(42);
}

void main() {
  process((int value) => print("Received: $value"));
}

四、类型转换

4.1、隐式转换

  • 某些情况下,Dart会自动进行类型转换。
  • 示例:double a = 42; (int型的值自动转换为double

4.2、显示转换

  • 使用.toString()、.toInt()、.toDouble() 等方法。

示例代码

int number = 42;
String stringNumber = number.toString(); // "42"
double doubleNumber = number.toDouble(); // 42.0

五、类型系统

详细的介绍可移步至官网查看 类型系统

六、总结

掌握数据类型及其特性是编写高效可靠的应用程序的关键。通过深入理解基本数据类型、复合数据类型、特殊类型以及空安全的概念,我们可以在不同的编程场景中选择最合适的数据结构,并利用 Dart 的类型系统来编写清晰易于维护的代码。无论是开发 Flutter 移动应用还是服务器端应用程序,良好的数据类型管理都是成功项目的基石

码字不易,记得 关注 + 点赞 + 收藏 + 评论