
                            
                            因收到Google相关通知，网站将会择期关闭。相关通知内容
                            
                            
                            03 新手村基础 Dart 语法 (上)
                            无论你处于编程的任何阶段，都应该铭记一点：


对于计算机编程而言，最重要的是 维护数据 的变化。


比如你支付宝中的账户金额；你微信聊天记录的内容；你游戏中的资源装备；你随手拍的一张照片、录制的一段意义非凡的视频，都是数据在计算机中的不同表现形式。作为编程者要通过代码逻辑，保证数据在 用户与应用交互 过程中的准确性，来完成功能需求。

本教程只会介绍最最基础的 Dart 语法，能支撑后续教程的内容即可。无论是自然语言，还是编程语言，语法的学习都是非常枯燥的。对于新手而言，不必任何细节都面面俱到，正所谓贪多嚼不烂。学习应该循序渐进、细水长流，先自己能站立了，再想跑的事。如果已经有 Dart 基础的朋友，本章简单过一下就行了，也可能温故而知新哦 ~



一、基础数据类型

先思考一下，在现实世界中，我们如何表示不同类别的事物? 其实很简单，就是根据事物的特征进行划分，然后 取名字 进行表示。当这种表示形式在全人类中达到共识，就会成为一个认知标准，比如下面是一只猫:



而提到猫，自然就会想到它体型不大，有两个眼睛，两个耳朵，四个腿，脸上有胡须，这就是类型的特征。而 猫 这个名字本身只是一个标志，用于对一类事物的指代。虽然不同的地域可能有不同的叫法，但重要的其实不是它叫什么，而是它是什么，能干什么。



在编程中，数据类型也是类似，它的存在是为了解决：


如何在代码中 表示数据种类 的问题。


解决方法也是一样： 取名字 —- 通过名称区分不同类型数据的特点。在任何编程语言中有 内置基础类型 以供使用，下面来简单看一下 Dart 中基础数据类型变量的定义。到这里，先简单认识一下四种数据类型：
数字、文字是人们日常生活在接触最多的数据，对于任何编程语言来说都是至关重要的。布尔型本身非常简单，只能表示真或假，对逻辑判断有着重要的意义。





1. 数字类型

在日常生活在，数字 是非常必要的，它可以描述数量，也可以进行数学运算。在 Dart 语言中，数字有两大类型： 整型(整数) int 和浮点型(小数) double 。定义变量的语法是 类型名 变量名 = 值 ，下面代码中定义了两个变量：

void main(){
  // 整型 age，表示年龄的数值
  int age = 2;
  // 浮点型 weight，表示体重的数值
  double weight = 4.5;
}


在这里学习 Dart 基础知识时，可以在项目的 test 文件夹里，编辑代码做测试。点击三角可以运行代码：





现在通过一个小练习，认识一下代码如何进行简单的逻辑运算：


定义三个浮点型变量 a,b,c，值分别是 2.3, 4.5, 2.5 ；
通过代码计算出平均值 avg ；并将结果输出到控制台。


代码如下，数字量之间可以进行四则运算，求平均值就是将数字相加，除以个数。通过 print 函数可以在控制台输出量的信息：

void main(){
  double a = 2.3;
  double b = 4.5;
  double c = 2.5;

  double avg = (a+b+c)/3;
  print(avg);
}


运行后，可以看到计算的结果。比如 a,b,c 变量分别代表三只小猫的体重，那这段代码就是：解决获得平均体重问题的一个方案。代码本身的意义在于 解决问题， 脱离问题需求而写代码，就像是在和空气斗智斗勇。





2. 字符串类型

在日常生活中，除了数字之外，最重要的就是 文字，在编程中称之为 字符串。 文字可以为我们提供信息，如何通过代码来表示和操作它，是一件非常重要的事。
在 Dart 中，通过 String 类型表示字符串，字符串值可以通过单引号 'str' 或 双引号 "str" 进行包裹，一般情况下，两者没有太大的区别，用自己喜欢的即可。字符串直接可以通过 + 号进行连接，如下所示：

void main() {
  String hello1 = 'Hello, World!';
  String hello2 = "Hello, Flutter!";
  print(hello1 + hello2);
}

---->[输出结果]----
Hello, World!Hello, Flutter!




通过 $变量名 可以在字符串内插入变量值。如下所示，将计算平均值的输出表述进行了完善：

void main() {
  double a = 2.3;
  double b = 4.5;
  double c = 2.5;

  double avg = (a + b + c) / 3;
  String output = '$a,$b,$c 的平均值是$avg';
  print(output);
}

---->[输出结果]----
2.3,4.5,2.5 的平均值是3.1 


另外，也可以通过 ${表达式} 来嵌入表达式，比如：

 String output = '$a,$b,$c 的平均值是${(a + b + c) / 3}';


也可以理解为变量是特殊的表达式，在插入时可以省略 {}。对于字符串来说，先了解如何定义和使用就行了，以后如有需要，可以在其他资料中系统学习。



3. 布尔型 bool

布尔型用于表示真假，其中只有 true 和 false 两个值，一般用于判断的标识。布尔值可以直接书写，可以通过一些运算得到。比如数字的比较、布尔值的逻辑运算等。

void main() {
  // 直接赋值
  bool enable = true;
  double height = 1.18;
  // 布尔值可以通过运算获得
  bool free = height < 1.2;
}




二、运算符

运算符可以和值进行连接，进行特定运算，产出结果；比如加减乘除，大小比较，逻辑运算等。可以说运算符是代码逻辑的半壁江山。对于初学者而言，先掌握下面的三类运算符：





1. 算数运算符

算数运算符作为数学的基础运算，从小就陪伴着我们，大家应该不会感到陌生。它连接两个数字进行运算，返回数值结果：



void main() {
  print(1 + 2);//3    加
  print(1 - 2);//-1   减
  print(1 * 2);//2    乘
  print(1 / 2);//0.5  除
  print(10 % 3);//1   余
  print(10 ~/ 3);//3  商
}




2.比较运算符

比较运算符，也是日常生活中极为常见的。它连接两个值进行运算，返回比较的 bool 值结果 ：



void main() {
  print(1 > 2); //false   大于
  print(1 < 2); //true    小于
  print(1 == 2); //false  等于
  print(1 != 2); //true   不等
  print(10 >= 3); //true  大于等于
  print(10 <= 3); //false 小于等于
}




3.逻辑运算符

逻辑运算符，用于连接 bool 值进行运算，返回 bool 值。 理解起来也很简单，&& 表示两个 bool 值都为 true，才返回 true ; || 表示两个 bool 值有一个是 true，就返回 true ; ! 之后连接一个 bool 值，返回与之相反的值。



如下代码所示，open 和 free 是两个 bool 值，表示条件。通过 && 运算得到的 bool 值表示需要同时满足这两个条件，即 免费进入 需要公园开放，并且可以免费进入：

void main() {
  // 公园是否开放
  bool open = true;
  // 是否免费
  bool free = false;

  // 公园是否免费进入
  bool freeEnter = open && free;
}




三、流程控制

如果是运算符是代码逻辑的半壁江山，那流程控制 就是另外一半。流程控制可以分为 条件控制 和 循环控制；其中：


条件控制 可以通过逻辑判断的语法规则，执行特定的分支代码块。
循环控制 可以让某个代码块执行若干次，直到符合某些条件节点结束。




1. 条件流程 : if - else

如果怎么样，就做什么，这种选择执行的场景，在日常生活中非常常见。而 if - else 就是处理这种选择分支的语法。 if 之后的 () 中填入布尔值，用于逻辑判断；条件成立时，执行 if 代码块；条件不成立，执行 else 代码块。如下代码根据 free 布尔值，打印是否可以免费入园：

void main() {
  double height = 1.18;
  // 布尔值可以通过运算获得
  bool free = height < 1.2;
  if(free){
    print("可免费入园");
  }else{
    print("请购买门票");
  }
}




2. 条件控制 : switch - case

if - else 只能对 bool 值进行逻辑判断，进行分支处理。某些场景中需要对更多类型的值进行判断，这时就可以使用 switch - case 进行分支处理。
如下代码所示，根据字母等级，打印对应的评级信息，其中 switch 后面的括号在是校验值， case 之后是同类型的值，当 case 后的值和校验值一致时，会触发其下的分支逻辑。 default 分支用于处理无法匹配的场合。

void main() {
  String mark = 'A';
  switch (mark) {
    case 'A':
      print("优秀");
      break;
    case 'B':
      print("良好");
      break;
    case 'C':
      print("普通");
      break;
    case 'D':
      print("较差");
      break;
    case 'E':
      print("极差");
      break;
    default:
      print("未知等级");
  }
}




3. 循环流程 - for 循环

有些情况下，我们需要不断执行某一段逻辑(循环体)，直到条件完成(循环条件)，这就是循环控制。
for 循环中，() 里有三个表达式，通过 ; 隔开，


第一个表达式是进入循环之前执行的语句，在循环过程中不会再次执行；
第二个表达式是循环条件，每次循环体执行完毕，都会校验一次。当条件满足时，会执行下次循环。
第三个表达式在每次循环体执行完毕后，都会执行一次。


如下代码的含义就是：在循环开始时定义 i 整数变量，赋值为 0， 在 i < 5 的条件下，执行循环体；每次循环体执行完毕后，让 i 增加 1 。 循环体中对 i 值进行累加，并且打印信息：

void main() {
  int sum = 0;
  for (int i = 0; i < 5; i = i + 1) {
    sum = sum + i;
    print("第 $i 次执行,sum = $sum");
  }
}

---->[输出结果]----
第 0 次执行,sum = 0
第 1 次执行,sum = 1
第 2 次执行,sum = 3
第 3 次执行,sum = 6
第 4 次执行,sum = 10


注: i = i + 1 可以简写为 i += 1, 其他的算数运算符也都有这种简写形式。
另外，表示整数 i 自加 1 ，也可以简写为 i++ 或 ++i。两者的区别在于对 i 赋值的先后性, 自减 1 同理。如果初学者觉得简写难看懂，可以不用简写。

---->[情况1：i++]---- 
int i = 3; 
int a = i++; //执行赋值后i才自加,故a=3 
print('a=$a,i=$i');//a=3,i=4 

---->[情况2：++i]---- 
int i = 3; 
int a = ++i; //执行赋值前i已经自加,故a=4 
print('a=$a,i=$i');//a=4,i=4




4. 循环流程 - while 循环

for 循环和 while 循环并没有什么本质上的区别，只是形式上的不同，两者可以进行相互转换。下面是类比 for 循环中的三块，将上面的代码转换为 while 循环。



可能有人会问，既然 while 循环和 for 循环可以相互转化，那为什么不干掉一个呢? 就像菜刀和美工刀虽然都可以完成切割的任务，但不同的场景下会有更适合的工具。 while 只需要关注循环条件，在某些场合下更简洁，语义也很不错； for 循环的固定格式，更便于阅读，可以一眼看出循环的相关信息。



另外还有 do - while 循环，算是 while 的变式。 do 代码块中是循环体，while 后依然是条件。 do - while 循环的最大特点是： 先执行循环体，再校验条件。也就是说，它的循环体必然会被执行一次。

void main() {
  int sum = 0;
  int i = 0;
  do{
    sum += i;
    print("第 $i 次执行,sum = $sum");
    i = i + 1;
  } while (i < 5);
}


根据不同的场景，可以选择不同的形式。 但千万别被形式整的晕头转向，记住一点：它们在本质上并没有区别，都是控制条件，执行循环体。而且它们之间都可以进行转换。



5. 中断控制 - break 和 continue

在循环流程中，除了循环条件可以终止循环，还可以通过其他关键字来中断循环。


break 关键字: 直接跳出循环，让循环终止。
continue 关键字：跳出本次循环，将进入下次循环。


void main() {
  // ---->[break情景]----
  for (int i = 0; i < 10; i++) {
    if (i % 3 == 2) {
      break; //直接跳出循环
    }
    print("i:$i"); //打印了 0，1
  }

  // ---->[continue情景]----
  for (int i = 0; i < 10; i++) {
    if (i % 3 == 2) {
      continue; //跳出本次循环，将进入下次循环
    }
    print("i:$i"); //打印了 0，1，3，4，6，7，9
  }
}




四、函数的定义和使用

函数是一段可以有输入和输出的逻辑单元；通过函数，可以将特定的算法进行封装，简化使用。这里，我们通过一个实际的问题场景来介绍函数：


身体质量指数，是BMI（Body Mass Index）指数，简称体质指数，是国际上常用的衡量人体胖瘦程度以及是否健康的一个标准。


对于一个人来说，只要知道自己的身高和体重，就可以通过公式 : BMI=体重÷身高^2 计算出体质指数。如果每次计算时，都要根据公式计算是非常麻烦的。

void main() {
  double toly = 1.8 / (70 * 70);
  double ls = 1.79 / (65 * 65);
  double wy = 1.69 / (50 * 50);
}


另外，如果某天体质指数 的计算公式改变了，那散落在代码中各处的直接计算都需要修改，这无疑是非常麻烦的。 函数的价值就在于封装算法，下面来体会一下函数的价值。



1. 函数的简单定义

函数可以有若干个输入值，和一个输出值。比如对于计算体质指数 来说，有身高 height 和体重 weight 两个小数。输出是 体质指数 的具体值。如下所示，定义 bmi 函数：函数名前是返回值类型；之后的括号中是参数列表，通过 , 号隔开，每个参数由 参数类型 参数名 构成；{} 中是函数的具体算法逻辑：

double bmi(double height, double wight) {
  // 具体算法
  double result = wight / (height * height);
  return result;
}




需要获取一个人的 体质指数 ，只要调用 bmi 函数，传入身高和体重即可。使用者不需要在意公式具体是什么，如果某天公式改变了，只需要修改 bmi 中的算法实现，其他代码都无需改动。所以，函数的价值不仅在于实现算法逻辑，也能为某个功能提供一个公共的接入口，以应对可能改变的风险。

void main() {
  double toly = bmi(1.8, 70);
  double ls = bmi(1.79, 65);
  double wy = bmi(1.69, 50);

  print("===toly:$toly===ls:$ls===wy:$wy===");
}




2. 命名参数

有些时候，函数的参数过多，在调用时需要记清顺序，是比较麻烦的。Dart 中支持命名参数，可以通过参数的名称来传参，不需要在意入参的顺序。通过 {} 包裹命名的参数，其中 required 关键字表示该入参必须传入; 另外，可以用 = 提供参数的默认值，使用者在调用时可以选填：

double bmi({
  required double height,
  double weight = 65,
}) {
  // 具体算法
  double result = weight / (height * height);
  return result;
}


如下所示，在使用时可以通过 weight 和 height 指定参数，参数的顺序是无所谓的；另外由于 weight 有默认值，在调用时可以不填，计算时会取默认值：

void main() {
  double toly = bmi(weight: 70, height: 1.8);
  double ls = bmi(height: 1.79);
  double wy = bmi(height: 1.69, weight: 50);
}




3. 位置参数

方括号 [] 包围参数列表，位置参数可以给默认值：

double bmi([double height = 1.79, double weight = 65]) {
  // 具体算法
  double result = weight / (height * height);
  return result;
}


在使用时必须要按照参数顺序传入，它和普通参数列表的区别在于：在调用时，可以省略若干个参数，省略的参数使用默认值：

void main() {
  double toly = bmi(70, 1.8);
  double ls = bmi();
  double wy = bmi(1.69);
}


函数是一个非常有用的语法功能，在一个函数中可以调用其他函数，来组织逻辑。上面的 bmi 函数其实只是将一行代码的运算进行封装，已经显现出了很大的价值，更不用说能完成某些特定功能的复杂函数。但封装也很容易造成只会使用，不懂内部实现逻辑的局面，这在即使好事(不用在意底层逻辑，专注上层使用)，也是坏事(底层逻辑有问题，难以自己修复)。


这里给个小作业: 找一个计算公式，通过函数来封装对它的调用




五、本章小结

到这里，对于编程来说最最基础的三个模块: 基本数据类型、运算符、流程控制，就有了基本的认识。这些语法点是代码逻辑实现的基石，对烹饪来说，相当于水、火、面、米、油、盐等最基础的材料，对一顿饭来说不可或缺。

基本的食材可以保证能吃饱，但对于一席盛大的晚宴来说，是远远不够的：酱醋茶酒、鸡鸭鱼肉，是更高等的食物素材。函数、对象可以对代码逻辑进行封装，从而更好地维护代码结构。下一篇，将继续介绍 Dart 基础语法，了解面向对象的相关知识。

                        
                        
                            