将 Dart 和 JavaScript 做一个对比:
开发效率高
Dart 运行时和编译器支持 Flutter 的两个关键特性的组合:
高性能
Flutter 旨在提供流畅、高保真的的 UI 体验。为了实现这一点,Flutter 中需要能够在每个动画帧中运行大量的代码。这意味着需要一种既能提供高性能的语言,而不会出现会丢帧的周期性暂停,而 Dart 支持 AOT,在这一点上可以做的比 JavaScript 更好。
快速内存分配
Flutter 框架使用函数式流,这使得它在很大程度上依赖于底层的内存分配器。因此,拥有一个能够有效地处理琐碎任务的内存分配器将显得十分重要,在缺乏此功能的语言中,Flutter 将无法有效地工作。当然 Chrome V8 的 JavaScript 引擎在内存分配上也已经做的很好,事实上 Dart 开发团队的很多成员都是来自Chrome 团队的,所以在内存分配上 Dart 并不能作为超越 JavaScript 的优势,而对于Flutter来说,它需要这样的特性,而 Dart 也正好满足而已。
类型安全和空安全
由于 Dart 是类型安全的语言,且 2.12 版本后也支持了空安全特性,所以 Dart 支持静态类型检测,可以在编译前发现一些类型的错误,并排除潜在问题,这一点对于前端开发者来说可能会更具有吸引力。与之不同的,JavaScript 是一个弱类型语言,也因此前端社区出现了很多给 JavaScript 代码添加静态类型检测的扩展语言和工具,如:微软的 TypeScript 以及Facebook 的 Flow。相比之下,Dart 本身就支持静态类型,这是它的一个重要优势。
Dart 团队就在你身边
看似不起眼,实则举足轻重。由于有 Dart 团队的积极投入,Flutter 团队可以获得更多、更方便的支持,正如Flutter 官网所述“我们正与 Dart 社区进行密切合作,以改进 Dart 在 Flutter 中的使用。例如,当我们最初采用 Dart 时,该语言并没有提供生成原生二进制文件的工具链(这对于实现可预测的高性能具有很大的帮助),但是现在它实现了,因为 Dart 团队专门为 Flutter 构建了它。同样,Dart VM 之前已经针对吞吐量进行了优化,但团队现在正在优化 VM 的延迟时间,这对于 Flutter 的工作负载更为重要。”
在这之前,我们知道”工欲善其事必先利其器“,所以需要安装相关工具。
…
win7电脑看这篇博客。
https://blog.csdn.net/weixin_30979229/article/details/114453053?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164921053916782246441003%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164921053916782246441003&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-4-114453053.142v5pc_search_result_control_group,157v4control&utm_term=win7%E5%AE%89%E8%A3%85java&spm=1018.2226.3001.4187
首先,现在官网下载flutter
SDK包,在此包里面包含了Dart
的SDK
文件,下载路径如下:
在 Windows 操作系统上安装和配置 Flutter 开发环境 | Flutter 中文文档 - Flutter 中文开发者网站
点击蓝色按钮即可下载。
下载完成之后,将该文件包解压到你想安装目录的下面,我的安装目录是在D:\SoftwareFolder\
路径下,将其解压。解压完成之后就是运行,flutter提供了两种运行方式:
flutter_console.bat
文件,就可以在命令行中输入flutter命令了。flutter
环境flutter\bin
目录,将地址复制,然后打开环境变量窗口进行配置环境变量。检测是否可用:
按快捷键win+R
输入cmd
命令,在命令行中输入flutter doctor
。
打开 Android studio
,在stting
->appearance &Behavior
->System Settings
->Android SDK
中进行配置。
但是出现了错误,没关系,先解决第一个框里面的问题。
它提示Android toolchain - develop for Android devices
,
说明是Android的SDK协议没有添加许可证,
找到自己android—sdk的路径,比如:G:\studioAnZhuang\AndroidStudioSDK\tools\bin
,关键是**\tools\bin**。
在此目录打开 cmd 命令行 输入以下命令:
sdkmanager --licenses
然后一路同意y
就可以了,最后在命令行下输入flutter doctor 查看结果。
之后关闭此命令行窗口,再次运行flutter doctor
发现还是这两个问题,于是看见它找出的问题是Unable to locate Android SKD
,这就要涉及到配置环境变量的问题,找到你的Android sdk
安装路径,比如我的安装路径如下图。
由于我不确定是不是这个路径,去环境变量里添加了这个之后,发现可行,把我激动坏了,环境变量配置如下所示。
关闭命令行窗口之后,再次运行flutter doctor
如下图所示。
不知道为啥,就是特别兴奋,感觉满满的成就感,哈哈哈,但是一想到还有一个问题没有解决,脑壳又大了。
于是分析了一下,发现是没有安装谷歌的原因,于是我通过下面链接去下载了google
浏览器。
Google Chrome 网络浏览器
它给我自动安装在了C盘,由于不知道怎么更改路径,就挺无语的,再次运行flutter doctor就没有报错了,如下图所示。
配置完这些东西之后,我们还需要去环境变量中添加2个路径如下图所示。
盘符名:安装文件夹\flutter_windows_2.5.3-stable\flutter\bin\cache\dart-sdk\bin
flutter2.0
之后,官网的安装包里面就自带了dart的sdk文件,所以,我们只需要找到它的文件位置,将它的环境变量设置好就可以开始肝代码了。将下面的路径添加到系统环境变量中。盘符名:安装文件夹\flutter_windows_2.5.3-stable\flutter.pub-cache\bin
bin
文件夹,创建一个即可。有了上面这些操作,我们就可以配置编译器,开始在编译器中肝代码了!!激动的心,颤抖的手,终于要开始了。
首先,打开Android studio
软件,点击File
> New
>New Flutter Project...
选择Dart
添加Dart sdk
文件位置,如下如图所示。
点击Next
,创建项目名和项目地址,之后点击Finish
,即可创建项目。
首先,找到Project
面板,在空白区域右击,选择new
>Dart File
>输入你的文件名,即可创建你的dart
文件。
写一段代码测试是否可以运行。
写完之后,点击mian
方法旁边的
按钮运行,并查看结果如下图。
如果发现无法运行,请点击下面图中的第一个框,进行选择模拟器,再点击运行。
首次,在VScode
官网进行下载,链接如下。
Download Visual Studio Code - Mac, Linux, Windows
安装特别简单,若有不会,请访问下面链接。
百度一下,你就知道 (baidu.com)
安装之后,我们需要在软件中安装flutter
插件和run
插件,如下图所示。
首先,你需要在你所需要创建项目的目录下使用cmd
命令,进入命令行,使用flutter create flutter_app
。
flutter_app
是你需要创建的项目名。
在vscode打开项目,找到android
目录下的build.gradle
文件并且打开。
在打开的文件中,将repositories{...}
下的google()
和mavenCentral()
注释,因为我们要换源,使用国内的镜像源。将下面3个源替换原来的两个源。
maven { url ‘https://maven.aliyun.com/repository/google’}
maven { url ‘https://maven.aliyun.com/repository/jcenter’ }
maven { url ‘https://maven.aliyun.com/repository/public’ }
之后打开你的flutter
安装目录,找到目录下的packages > flutter_tools > gradle >flutter.gradle>
的文件,双击在vscode中打开,将repositories{...}
下面的代码替换。保存,重新打开vscode。
说完了安装方法,现在介绍两种添加Flutter
第三方包的两种方法:
flutter
项目的pubspec.yaml
文件中添加:dependencies:
所在的行,并且需要知道它的版本号,所以,打开https://pub.dev/
,在这里面你可以搜索到所有开源的第三方包。provider
的包:dependencies
处,点击Pub get
,在下面的Messges
窗口中可以看到是否添加成功,若成功之后,可以在External Libraries
中查看文件的位置。首先,我们需要知道程序是都是从main
方法开始执行,于是有了固定的写法,如下所示。
// 定义一个输出方法
void printInteger(int num){
print("hello world $num"); // 输入语句,将文本输出到控制台
// $num 用于将形参的值放进来
}
// 在主函数中输出
void main(){
var number = 3000; // 定义一个活动变量,可以是任意类型值
printInteger(number); // 调用方法
}
从上面可以看出:
在main方法后面是一对小括号与一对大括号。
大括号里面放置的是需要执行的程序语句。
函数和方法前面都有类型声明,void
关键字表示该方法 无返回值
,int
是整形数字。
两根斜杠为注释内容,程序不会执行被注释的内容。
打印使用print( JavaScript
中使用console.log()
)。
每行代码结束时,必须写结束分号。
字符串通过引号包起来,支持模板字符串。
用var
声明的变量。其数据类型是动态的。
声明函数不需要关键字(JavaScript
中使用function
关键字声明函数)。
在Dart
中,注释有两种写法,和javascript
的注释方法一样,如下所示。
//
两根斜杠为注释。// 这行文本被注释
/* 这里边是文本内容 */
,以两根斜杠为边,里面再放两个星号,在星号中的文本就是注释内容。/*
这行文本被注释
这行文本被注释
*/
dartdoc
将注释转换为文档(文档注释支持markdown
语法)。/// 这是文档注释
变量是一个引用,Dart万物皆对象,变量存储的是对象的引用。
声明变量
明确指定类型:int age = 18;
不明确类型:
var age = 18;
dynamic age = 18;
Object age = 18
。
Object
是 Dart
所有对象的根基类,也就是说在 Dart 中所有类型都是Object
的子类(包括Function和Null),所以任何类型的数据都可以赋值给Object
声明的对象。 dynamic
与Object
声明的变量都可以赋值任意对象,且后期可以改变赋值的类型,这和 var
是不同的,如:
var t;
dynamic t;
Object x;
var t = "ha";
t = "hi world";
x = 'Hello Object';
//下面代码没有问题
t = 1000; // 出错
//下面代码没有问题
t = 1000;
x = 1000;
dynamic
与Object
不同的是dynamic
声明的对象编译器会提供所有可能的组合,而Object
声明的对象只能使用 Object
的属性与方法, 否则编译器会报错。
dynamic a;
Object b = "";
main() {
a = "";
printLengths();
}
printLengths() {
// 正常
print(a.length);
// 报错 The getter 'length' is not defined for the class 'Object'
print(b.length);
}
dynamic
的这个特点使得我们在使用它时需要格外注意,这很容易引入一个运行时错误,比如下面代码在编译时不会报错,而在运行时会报错:
print(a.xx); // a是字符串,没有"xx"属性,编译时不会报错,运行时会报错
变量名大小写敏感(age与Age是两个不同的变量)。
Dart
变量的值不会进行隐式转换(null不会自动 转换成false)。
void main() {
//定义变量
var name1="张三";
print(name1); // 输出字符串 张三
// 指定类型的变量
String name2 = "李四";
print(name2); // 输出String类型的字符串 李四
// 任意类型的变量
dynamic name3 = "王五";
print(name3); // 输出字符串 王五
// 任意类型的变量
Object name4 = "赵六";
print(name4); // 输出字符串 赵六
}
常量就是值不可以改变的变量(一旦声明,其值不能改变)。
声明常量
使用const
关键字进行声明变量。
const age = 18;
使用final
关键字进行声明变量。
final age = 18;
const
与final
的区别
const time=DateTime.now();
//报错-无法将运行时得知分配给const
变量。final time = DateTime.now();
//成功-可以将运行时的值分配给final
变量。void main(List args) {
// const定义常量
const age = 18;
// age = 19; // 报错,常量不能再次赋值
print(age); // 输出整形 18
// final定义常量
final age1 = 18;
// age1 = 19; // 报错,常量不能再次赋值
print(age1);
// 报错-无法将运行时得知分配给`const`变量
// Cannot invoke a non-'const' constructor where a const expression is expected.
// const time1=DateTime.now();
// 成功-可以将运行时的值分配给`final`变量
final time2=DateTime.now();
print(time2);
}
num
数字类型(既可以是整数,也可以是小数)
int
表示整数(必须是整数)double
表示浮点数(既可以是整数,也可以是小数)void main(List args) {
// 定义一个整型变量
int num1 = 123;
print(num1); // 123
// 定义一个浮点数变量
double num2 = 123;
print(num2); // 123.0
// 定义一个数值变量,它包含了int类型和double类型
num num3 = 123;
print(num3); // 123
num num4 = 123.0;
print(num4); // 123.0
}
常用API
首先,我们需要知道怎么定义字符串,字符串定义的引号都是成对出现,字符串的定义方法如下:
使用var的方式进行定义。
var str1 = 'this is str1'; // 单引号形式
var str2 = "this is str2"; // 双引号新式
// 输出结果如下所示
this is str1
this is str2
使用String定义字符串,3个引号包括换行符。
String str1 = 'this is str1'; // 单引号形式
String str2 = "this is str2"; // 双引号新式
String str3 = '''
this is str3
this is str3'''; // 实现多行显示,原样显示
// 输出结果如下所示
this is str1
this is str2
this is str3
this is str3
正则表达式。
首先,我们需要定义两个字符串变量,然后将他们拼接起来。
+
加号将他们连接。 // 字符串拼接
String str1 = "张三想:";
String str2 = "吃饭";
print(str1+str2);
//或者
String str3 = str1 + str2;
print(str3);
// 效果如下
张三想:吃饭
张三想:吃饭
$
方式进行拼接操作。 String str1 = "张三想:";
String str2 = "吃饭";
print("$str1 $str2");
张三想: 吃饭
使用字符分割,结果是一个数组类型的值。
.split("字符")
– 根据字符进行分割。 // 字符串分割
String str1 = "hello world";
print(str1.split(""));; // 按照空值进行分割
[h, e, l, l, o, , w, o, r, l, d]
字符串裁切
.trim()
– 将字符串前后空格裁切掉。.trimLeft()
– 将字符串的左边空格裁切。.trimLeft()
– 将字符串的右边空格裁切。// 字符串裁切
String str1 = " hello world ";
print(str1.trim()); // 删除前后空格
print(str1.trimLeft()); // 删除左边空格
print(str1.trimRight()); // 删除右边空格
hello world
hello world
hello world
判断字符串是否为空
.isEmpty
– 判断字符串是否为空,返回值是 true或 false。.isNotEmpty
– 判断字符串是否不为空,返回值是 true或 false。// 判断字符串是否为空
String str1 = ""; // 定义空字符串
print(str1.isEmpty);
print(str1.isNotEmpty);
true
false
字符串替换
.replaceAll(旧字符,新字符)
,而.replaceFirst()
只查找第一个并替换。 // 字符串替换
String str1 = "hello dart,hello world";
print(str1.replaceAll("hello", "你好"));
查找字符
.contains('字符串')
– 在字符串中查找字符,返回值为true 或 false。 // 字符查找
String str1 = "hello dart,hello world";
print(str1.contains("l"));
true
.indexOf(字符)
– 用于在找到字符的索引位置,返回索引下标,从左开始查找。.lastIndexOf(字符)
– 找到字符的索引位置,返回索引下标,从右往左查找。 // 定位字符
String str1 = "hello dart,hello world";
print(str1.indexOf('ll'));
print(str1.lastIndexOf("or"));
2
18
布尔类型只有true
和false
。
Dart通过bool关键字来表示布尔类型。
对变量进行判断时,要显式的检查布尔值
// 定义一个true值
bool b1 = true;
print(b1);
// 定义一个false值
bool b2 = false;
print(b2);
true
false
显式的判断
与if语句,将条件true
赋值给一个变量保存,将其放入if
的判断中进行判断,使用如下:
bool b3 = true;
if (b3) {
print("条件成立!");
}else{
print("条件不成立");
}
条件成立!
判断字符是否为 NaN。
var b1 =0/0;
print(b1.isNaN);
true
判断是否为空值。
// 判断是否为空值
var flag;
if (flag == Null) {
print("是空值");
} else {
print("不是空值");
}
List 就是Dart中的数组,由List
对象表示。List有两种声明方式:
字面量方式
创建列表。
List list = [1,2,"张三","不法分子"]; // 不限定元素的数据类型
泛型方法限定列表类型。
List list = [1,2,3]; // 泛型,限定元素的类型是int
构造函数方式
创建一个不限定长度的列表。
List list = new List.empty(growable:true); // 不限制长度的空列表
[]
填充指定长度的列表。
List list = new List.filled(3,6); // 声明指定长度的填充列表
[6, 6, 6]
扩展操作符(…)
将第一个列表插入到另一个列表中。
var list = [1,2,3];
var list2 = [0,...list];
[0, 1, 2, 3]
使用?
先进行判断是否可以扩展,在下面列子中用空值进行试验。
// 判断是否可以扩展
var list;
// var list1 = [123,...list]; //报错:type 'Null' is not a subtype of type 'Iterable'
var list2 = [234,...?list];
print(list2);
添加元素
.add(数据)
– 向列表中添加元素,可以是字符串、数组、各种数据类型。
// 添加元素
List list = [12,23,34];
list.add(1.3);
list.add("字符串");
list.add([true,false]);
print(list);
[12, 23, 34, 1.3, 字符串, [true, false]]
.addAll(iterable)
– iterable是一个可迭代的对象,可以在里面放置多个元素。
// 添加元素
List list = [12,23,34];
list.addAll(["name",123,["张三",18]]);
print(list);
[12, 23, 34, name, 123, [张三, 18]]
在指定位置添加元素。
.insert(index,element)
– index为元素下标,element为元素
// 在指定位置添加元素
List list = [12,23,34,45,56];
list.insert(3, "张三"); // 在下标为3的地方添加“张三”
print(list);
[12, 23, 34, 张三, 45, 56]
清空列表
.clear()
– 清空列表。
// 清空列表
List list = [12,23,34,45,56];
list.clear();
print(list);
[]
连接元素
.join('-')
- -将列表中的元素使用 - 连接。删除元素
.remove(元素名)
– 参数为需要删除的元素名。
List list = [12,23,34,45,56];
list.remove(23);
print(list);
[12, 34, 45, 56]
.removeAt(下标)
– 根据下标删除元素。
// 根据下标删除元素
List list = [12,23,34,45,56];
list.removeAt(list.length-1);
print(list);
[12, 23, 34, 45]
返回数组长度
.length
– 可以查看数组有少个元素。
// 查看数组长度
List list = [12,23,34,45,56];
print(list.length);
5
创建一个固定长度的列表
.filled(元素个数,填充的字符)
--所接收的元素类型一定是List
类型,创建的列表长度是固定的,不可以修改他的长度。
List list = List.filled(3,6); // 声明指定长度的填充列表
print(list);
[6, 6, 6]
指定创建指定类型与长度的列表。
// 创建指定类型的快速填充
List list = List.filled(3,""); // 所创建的列表中只能添加int类型的元素。
list[0]="张三";
print(list);
[张三, , ]
列表反转
.reversed
– 将列表中的元素翻转,得到的结果是一个元组,可以使用在后面加上.toList()
方法.
// 列表的反转
List list = [12,23,34,45,56];
print(list.reversed);
// 变为列表
print(list.reversed.toList());
(56, 45, 34, 23, 12)
[56, 45, 34, 23, 12]
forEach()
map()
where()
any()
every()
使用for
循环进行遍历。
// for 循环进行遍历
var list = [1,2,3];
for (var i = 0; i < list.length; i++) {
print(list[i]);
}
1
2
3
for … in 循环。
// for in 循环进行遍历
var list = [1,2,3];
for (var item in list) {
print(item);
}
1
2
3
forEach 使用匿名函数进行遍历,其中element是一个形参,使用print可将他打印出来。
// forEach
var list = [1,2,3];
list.forEach((element) {
print(element);
});
1
2
3
使用map()将列表中的每个元素进行相乘,得到一个处理之后的列表,注意:=>
函数只能右一行,可以省略大括号。
// map
var list = [1,2,3];
list.map((e)=> e*e); // 也可以写成这样list.map((e)=> {e*e});
print(list);
}
[1, 2, 3]
where()返回符合条件的元素
//where()返回符合条件的元素
// 判断数字是否为奇数
var list = [1,2,3,4,5,6,7,8];
bool isOdd(n) => n%2==1; // 箭头函数,判断数字是否为奇数
var oddNum = list.where((element) => isOdd(element)); // 返回结果是一个元组类型
print(oddNum.toList());
[1, 3, 5, 7]
isOdd()
函数进行判断,将判断的结果返回给list,并重复判断,直到不满足条件为止。而element
则是列表中的每一个元素。使用any()检测是否有奇数,返回值为true或false。有一个也是true。
// 使用any() 检测是否奇数
var list = [1,2,3,4,5,6,7,8];
bool isOdd(n) => n%2==1; // 箭头函数,判断数字是否为奇数
print(list.any(isOdd));
true
使用every()来判断是否都是奇数。
// 使用every()来判断是否都是奇数
var list = [1,2,3,4,5,6,7,8];
bool isOdd(n) => n%2==1; // 箭头函数,判断数字是否为奇数
print(list.every(isOdd));
false
使用扩展方式,通过.expend()
方法进行降维处理。
// 扩展,使用expend进行降维
var list = [[1,2,3],[4,5,6]];
var flattened = list.expand((element) => element).toList();
print(flattened);
折叠-- .fold(initialValue, (previousValue, element) => null)
,initialValue
为初始值,对列表中的每一个元素,做一个累计的操作。
// 折叠
var list = [1,2,3,4,5,6];
int result = list.fold(2, (previousValue, element) => previousValue+element);
print(result);
Set是一个无序的,元素唯一的集合,不能有重复值。
Set有字面量和构造函数两种声明方式(字面量中用大括号)。
无法通过下标取值。
具有集合特有的操作。比如:求交集、并集、差集等。
字面量
// 字面量
var nums = {1,2,3};
print(nums);
{1, 2, 3}
构造函数的形式创建集合
// 构造函数创建集合
var fruits = new Set(); // 使用构造函数的形式创建集合
fruits.add("张三"); // 向集合中添加添加元素
fruits.add("李四");
fruits.add("王五");
print(fruits); // 打印集合
print(fruits.toList()); // 集合转换为表格形式
{张三, 李四, 王五}
[张三, 李四, 王五]
列表转换为集合
// 表格转换为集合,重复的元素会被过滤掉
List list = [1,2,2,3,4,4]; // 定义列表
print(list.toSet()); // 列表转换为集合
{1, 2, 3, 4}
集合特有的操作,交集、差集、并集。
// 集合特有操作
var name1 = new Set();
name1.addAll(['张山','李四',"王五"]);
var name2 = new Set();
name2.addAll(["王五","赵六","马七"]);
// 求交集,共同有的元素会被显示出来了。
print(name1.intersection(name2));
// 求并集,将他们合并,共同的元素只留一个。
print(name1.union(name2));
// 求差集,第一个中有的,而第二个中没有的元素。
print(name1.difference(name2));
// 返回第一个元素
print(name1.first);
// 返回最后一个元素
print(name1.last);
Map是一个无序的键值对(key-value)映射。通常被作为哈希或字典。]
Map的键值对是成对出现的。
声明方式:
var map = {key1:value1,key2:value2};
var map = new Map();
map['key'] = value;
字面量形式
// 字面量形式
var person = {
'name':'张三',
'age':18,
'information':'法外狂徒',
};
print(person);
{name: 张三, age: 18, information: 法外狂徒}
构造函数
// 构造函数
var p = new Map();
p['name'] = "张三"; // 向map中添加元素
p['age'] = 18;
p['info'] = '法外狂徒';
print(p);
// 访问属性
print(p['name']); // 访问name的值
{name: 张三, age: 18, information: 法外狂徒}
{name: 张三, age: 18, info: 法外狂徒}
张三
判断Map中的Key和Value是否存在,返回值为true或false。
var p = new Map();
p['name'] = "张三";
p['age'] = 18;
p['info'] = '法外狂徒';
print(p);
// 判断Map中的Key是否存在
print(p.containsKey('name'));
// 判断Map中的Value是否存在
print(p.containsValue('张山'));
true
false
.putIfAbsent()
赋值,如果 Key 不存在,我们才赋值(如果key已存在,则不赋值)。
var p = new Map();
p['name'] = "张三";
p['age'] = 18;
p['info'] = '法外狂徒';
print(p);
//如果 Key 不存在,向Key赋值
p.putIfAbsent('score', () => 100);
print(p);
{name: 张三, age: 18, info: 法外狂徒, score: 100}
.keys
和.values
获取map中所有的key 和 value。
// 获取所有的key 和 value
var person = {'name':'张三','age':18,'information':'法外狂徒'};
print(person.keys);
print(person.values);
(name, age, information)
(张三, 18, 法外狂徒)
删除元素
.remove(key)
– 根据key 进行删除。
// 删除元素
var person = {'name':'张三','age':18,'information':'法外狂徒'};
person.remove('name');
print(person);
{age: 18, information: 法外狂徒}
.removeWhere()
– 根据条件进行删除。
// 根据条件进行删除
var person = {'name':'张三','age':18,'information':'法外狂徒'};
person.removeWhere((key, value) => key=='name');
print(person);
{age: 18, information: 法外狂徒}
Runes(符文)
Symbol
#
开头来表示的标识符。dynamic
运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。Dart语言内置了丰富的运算符,并提供了以下类型的运算符:算术运算符、关系运算符、类型判断运算符、赋值运算符、逻辑运算符、按位和移位运算符、条件表达式、级联运算符以及其他运算符。
地板除(~/)-- 相除之后,向下取整。
类型判断运算符(is |is!)-- 判断某种变量是否属于某种类型。
避空运算符(?? | ??=) – 如果变量为空,才会对变量赋值,变量不为空,不对其做任何操作。
条件属性访问(?.) – 先判断属性是否存在,存在的话再去访问。
级联运算符(…)
myObject.myMethod(); // 返回myMethod的返回值
myObject..myMethod(); // 返回myMethod()对象的引用
~/
地板除,相除之后,向下取整
// 地板除
print(5/3); // 除法
print(5~/3); // 地板除
1.6666666666666667
1
is
和is!
类型判断运算符 // 类型判断运算符
List list = []; // 定义一个列表
// is运算符
if (list is List) { // 判断是否是列表
print("是List");
} else {
print("不是List");
}
// is! 运算符
if (list is! List) {
print("不是列表");
} else {
print("是列表");
}
是List
是列表
??
和??=
避空运算符
// 避空运算符
print(1 ?? 3); //返回1,因为1不为空
print(null ?? 11); // 返回11,因为第一个参数为null
var name; //name没有赋值,为空。
print(name ?? "name为空");
// 赋值避空运算符
name ??= "张三"; //进行判断,如果为空,将张三赋值给name
print(name);
1
11
name为空
张三
条件属性运算符
// 条件属性运算符(判断可能为空的属性)
var m = new Map();
print(m.length); // 返回0
var obj;
// print(obj.length); //The getter 'length' was called on null.
print(obj?.length); // 返回null
0
null
级联运算符
// 级联运算符
// 普通添加删除数据
Set s =new Set();
s.add("张三");
s.add("李四");
s.add([1,2,3]);
s.removeWhere((element) => element=="张三");
print(s);
// 级联添加删除数据
Set set = new Set();
set..add("张山")
..add("赵陆")
..add([1,2,3])
..removeWhere((element) => element=="张三");
print(set);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cpQLAH98-1638454824693)(F:\flutter笔记\Dart_imges\image-20211120170520611.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j755TOBt-1638454824693)(F:\flutter笔记\Dart_imges\image-20211120170555298.png)]
// 算数运算符
print(2 + 3 == 5);
print(2 - 3 == -1);
print(2 * 3 == 6);
print(5 / 2 == 2.5); // 结果是一个浮点数
print(5 ~/ 2 == 2); // 结果是一个整数
print(5 % 2 == 1); // 取余
print('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');
// 自增自减运算符
var a, b;
a = 0;
b = ++a; // 在 b 赋值前将 a 增加 1。
print(a == b); // 1 == 1
a = 0;
b = a++; // 在 b 赋值后将 a 增加 1。
print(a != b); // 1 != 0
a = 0;
b = --a; // 在 b 赋值前将 a 减少 1。
print(a == b); // -1 == -1
a = 0;
b = a--; // 在 b 赋值后将 a 减少 1。
print(a != b); // -1 != 0
用法基本上和其他语言相同。
使用...
可以进行拼接操作,两个..
表示级联操作。
三个点
List a = ["张三","李四","王五"];
List b = ["赵六","马奇","黄八"];
List c = [...a,...b];
print(c);
// 结果为:[张三, 李四, 王五, 赵六, 马奇, 黄八]
Map map1 = {'张三':'1','李四':'2','王五':'3',};
Map map2 = {'赵六':'4','马奇':'5','黄八':'6',};
Map map3 = {...map2,...map1};
print(map3);
// 结果为:{赵六: 4, 马奇: 5, 黄八: 6, 张三: 1, 李四: 2, 王五: 3}
两个点
class Test {
//正常写法
A printfA() {
var a = A();
a.a();
a.b();
a.c();
return a;
}
//级联写法
A printfA() {
return A()..a()..b()..c();
}
}
class A {
a() {}
b() {}
c() {}
}
// 定义函数
void printInfo(){ // 无参函数,无返回值
print("hello world!");
}
int getNum(){ // 有返回值,无参函数
// return "张三"; // 不能返回String类型值
return 18; // int类型声明的函数只能返回int类型的值
}
void main(List args) {
printInfo(); // 调用函数
int a = getNum(); // 接收函数返回值
print(a);
}
hello world!
18
void main(List args) {
// 匿名函数
var myPrint = (value){ // 定义一个匿名函数
print(value);
};
List fruits = ["苹果","香蕉","西瓜"];// 定义一个列表、
// fruits.forEach((element) {element});
fruits.forEach(myPrint);
}
苹果
香蕉
西瓜
myPrint
替换了(element) {element}
,原因是在.forEach()
方法中传入的也是一个匿名函数。只能一行显示的简单函数,并且没有分号。
// 箭头函数
List fruits = ["苹果","香蕉","西瓜"];
fruits.forEach((element) =>{
print(element) // 箭头函数中不能有分号,并且只能有一行
});
fruits.forEach((element) =>print(element)); // 只能有一行
苹果
香蕉
西瓜
苹果
香蕉
西瓜
立即执行函数就是立即执行的函数。
// 立即执行函数
(
(int n){
print(n);
}
)(1223556);
1223556
// 定义一个String类型的必选参数
String userInfo(String name){
return '你好:$name';
}
void main(List args) {
// 必填参数
// String res = userInfo(123); // 传入的值必须和定义值类型一样
String res = userInfo("张三");
print(res);
}
你好:张三
// 可选参数
// // 必须给age定一个默认值,如果为null会和int类型冲突。或者使用动态类型 dynamic 和 Object类型
// String userInfo(String name,[int age=0]) // int类型
// String userInfo(String name,[dynamic age]) // Object类型
String userInfo(String name,[Object age=0]){
return '你好:$name,年龄:$age';
}
void main(List args) {
// 必填参数
// String res = userInfo(123); // 传入的值必须和定义值类型一样
String res =userInfo("张三",18);
print(res);
}
形参类型必须与实参类型一致。
可选参数用中括号包裹起来。
// 命名参数
String userInfo(String name,{int age=0}){ // 使用花括符进行定义,int类型必须赋值
return '你好:$name,年龄:$age';
}
void main(List args) {
// 命名参数调用时,必须与声明的形参一致
String res =userInfo("张三",age:18); // 使用键值对的形式进行传递参数
print(res);
你好:张三,年龄:18
属性名:属性值
的形式进行传参。// 函数参数
var myPrint = (value){ // 定义一个匿名函数
print(value);
};
List fruits = ["苹果","香蕉","西瓜"];// 定义一个列表、
// 将匿名函数传递给forEach函数
fruits.forEach(myPrint);
苹果
香蕉
西瓜
parent(){
var money = 1000;
return (){
money-=100;
print(money);
};
}
var p = parent(); // 将parent函数保存为p函数
p(); // 每次调用完之后只释放return里面的匿名函数的地址,并没有parent函数的地址。
p(); // 所以可以一直调用一直减
p();
900
800
700
…
使用class
关键字进行定义类,类名后面是一对花括符,如:class 类名{};
实例化类使用new
关键字。
在new
对象的时候类名后面需要写一对小括号,比如:类型 对象名 = new 类名();
// 声明类
class Person{
// 类的属性
String name = "张三";
// 类的方法
void getInfo(){
print("我是$name");
}
}
void main(List args) {
// 实例化类,得到一个对象
Person p = new Person();
// 访问类中的属性
print(p.name);
// 访问类中的方法
p.getInfo();
}
张三
我是张三
dart中所有的内容都是对象。
为什么这么说呢?看下面例子。
// new一个Map对象,Map是Dart中内置的一个类,不需要自己创建
Map m = new Map();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cFrApKDO-1638454824699)(F:\flutter笔记\Dart_imges\image-20211121170336802.png)]
在当前目录中创建一个lib
目录,在该目录中创建一个叫lei.dart
文件,在文件中写入一个类,如下所示:
// lei.dart
// 创建一个人类
class Person{
int a =10;
late int b; // 创建一个空值b
// 有参构造函数
Person(this.a,this.b){
print('${a} $b');
}
// 命名构造函数
Person.info(){
print("这是命名构造函数");
}
}
// 创建一个动物类
class Animal{
late String name;
late String info;
Animal(this.name,this.info){
print("传入的动物是:$name ,种类是:$info");
}
}
在上面类的上一级目录创建一个名为Factory_Constuctor.dart
的文件,并写入下面代码,主要是实现类的调用。
import 'lib/lei.dart';
void main(List args) {
// Person p = new Person(123,456);
Person p = new Person.info();
int a1 = p.a;
print("a为:$a1");
Animal animal = new Animal("小狗", "泰迪");
print(animal.name);
}
这是命名构造函数
a为:10
传入的动物是:小狗 ,种类是:泰迪
小狗
// 构造函数
class Point{
// 定义类属性
num x=0,y=0;
// 声明普通构造函数,在创建对象时,就会自动执行构造函数
Point(num x, num y){ // 构造函数与类同名,并设置为有参构造函数
print("这是构造函数");
// 打印
print("参数值$x $y");
// 为了避免有歧义,使用this指向类中属性
this.x=10; //指向第4行的x,并改变x的值为10
this.y=20; //指向第4行的y,并改变y的值为20
}
}
void main(List args) {
Point p = new Point(40,30); // 创建对象,并给构造函数传递参数
print("属性值:");
print(p.x); // 打印属性x的值
print(p.y);
}
这是构造函数
参数值40 30
属性值:
10
20
class Point{
// 定义类属性
num x=0,y=0;
// 简写构造函数
Point(this.x, this.y); // 简写构造函数,需要加分号结尾。
}
void main(List args) {
Point p = new Point(40,30); // 创建对象,并给构造函数传递参数
print("属性值:");
print(p.x); // 打印属性x的值
print(p.y);
}
属性值:
40
30
class Point{
// 定义类属性
num x=0, y=0;
// 简写构造函数
Point(this.x,this.y);
// 命名构造函数
Point.origin(){ // origin-原始的
x = 0;
y = 0;
}
Point.fromJson({x:0,y:0}){
this.x = x;
this.y = y;
}
}
void main(List args) {
// 默认坐标
Point p1 = new Point.origin();
print(p1.x);
// 手动设置坐标
Point p2 = new Point.fromJson(x: 20,y: 30);
print(p2.x);
}
0
20
new
关键字。class Point{
num x=0;
num y=0;
// 构造函数简写
Point(this.x,this.y);
}
class ImmutablePoint{
// 属性必须通过 final 声明
final num x;
final num y;
// 常量构造函数,必须通过 const 声明,并且常量声明的函数不能有函数体
const ImmutablePoint(this.x,this.y);
}
void main(List args) {
var p1 = new Point(1, 3);
var p2 = new Point(1, 3);
print(p1 == p2);
// 常量构造函数,可以当做普通构造函数使用
var p3 = new ImmutablePoint(3,4);
var p4 = new ImmutablePoint(3,4);
print(p3 ==p4);
// 声明不可变对象,必须通过 const 关键字,而new出来的对象是指向不同的地址,所以不相等
var p5 = const ImmutablePoint(3,4);
var p6 = const ImmutablePoint(3,4);
print(p5 ==p6); // true
// 创建对象可以不用 new 关键字进行实现
var p7 = ImmutablePoint(3,4);
var p8 = ImmutablePoint(3,4);
print(p3 ==p4); // false
}
分为私有属性和私有方法,就是在属性名或者方法名前面加一个短下划线_
,例如:_name
和_Animal()
方法就是被定义为私有的属性和方法。
在lib
目录下创建一个名为private.dart
的文件,里面写一下代码:
// 创建一个动物类
class Animal{
late String _name; // 定义私有属性
late String info;
// ignore: unused_element
_Animal(_name,info){
print("传入的动物是:$this._name ,种类是:$info");
}
int _aaa(){ // 定义私有方法
return 100;
}
}
// 创建一个人类
// 创建一个人类
class Person{
late String name;
late String info;
Person(this.name,this.info){
print(this.name);
print(this.info);
}
}
在privaDemo.dart
文件中调用。
import 'lib/private.dart';
void main(List args) {
Animal animal = new Animal("晓白", "牧羊犬");
// var aa = animal._aaa(); // 不能调用私有方法
// String name = animal._name; // 不能访问私有属性
print(animal.info);
Person p = new Person("张三","法外狂徒");
print("name为:${p.name}");
}
传入的动物是:晓白 ,种类是:牧羊犬
牧羊犬
张三
法外狂徒
name为:张三
通过 factory
声明,工厂函数不会自动生成实例,而是通过代码来决定返回的实例。
class Rect{
late num _height;
late num _width;
Rect(this._height,this._width);
// get方法,注意方法名之后不加小括号
get getarea{
return this._height* this._height;
}
// set方法,注意set方法需要加小括号
set setHeight(value){
this._height = value;
}
}
void main(List args) {
Rect rect = new Rect(10, 20);
// 得到getarea值
print("矩形面积为:${rect.getarea}");
// 调用set方法为height设置值
rect.setHeight=30;
print("面积为:${rect.getarea}");
}
矩形面积为:100
面积为:900
class Rect{
late num height;
late num width;
// 初始化列表
Rect():height=3,width=20{
print("height为:${this.height},width为:${this.width}");
}
}
void main(List args) {
// 创建对象
Rect rect = new Rect();
}
height为:3,width为:20
static
关键字来实现类级别的变量和函数。import 'dart:ffi';
class Person{
static String name = "张三"; // 定义静态属性
int age = 18; // 定义非静态方法
// 定义静态方法
static void show(){
print("我的名字叫:${name}");
}
void printInfo(){
print("${name}的信息");
print("年龄为:${this.age}");
// 调用静态方法
show();
}
static void printUserInfo(){
print(name); // 访问静态属性
show(); // 调用静态方法
// print(age); // 静态方法无法范文非静态属性
// this.printInfo(); // 静态方法无法访问非静态方法
// printInfo(); // 静态方法无法访问非静态方法
}
}
void main(List args) {
// Person person = new Person(); // 创建对象
// person.show(); // 被修饰的静态方法不能由创建的对象进行访问
// 由类名进行访问
print(Person.name);
Person.show();
// 非静态方法与非静态属性的使用
Person person = new Person();
person.printInfo();
print(person.age);
// 调用静态方法
Person.printUserInfo();
}
张三
我的名字叫:张三
张三的信息
年龄为:18
我的名字叫:张三
18
张三
我的名字叫:张三
extends
关键字来继承父类。class Person{
String name ="张三";
num age = 20;
void printInfo(){
print("姓名:${this.name},年龄:${this.age}");
}
}
// 创建一个男人类,并继承人类
class Man extends Person{
}
void main(List args) {
// 创建一个男人对象
Man man = new Man();
print(man.name); // 调用人类的name
man.printInfo(); // 调用父类的方法
}
张三
姓名:张三,年龄:20
@override
关键词。class Person{
late String name;
late num age;
// 构造函数
Person(this.name,this.age);
void printInfo(){
print("Person类");
print("姓名:${this.name},年龄:${this.age}");
}
}
// 创建一个男人类,并继承人类
class Man extends Person{
// 定义子类的属性
late String sex;
// 重写父类构造函数
Man(String name, num age, String sex) : super(name, age){ // 实例化构造函数的时候,将子类的name与age传递给父类的构造函数
this.sex =sex; // 将子类的构造函数里的sex赋值给子类sex属性
}
// 复写父类方法
@override
void printInfo(){
print("man类");
print("姓名:${this.name},年龄:${this.age},性别:${this.sex}");
}
// 定义子类的方法
void run(){
print("儿子类子跑");
}
}
void main(List args) {
// 创建父类对象
Person person = new Person("张三",18);
person.printInfo();
// Person person1 = new Person("李四",56);
// person1.printInfo();
// 创建子类对象
Man man =new Man("张大娃", 32,"男");
man.printInfo(); // 通过构造函数,找到父类的构造函数,使用父类的方法进行打印。
man.run(); // 子类调用子类的方法
}
Person类
姓名:张三,年龄:18
man类
姓名:张大娃,年龄:32,性别:男
儿子类子跑
使用super
为命名构造函数传参。
class Person{
late String name;
late num age;
// 命名构造函数
Person.xxx(this.name,this.age);
// 创建一个男人类,并继承人类
class Man extends Person{
// 定义子类的属性
late String sex;
// 重写父类构造函数
Man(String name, num age, String sex) : super.xxx(name, age){ // 实例化命名构造函数的时候,将子类的name与age传递给父类的构造函数
this.sex =sex; // 将子类的构造函数里的sex赋值给子类sex属性
}
// 复写父类方法
@override
void printInfo(){
print("man类");
print("姓名:${this.name},年龄:${this.age},性别:${this.sex}");
}
void main(List args) {
Person person = new Person.xxx("张三",18); // 命名构造函数传参
person.printInfo();
Man man =new Man("张大娃", 32,"男");
man.printInfo(); // 通过构造函数,找到父类的构造函数,使用父类的方法进行打印。
man.run(); // 子类调用子类的方法
}
Person类
姓名:张三,年龄:18
man类
姓名:张大娃,年龄:32,性别:男
子类调用父类方法,在子类的方法名前面加上一个supper
关键字,例如:supper.run()
,调用父类的run()方法
。
子类中使用父类的属性时,可以使用this
关键词进行调用。
abstract
关键字来定义。abstract
声明,Dart中没有方法体的方法我们称为抽象方法。// 定义抽象类
abstract class Animal{
eat(); // 抽象方法
run();
// 在抽象类中定义,该方法可以有方法体
printInfo(){
print("我来自抽象类");
}
}
// 子类继承父类必须实现父类中的所有方法
class Dog extends Animal{
@override
eat() {
print("小狗在啃骨头");
}
@override
run() {
print("小狗再跑");
}
}
// 子类继承父类必须实现父类中的所有方法
class Cat extends Animal{
@override
eat() {
print("小猫在吃饭");
}
@override
run() {
print("小猫在跑");
}
}
void main(List args) {
Dog dog = new Dog();
dog.eat();
dog.printInfo(); // 调用抽象类的方法
Cat cat = new Cat();
cat.eat();
cat.printInfo(); // 调用抽象类的方法
}
小狗在啃骨头
我来自抽象类
小猫在吃饭
我来自抽象类
// 定义抽象类
abstract class Animal{
eat(); // 抽象方法
}
// 子类继承父类必须实现父类中的所有方法
class Dog extends Animal{
@override
eat() {
print("小狗在啃骨头");
}
//
run(){
print("小狗正在跑");
}
}
// 子类继承父类必须实现父类中的所有方法
class Cat extends Animal{
@override
eat() {
print("小猫在吃饭");
}
//
run(){
print("小狗正在跑");
}
}
void main(List args) {
// 子类的一个实例赋值给父类的应用,也就是所在下面创建的对象就属于父类,而run方法时子类中定义的,所以父类无法调用子类的run方法。
Animal dog = new Dog();
dog.eat();
// dog.run(); // 无法调用run方法
Animal cat = new Cat();
cat.eat();
// cat.run(); // 无法调用run方法,父类中没有run 方法
}
小狗在啃骨头
小狗正在跑
小猫在吃饭
interface
关键字定义接口,普通类或抽象类都可以作为接口被实现。implement
关键字进行实现。// 定义接口
abstract class Person{
late String name;
eat();
run();
info(String str);
}
// 继承Person接口
class Man implements Person{
@override
late String name;
@override
eat() {
print("男人在吃饭");
}
@override
info(String str) {
print("${str}的信息");
}
@override
run() {
print("男人在奔跑");
}
Man(String str);
}
// 继承Person接口
class Women implements Person{
@override
late String name;
@override
eat() {
print("女人在吃饭");
}
@override
info(name) {
print("${name}的信息");
}
@override
run() {
print("女人在奔跑");
}
// Women(this.name);
}
void main(List args) {
// 创建man对象
Man man = new Man("张三");
man.info("张三");
// 创建women对象
Women women = new Women();
women.info("张如玉");
women.run();
}
可以将这些接口、类、main
进行分离,分别放在不同的Dart
文件中,如果要导入这些模块,需要使用improt
关键字进行导入。
mixins
实现类似多继承的功能。mixins
的类只能继承自Object
,不能继承其他类。mixins
的类不能有构造函数。mixins
多个mixins
类。mixins
绝不是继承,也不是接口,而是一种全新的特性。小结:
多继承:
使用with后面的类:
被继承的类不能继承其他类
被继承的类中不能有构造函数
with
class X with a,b{
...
}
也可以
class X extends c with a,b{
...
}
抽象类:
抽象类不能实例化,继承必须实现内部抽象方法和属性
抽象类可以继承extends(复用其中普通方法),可以实现implements(当模板)
抽象类中的方法不加abstract
abstract class x{
int a;
int b;
void f(); 抽象方法
void ff(){...}; 普通方法
}
继承该抽象类的类,只用实现抽象方法,普通方法和属性不用重写
多态:父类引用子类,父类的方法引用子类的方法,只能调用父类中存在的方法,不能调用子类中父类没有的方法
Animal c=new Dog(); c只能调用Animal中的方法,且引用子类Dog中的相同方法
接口:
使用abstract定义抽象类为接口,操作和抽象类一样
抽象类的所有属性和函数都必须重写
abstract class x{
int a;
int b;
void f(); 抽象方法
void ff(){...}; 普通方法
}
class c implements x{
int a;
int b;
void f(){}
void ff(){}
}
多接口:
class c implements a,b{...}
T getValue(T value){..方法体..return..}
// 定义泛型方法,一般使用大写 T 表示
T getValue(T value){
return value;
}
void main(List args) {
// 传入int类型参数
var d = getValue(123);
print(d);
// 传入string类型参数并指定类型。
var str =getValue("张三");
print(str);
}
123
张三
class Mylist{ // 定义一个泛型类
List list = []; // 定义一个泛型列表
// 定义一个泛型方法,负责向列表中添加数据
void add(T value){
this.list.add(value);
}
// 返回列表
List getList(){
return list;
}
}
void main(List args) {
// 限定为String类型的列表
Mylist l2 = Mylist();
l2.add("张三"); // 添加一个string参数
l2.add("李四");
// l2.add(123); // 在创建对象时限定为String类型,只能传入String数据
print(l2.getList()); // 打印列表
// 限定为int类型的列表
Mylist l3 = Mylist();
l3.add(123);
l3.add(456);
print(l3.getList());
}
[1, 张三, false]
。。。。。。。。
有时间再更新
。。。。。。。。