learn-tech/专栏/Flutter入门教程/03新手村基础Dart语法(上).md
2024-10-16 00:01:16 +08:00

477 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

因收到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 同理。如果初学者觉得简写难看懂,可以不用简写。
---->[情况1i++]----
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"); //打印了 01
}
// ---->[continue情景]----
for (int i = 0; i < 10; i++) {
if (i % 3 == 2) {
continue; //跳出本次循环将进入下次循环
}
print("i:$i"); //打印了 0134679
}
}
函数的定义和使用
函数是一段可以有输入和输出的逻辑单元通过函数可以将特定的算法进行封装简化使用这里我们通过一个实际的问题场景来介绍函数
身体质量指数是BMIBody 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 基础语法了解面向对象的相关知识