35分钟教你学会dart
这是我目前暂定的目录,后面可能会有所改变,

Flutter的安装与设置(第一节)

image.png

这是flutter系列的第二节,

其实说35分钟教你学会dart,有点言过其实了,不过你依旧可以在这篇文章中学到了解 Dart 基础知识

例如:

  • 变量、数据类型和运算符
  • 条件和循环
  • collection
  • function

完成后,您就可以直接使用 Dart 进行 Flutter 开发了。

入门

单击页面顶部或底部的“下载资料”按钮下载示例代码。您不会在本教程中构建示例项目,但可以使用编码示例作为参考。

您可以将main.dart 中的代码粘贴到 DartPad 中,也可以使用Dart SDK运行该文件。

要快速入门,最好使用开源工具DartPad,它可以让您通过 Web 浏览器编写和测试 Dart 代码:

DartPad 编辑器,注释以显示下方每个元素的位置

DartPad 的设置类似于典型的 IDE。它包括以下组件:

  • 编辑器窗格:位于左侧。您的代码将放在此处。
  • RUN 按钮:在编辑器中运行代码。
  • 控制台:位于右上角,显示输出。
  • 文档面板:位于右下角,显示有关代码的信息。
  • 示例:此下拉列表显示了一些示例代码。
  • Null Safety 按钮:使用此按钮可选择加入 Dart 的新声音零安全功能。
  • 版本信息:在右下角,DartPad 显示当前使用的 Flutter 和 Dart 版本。

如果您愿意,可以在您的机器上本地安装 Dart SDK。一种方法是安装 Flutter SDK。安装 Flutter 也会安装 Dart SDK。

要直接安装 Dart SDK,请访问https://dart.dev/get-dart。

为什么是flutter?

Dart 与 Java、C#、Swift 和 Kotlin 等其他语言有许多相似之处。它的一些功能包括:

  • 静态类型
  • 类型推断
  • 字符串表达式
  • 多范式,包括面向对象和函数式编程
  • 空安全

Dart 已针对在各种平台上开发快速应用程序进行了优化。

核心概念

Dart 程序以调用main. Dart 的语法main看起来类似于 C、Swift 或 Kotlin 等其他语言的语法。

清除默认 DartPad 中的所有代码并添加main到编辑器中:

void main() {

}

你会看到之前有一个返回类型main。在这种情况下,它是void,意味着main不会返回任何东西。

后面的括号main表示这是一个函数定义。大括号包含函数体。

在里面main,你为你的程序添加 Dart 代码。

接下来,您将了解有关以下核心概念的更多信息:

  • 变量、注释和数据类型
  • 基本dart类型
  • Operators
  • 字符串
  • 不变性
  • 可空性
  • 条件和中断
  • For 循环

是时候深入了解了

变量、注释和数据类型

您要添加的第一件事main是变量赋值语句。变量保存您的程序将处理的数据。

您可以将变量视为计算机内存中保存值的盒子。每个框都有一个名称,即变量的名称。要使用 Dart 表示变量,请使用var关键字。

添加一个新变量到main

var myAge = 35;  

每个 Dart 语句都以分号结尾,就像 C 和 Java 中的语句一样。在上面的代码中,您创建了一个变量myAge,并将其设置为等于35

您可以使用printDart 中的内置将变量打印到控制台。在变量之后添加该调用:

print(myAge); // 35

在 DartPad 中单击RUN以运行代码。您将在控制台中看到变量的值35

第一次dart输出

注释

Dart 中的注释与 C 和其他语言中的注释类似:后面的文本//是单行注释,而其中的文本/* ... */是多行注释块。

下面是一个例子:

// This is a single-line comment.

print(myAge); // This is also a single-line comment.

/*
 This is a multi-line comment block. This is useful for long
 comments that span several lines.
 */

数据类型

Dart 是静态类型的,这意味着 Dart 中的每个变量都有一个在编译代码时必须知道的类型。运行程序时变量类型不能改变。C、Java、Swift 和 Kotlin 也是静态类型的。

这与动态类型的Python 和 JavaScript 等语言形成对比。这意味着在运行程序时变量可以保存不同类型的数据。编译代码时不需要知道类型。

单击myAge编辑器窗口并查看文档面板。你会看到 Dart推断出myAge是一个,int因为它是用整数值35初始化的。

如果您没有明确指定数据类型,Dart 会使用类型推断来尝试确定它,就像 Swift 和 Kotlin 所做的那样。

类型推断

Dart 还对int. 输入一个变量,pi,等于 3.14:

var pi = 3.14;

print(pi); // 3.14

Dart 推断pi为 a 是double因为您使用了一个浮点值来初始化它。您可以在 Dart 信息面板中通过单击 来验证pi

双数据类型推断

或者,您可以声明类型,而不是使用类型推断。

基本dart类型

Dart 使用以下基本类型:

  • int : 整数
  • double : 浮点数
  • bool : 布尔值
  • 字符串:字符序列

以下是每种 Dart 类型的示例:

Dart 数据类型

int并且double都派生自一个名为num. num使用dynamic关键字来模拟静态类型 Dart 中的dynamic类型。

通过替换var为您要使用的类型来执行此操作:

int yourAge = 27;
print(yourAge); // 27

dynamic关键字

如果您使用dynamic关键字而不是var,您将获得有效的dynamic类型变量:

dynamic numberOfKittens;

在这里,您可以设置numberOfKittensString使用引号。您将在本教程的后面了解有关String该类型的更多信息。

numberOfKittens = 'There are no kittens!';

print(numberOfKittens); // There are no kittens!

numberOfKittens有一个类型,因为 Dart 有静态类型。但该类型是dynamic,这意味着您可以为它分配具有其他类型的其他值。因此,您可以int在打印语句下方分配一个值。

numberOfKittens = 0;

print(numberOfKittens); // 0

或者,如果你在薛定谔的盒子里有一只小猫,你可以赋值double

numberOfKittens = 0.5;

print(numberOfKittens); // 0.5

薛定谔猫

单击运行以查看numberOfKittens控制台中打印的三个不同值。在每种情况下, 的类型numberOfKittens仍然存在dynamic,即使变量本身持有不同类型的值。

Dart dynamic数据类型

布尔值

bool类型包含true或 的值false

bool areThereKittens = false;

print(areThereKittens); // false

但是,如果你看看薛定谔的盒子,你可能会转而养一只活生生的小猫:

bool areThereKittens = false;

print(areThereKittens); // false

再次运行代码以在控制台中查看您的布尔值。你在盒子里看是一件好事!:]

Dart bool 数据类型

操作符

Dart 具有您在其他语言(如 C、Swift 和 Kotlin)中熟悉的所有常用运算符。

Dart 运算符的一些示例包括:

  • 算术
  • ==
  • 递增和递减
  • 比较
  • 逻辑运算符

注意:Dart 还允许运算符重载,就像在 C++ 和 Kotlin 中一样,但这超出了本教程的范围。要了解有关该主题的更多信息,请访问 Wikipedia 的overator 重载页面。

接下来,您将了解这些运算符中的每一个。

算术运算符

算术运算符的工作方式与您期望的一样。通过向 DartPad 添加一系列操作来尝试它们:

print(40 + 2); // 42

print(44 - 2); // 42

print(21 * 2); // 42

print(84 / 2); // 42.0

对于除法,即使是整数,Dart 也会将结果变量推断为 a double。这就是为什么最后一条语句得到42.0而不是 42的原因print

注意:DartPad 在控制台中将“84 / 2”的结果显示为 42,因为它将输出到控制台的格式设置为仅显示有效数字。如果您在 Dart SDK 的 Dart 程序中打印相同的语句,您将得到42.0作为结果。

等号运算符

Dart 使用双等于( ==) 等于和不等于( !=) 运算符:

print(42 == 43); // false

print(42 != 43); // true

比较运算符

Dart 使用典型的比较运算符:

  • 小于 (<)
  • 大于 (>)
  • 等于 (=>)

这里有些例子:

print(42 < 43); // true print(42 >= 43); // false

此外,它还使用常用的复合算术/赋值运算符:

var value = 42.0;

value += 1; print(value); // 43.0

value -= 1; print(value); // 42.0

value *= 2; print(value); // 84.0

value /= 2; print(value); // 42.0

复合算术/赋值运算符执行两项任务。+=将右边的值与左边的变量相加,然后将结果赋给变量。

的缩写形式+= 1++

value++;

print(value); // 43.0

Dart 有通常的模运算符 ( %) 来返回一个数除以另一个数后的余数:

print(392 % 50); // 42

392 ÷ 50 = 7.84,但结果窗格中的 42 来自哪里?用长除法更容易看到。

长除法显示 392 除以 50,余数为 42

逻辑运算符

DART使用相同的逻辑运算符为其他语言,包括&&||OR

print((41 < 42) && (42 < 43)); // true

print((41 < 42) || (42 > 43)); // true

否定运算符是感叹号,它把假变成真,真变成假。

print(!(41 < 42)); // false

有关dart运算符的完整列表,请参阅 Dart 文档。

字符串

Dart 字符串类型是String. 字符串在 Dart 中使用由*单*引号双引号括起来的文本表示。

您可以使用varand 类型推断或String创建字符串变量,就像您见过的其他类型一样:

var firstName = '早起的年轻人';

String lastName = "坚果";

与 Kotlin 和 Swift 等语言类似,您可以使用美元符号将表达式的值嵌入到字符串中:${ *expression* }

如果表达式是标识符,则可以省略{ }。添加以下内容:

var physicist = "$firstName $lastName likes the number ${84 / 2}";

print(physicist); // 早起的年轻人 坚果

$firstName$lastName由可变值替换。在``返回计算的结果。

转义字符串

Dart 中使用的转义序列类似于其他类 C 语言中使用的转义序列。例如,您用于\n换行。

如果字符串中有特殊字符,请使用\转义它们:

var quote = 'If you can\'t explain it simply\nyou don\'t understand it well enough.';

print(quote);

// 如果你不能简单地解释它

// 你还不够了解。

此示例使用单引号,因此它需要一个转义序列 ,\'can'tdon't的撇号嵌入到字符串中。如果您改用双引号,则不需要转义撇号。

如果您需要在字符串中显示转义序列,您可以使用以 为前缀的原始字符串r

var rawString = r"如果你不能简单地解释它\n你就没有很好地理解它。";

print(rawString); 

// 如果你不能简单地解释它\n你就没有很好地理解它。

在这里,Dart 将其\n视为普通文本,因为字符串以r.

单击DartPad 中的RUN以在控制台中查看所有字符串。

Dart 字符串数据类型

不变性

Dart 使用关键字constfinal不改变的值。

使用const对于那些在编译时已知值。使用final了不具备在编译时已知的,但初始化后不能被重新分配的值。

注意final就像val在 Kotlin 或letSwift 中一样。

您可以使用constandfinal代替var并让类型推断确定类型:

const speedOfLight = 299792458;

print(speedOfLight); // 299792458

在这里,Dart 推断这speedOfLight是一个int,正如您在 DartPad 的信息面板中看到的那样。

Dart 常量推断

final表示变量是不可变的,这意味着您不能重新分配final值。您可以使用final或显式声明类型const

final planet = 'Jupiter';

// planet = 'Mars';

// error: planet can only be set once

final ​String moon = 'Europa';

print('$planet has a moon, $moon');

// Jupiter has a moon, Europa

可空性

过去,如果你没有初始化一个变量,Dart 会给它赋值null,这意味着变量中没有存储任何内容。不过,从 Dart 2.12 开始,Dart 加入了其他语言,如 Swift 和 Kotlin,默认情况下不可为空。

此外,Dart保证不可为空的类型永远不会包含空值。这被称为空安全

通常,如果要声明一个变量,必须对其进行初始化:

String middleName = 'May';

print(middleName); // May

但是,并非每个人都有中间名,因此创建middleName一个可为空的值是有意义的。要告诉 Dart 您想要允许 value null,请?在类型后添加。

String? middleName = null;

print(middleName); // null

可空类型的默认值是null,因此您可以将表达式简化为以下内容:

String? middleName;

print(middleName); // null

运行它并null打印到控制台。

Dart 空字符串输出

空感知运算符

Dart 有一些可识别空值的运算符,您可以在处理空值时使用。

双问号运算符 ,??就像Kotlin 中的Elvis 运算符:如果对象不为空,它返回左侧操作数。否则,它返回右边的值:

var name = middleName ?? 'none';

print(name); // none

由于middleNameis null,Dart 分配 的右侧值'none'

?.运算符保护您访问空对象的属性。null`如果对象本身为空,则返回。否则,它返回右侧属性的值:

print(middleName?.length); // null

在空安全之前的日子里,如果你忘记了问号并写了middleName.length,如果middleName为空,你的应用程序会在运行时崩溃。这不再是问题,因为 Dart 现在会立即告诉您何时需要处理空值。

控制流

控制流可让您决定何时执行、跳过或重复某些代码行。您可以使用条件循环来处理 Dart 中的控制流。

在本节中,您将了解更多关于:

  • 条件句
  • While 循环
  • 继续和中断
  • For 循环

以下是您需要了解的有关 Dart 中的控制流元素的信息。

条件句

控制流的最基本形式是根据程序运行时发生的条件决定是执行还是跳过代码的某些部分。

处理条件的语言结构是if/else语句。if/else在 Dart 中看起来几乎与它在其他类 C 语言中的使用相同。

如果语句

假设您有一个变量,animal,它当前是一只狐狸。它看起来像这样:

var animal = 'fox';

狐狸

您可以使用if语句来检查animal是猫还是狗,然后运行一些相应的代码。

if (animal == 'cat' || animal == 'dog') {
  print('Animal is a house pet.');
}

在这里,您使用了相等OR运算符boolif语句创建了一个内部条件。

其他语句

使用else子句,如果条件为假,您可以运行替代代码:

else {
  print('Animal is NOT a house pet.');
}
// Animal is NOT a house pet.

您也可以将多个组合if/else语句成if/ else if/else结构:

if (animal == 'cat' || animal == 'dog') {
  print('Animal is a house pet.');
} else if (animal == 'rhino') {
  print('That\'s a big animal.');
} else {
  print('Animal is NOT a house pet.');
}
// Animal is NOT a house pet.

你可以有很多else if分支之间if,并else根据您的需要。

While 循环

循环允许您重复代码一定次数或基于特定条件。您可以使用while 循环处理基于条件的重复。

Dart 中有两种形式的 while 循环:whiledo-while。不同之处在于 for while,循环条件发生在代码块之前。在do-while,条件发生在之后。这意味着do-while循环确保代码块至少运行一次。

测试 While 循环

要尝试此操作,请创建一个i初始化为 1的变量:

var i = 1;

接下来,使用while循环i在递增时打印。设置条件i为小于10:

while (i < 10) {
  print(i);
  i++;
}
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9

运行代码,您将看到while循环打印数字 1 到 9。

尝试 Do-While 循环

i在 DartPad 中重置,然后添加一个do-while循环:

i = 1;
do {
  print(i);
  i++;
} while (i < 10);
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9

结果和以前一样。然而这一次,循环体在检查循环退出条件之前运行了一次。

继续和中断

Dart在循环和其他地方使用continuebreak关键字。以下是他们所做的:

  • continue:跳过循环中剩余的代码并立即进入下一次迭代。
  • break:停止循环并在循环体之后继续执行。

continue在代码中使用时要小心。例如,如果您do-while从上面进行循环,并且您希望在i等于 5时继续,则可能会导致无限循环,具体取决于您放置continue语句的位置:

i = 1;
do {
  print(i);
  if (i == 5) {
    continue;
  }            
  ++i;
} while (i < 10);
// 1
// 2
// 3
// 4
// 5
// 5
// 5
// 5
// 5
// 5
// 5
// 5
// 5
// 5
// ...

发生无限循环的原因是,一旦i为 5,您就不会再增加它,因此条件始终为真。

如果在 DartPad 中运行它,无限循环将导致浏览器挂起。相反,使用break,因此循环在i达到 5后结束:

i = 1;
do {
  print(i);
  if (i == 5) {
    break;
  }
  ++i;
} while (i < 10);
// 1
// 2
// 3
// 4
// 5

运行代码。现在,循环在五次迭代后结束。

For 循环

在 Dart 中,您使用for循环来循环预定次数。for循环由初始化、循环条件和动作组成。再一次,它们类似于for其他语言中的循环。

Dart 还提供了一个for-in循环,它遍历一组对象。稍后您将了解有关这些的更多信息。

要查看for循环的工作原理,请为总和创建一个变量:

var sum = 0;

接下来,使用for循环将循环计数器从i1初始化。然后您将检查它i是否小于或等于 10,并i在每次循环后递增。

在循环内,使用复合赋值添加i到运行总和:

for (var i = 1; i <= 10; i++) {
  sum += i;  
}
print("The sum is $sum"); // The sum is 55

在 DartPad 中运行您的代码以查看总和。

Dart for 循环

Collections

集合对于对相关数据进行分组很有用。Dart 包括几种不同类型的集合,但本教程将介绍两种最常见的:ListMap.

列表

Dart 中的列表类似于其他语言中的数组。您可以使用它们来维护有序的值列表。列表是从零开始的,因此列表中的第一项位于索引 0 处:

甜点清单

以下是不同甜点的清单:

List desserts = ['cookies', 'cupcakes', 'donuts', 'pie'];

您将列表的元素括在方括号中:[ ]。使用逗号分隔元素。

在该行的开头,您可以看到类型为List。您会注意到没有包含类型。Dart 推断该列表具有类型。List

这是一个整数列表:

final numbers = [42, -1, 299792458, 100];

单击numbersDartPad,您将看到 Dart 将类型识别为 a Listof int

int的dart列表

使用列表元素

要访问列表的元素,请使用下标表示法,将索引号放在列表变量名称之后的方括号之间。例如:

final firstDessert = desserts[0];
print(firstDessert); // cookies

由于列表索引是从零开始的,因此desserts[0]是列表的第一个元素。

分别使用add和 来添加和删除元素remove

desserts.add('cake');
print(desserts); 
// [cookies, cupcakes, donuts, pie, cake]

desserts.remove('donuts');
print(desserts); 
// [cookies, cupcakes, pie, cake]

运行代码查看结果。

Dart 列表添加和删除方法

早些时候,您了解了for循环。Dart 的for-in循环尤其适用于列表。试试看:

for (final dessert in desserts) {
  print('I love to eat $dessert.');
}
// I love to eat cookies.
// I love to eat cupcakes.
// I love to eat pie.
// I love to eat cake.

您不需要使用索引。Dart 只是遍历 的每个元素desserts并将其每次分配给名为 的变量dessert

饿了?好吧,在你吃完蔬菜之前,你不能吃任何甜点。:]

map

当你想要一个配对值列表时,Map是一个不错的选择。DartMap类似于Swift 中的字典和Kotlin 中的映射

dart地图

以下是 Dart 中的地图示例:

Map<String, int> calories = {
  'cake': 500,
  'donuts': 150,
  'cookies': 100,
};

您围绕Maps的花括号{ }。使用逗号分隔地图的元素。

映射的元素称为键值对,其中键位于冒号左侧,值位于右侧。

您可以通过使用键查找值来查找值,如下所示:

final donutCalories = calories['donuts'];
print(donutCalories); // 150

键 ,'donuts'位于地图名称后面的方括号内。在这种情况下,它映射到 的值150

单击donutCaloriesDartPad,您将看到推断的类型是int?而不是int。这是因为,如果地图不包含您要查找的键,它将返回一个null值。

飞镖图输出

通过指定键并为其分配值来向映射添加新元素:

calories['brownieFudgeSundae'] = 1346;
print(calories);
// {cake: 500, donuts: 150, cookies: 100, brownieFudgeSundae: 1346}

运行该代码,您将看到以水平格式打印的地图,最后是您的新甜点。

Functions

函数使您可以将多行相关代码打包到一个主体中。然后调用该函数以避免在整个 Dart 应用程序中重复这些代码行。

飞镖功能

一个函数由以下元素组成:

  • 返回类型
  • 函数名
  • 括号中的参数列表
  • 括在括号中的函数体

定义函数

您要转换为函数的代码位于大括号内。调用函数时,传入与函数参数类型匹配的参数。

接下来,您将在 DartPad 中编写一个新函数,该函数将检查给定的字符串是否为香蕉

bool isBanana(String fruit) {
  return fruit == 'banana';
}

该函数用于return返回一个bool. 您传递给函数的参数决定了bool.

对于任何给定的输入,此函数将始终返回相同的值类型。如果函数不需要返回值,您可以将返回类型设置为void. main例如,这样做。

使用函数

您可以通过传入字符串来调用该函数。然后,您可以将该调用的结果传递给print

void main() {
  var fruit = 'apple';
  print(isBanana(fruit)); // false
}

嵌套函数

通常,您可以在其他函数外部或 Dart 类内部定义函数。但是,您也可以嵌套 Dart 函数。例如,您可以嵌套isBananamain.

void main() {
  bool isBanana(String fruit) {
    return fruit == 'banana';
  }

  var fruit = 'apple';
  print(isBanana(fruit)); // false
}

您还可以将参数更改为函数,然后使用新参数再次调用它:

fruit = 'banana';
print(isBanana(fruit));  // true

调用函数的结果完全取决于你传入的参数。

可选参数

如果函数的参数是可选的,您可以用方括号将其括起来并使类型可以为空:

String fullName( String first, String last, [ String? title]) {
   if (title == null ) {
     return  ' $first  $last ' ; 
  } else {
     return  ' $title  $first  $last ' ; 
  } 
}

在这个函数中,title是可选的。null如果您不指定它,它将默认为。

现在,您可以使用或不使用可选参数调用该函数:

print(fullName('Joe', 'Howard'));
// Joe Howard

print(fullName('Albert', 'Einstein', 'Professor'));
// Professor Albert Einstein

命名参数和默认值

当您有多个参数时,很难记住哪个是哪个。dart解决了这一难题命名参数,您可以通过与周围大括号参数列表获得:{ }

默认情况下,这些参数是可选的,但您可以为它们提供默认值或使用required关键字使它们成为必需:

bool withinTolerance({required int value, int min = 0, int max = 10}) {
  return min <= value && value <= max;
}

value是必需的,而minmax是可选的,具有默认值。

使用命名参数,您可以通过提供带有冒号的参数名称以不同的顺序传递参数:

print(withinTolerance(min: 1, max: 5, value: 11)); // false

调用函数时,您可以不使用默认值的参数。

print(withinTolerance(value: 5)); // true

运行您的代码以查看正在运行的新函数。

命名和默认参数

匿名函数

Dart 支持一流的 functions,这意味着它像对待任何其他数据类型一样对待函数。您可以将它们分配给变量,将它们作为参数传递并从其他函数中返回它们。

要将这些函数作为值传递,请省略函数名称和返回类型。由于没有名称,这种类型的函数称为匿名函数

匿名函数

您可以将匿名函数分配给名为 的变量onPressed,如下所示:

final onPressed = () {
  print('button pressed');
};

onPressed有一个类型的值Function。空括号表示该函数没有参数。与常规函数一样,大括号内的代码是函数体。

要在函数体内执行代码,请调用变量名,就像它是函数名一样:

oonPressed(); // button pressed 按钮按下

您可以使用箭头语法简化函数体仅包含一行的函数。为此,请移除大括号并添加一个粗箭头=&gt;

这是上面匿名函数和重构版本的比较:

// original anonymous function
final onPressed = () {
  print('button pressed');
};

// refactored
final onPressed = () => print('button pressed');

读起来好多了。

使用匿名函数

你会经常看到 Flutter 中的匿名函数,就像上面的那些,作为 UI 事件的回调传递。这使您可以指定在用户执行某些操作(例如按下按钮)时运行的代码。

您会看到匿名函数的另一个常见地方是集合。您可以为集合提供一个匿名函数,该函数将对集合的每个元素执行某些任务。例如:

// 1
final drinks = ['water', 'juice', 'milk'];
// 2
final bigDrinks = drinks.map(
  // 3
  (drink) => drink.toUpperCase()
);
// 4
print(bigDrinks); // (WATER, JUICE, MILK)

让我们看看每一步:

  1. 定义一个drinks包含小写字母的列表。
  2. .map 获取所有列表值并返回一个带有它们的新集合。
  3. 匿名函数作为参数传递。在该匿名函数中,您有一个drink表示列表中每个元素的参数。
  4. 匿名函数的主体将每个元素转换为大写并返回值。由于原始列表是字符串列表,因此drink也有 type String

使用匿名函数并将其与它结合.map是将一个集合转换为另一个集合的便捷方式。

注意:不要将.map方法与Map类型混淆。

运行代码以查看生成的集合。

匿名函数

恭喜,您已阅读完本教程。您现在应该对学习如何构建 Flutter 应用程序时看到的 Dart 代码有了更好的理解!

下一步

另外,请查看官方 Dart 文档

我希望你喜欢这篇关于 Dart 基础知识的简短介绍。可以给我点赞,如果您有任何问题或意见,请评论区告诉我
我们下周见,下周将给大家分享更多的新鲜知识,当然如果你觉得这篇文档有点看不懂,需要更基础的,我也可以在后面准备一个手把手dart系列,请评论区告诉我!