Dart语言简介
对于Dart这一门语言,百度百科是这么解释的:Dart是谷歌开发的计算机编程语言,它被应用于web、服务器、移动应用和物联网等领域的开发,它是面向对象、类定义、单继承的语言,当然啦~ 楼主来了解这个语言就是为了了解用Dart来开发的Flutter应用。
Dart SDK 和 IDE的安装
要学某种语言,首先当然是SDK 和 IDE的安装
Dart SDK的安装可以参考官网的命令来安装:Dart官网
⚠️:如果在安装的过程中出错,可以看看https://blog.csdn.net/qq_40028324/article/details/105692357这篇文章能否帮你解决问题(毕竟楼主是依靠这篇文章来解决问题的 亲测有效~)
关于Dart的开发工具选择比较多,有IDEA、VS Code 等 楼主这里使用的是IDEA 每个开发工具的具体安装参考官网即可,由于楼主使用的是IDEA,我这里就拿IDEA来举例。
安装IDEA之后,打开IDEA,搜索Dart插件安装,到此 我们的Dart整个开发环境就搭建好了,接着就要进入正题了~
Hello World
// main 方法是程序入口
void main() {
print("Hello World"); // 输出:Hello World
}
一、Dart中的数据类型
1、变量和常量
变量:var
常量:const ⚠️:使用const声明的必须是编译期变量
关键字final:声明只能赋值一次的变量
🌰:
void main() {
var a = 10;
final b = 20;
const c = 30;
}
2、数值型:num
num 只有int 和 double两种类型
常用的操作:+ - * / % ~/
常用属性:isNaN(是否不是数字),isEven,isOdd......
🌰:
void main() {
num a = 12.5;
int b = 20;
print(b ~/a); // 1 ~/表示除之后对结果取整
print(b/a); // 1.6
print((0.0/0.0).isNaN); // true
print(b.isEven);// 是否是偶数 true
print(b.isOdd);// 是否是奇数 false
}
3、字符串:String
""
和 ''
都可以创建字符串
"""
和 '''
创建多行的字符串
r
创建一个原始的字符串
常用操作:+ * == []
常用属性:length、isEmpty、split()......
插值表达式:${expression}
🌰:
void main () {
String str0 = "Hello"; // ''
String str1 = '''Hello
World!!!''';
String str2 = r'Hello \n Dart';
String str3 = 'Hello';
String str4 = str3 + ' World';
print(str0);
print(str1);
print(str2); // Hello \n Dart
print(str4); // Hello World
print(str3 * 2); // HelloHello
print(str3 == str4); // false
print(str3[4]); // o
int a = 1;
int b = 2;
print("a + b = ${a+b}"); // a + b = 3
print(str4.substring(0,3)); // Hel
print(str4.split(' '));// [Hello, World]
}
4、布尔类型:bool
true、false
5、列表(数组):List
构造创建:var list = new List();
🌰:
void main () {
var list = [1,2,3,"Dart",false]; // list里面的元素可以是多种类型 不要求是同一种类型
print(list); // [1,2,3,"Dart",false]
var list1 = const [1,2,3];
// list1[1] = 6; // 运行会报异常
list.insert(0, 999);
print(list); // [999,1,2,3,"Dart",false]
// 遍历List
list.forEach((element) {
print(element);
});
print(list.indexOf(6)); // 如果没有找到对应的元素 返回结果是 -1
var list2 = new List();
}
6、键值对:Map
创建Map:var language = {'first':''Dart,'second':'Java'};
创建不可变的Map:var language = const {'first':''Dart,'second':'Java'};
构造创建:var language = new Map();
常用的属性、操作:length、keys、values、forEach(遍历)、containsKey(是否包含某个key)......
asMap():把list转成map
🌰:
void main() {
var map0 = {"first":"Dart",1:true, true:666,"OC":null};// key 和 value 都可以是任意类型
print(map0["OC"]);// null
var map = {"first":"Dart","second":"Swift","third":"Java"};
map.forEach(func);
var list = ["Dart","Swift","Java"];
print(list.asMap()); // {0: Dart, 1: Swift, 2: Java}
}
void func(key,value) {
print("key = $key, value = $value");
}
7、dynamic(动态型)
🌰:
void main() {
var a;
a = 10;
a = "Dart";
dynamic b = 10; // dynamic 表示是动态类型 如果写int b = 10; b = "Dart"是会报错的 因为int b = 10 默认b就是int类型
b = "Dart";
}
二、运算符
1、算术运算符
常用的操作:+、-、*、/、~/、%
递增递减:++var、var++、--var、var--
🌰:
void main () {
int a = 1;
print(a + 1); // 2
print(a++); // 1
print(a); // 2
print(--a);// 1
}
2、关系运算符
运算符:==、!=、>、<、>=、<=
3、逻辑运算符
运算符:!、&&、||
4、赋值运算符
基础运算符:=、??=
复合运算符:+=、 -= 、/= 、*= 、%= 、~/=
🌰:
void main () {
int a = 10;
int b;
// ??= 表示如果有值就是原来的值 如果没有值就是赋的值
b ??= 20;
print(b); // 20
int c = 10;
c ??= 20;
print(c); // 10
print(a ~/= 5); // 2
}
5、条件表达式
三目运算符:?:
??运算符:expre1 ?? expre2 表示如果第一个表达式为nil 则取第二个表达式
🌰:
void main () {
String a;
String b = "Dart";
String c = a ?? b;
print(c); // Dart
}
三、控制语句
1、if 、if else
2、for 循环、for...in 语句
🌰:
void main () {
var list = [1,2,3,4,5,6];
for(int index = 0; index < list.length; index++) {
// print(list[index]);
}
for(var item in list) {
print(item);
}
}
3、while、do...while
🌰:
void main() {
int count = 0;
while(count < 5) {
print(count++); // 0 1 2 3 4
}
// count = 5
do {
print(count --);
}while(count > 0 && count < 5); // 5 4 3 2 1
}
4、break、continue
break:终止循环
continue:跳出当前循环
🌰:
void main () {
var list1 = [1,2,3];
var list2 = [4,5,6];
for(var item1 in list1) {
for(var item2 in list2) {
if(item2 == 5) {
// break; // 4 4 4
continue; // 46 46 46
}
print(item2);
}
}
}
5、switch...case语句
5.1 比较类型:num、String、编译期常量、对象、枚举
5.2 非空case必须有一个break
5.3 使用default来处理默认情况
5.4 可以用continue来加一个跳转标签(其他语言没有的)
🌰:
void main () {
String language = "Python";
switch(language) {
Test: // 标签随便定义的
case "Java":
print("Java");
break;
case "Dart":
print("Dart");
break;
case "Python":
print("Python");
continue Test;
// break;
default:
print("None");
}
// 输出结果是:Python、Java
}
四、方法
1、方法的定义
返回类型 方法名 (参数1,参数2...){
方法体...
return 返回值
}
2、方法特性
2.1 方法也是对象 并且具有具体的类型Function
2.2 方法的返回值、参数类型都可以省略
2.3 方法都有返回值 如果没有返回值默认是null
🌰:
void main (List args) {
printPerson("Sunny", 18); // 输出:name = Sunny,age = 18
}
printPerson (name, age) {
print("name = $name,age = $age");
}
2.4 箭头语法: => expre 是return{expre}的缩写 ⚠️:只适用于一个表达式
🌰:
void main (List args) {
print(printPerson("Sunny", 18)); // 输出:name = Sunny,age = 18
}
printPerson (name, age) => "name = $name,age = $age";
3、可选参数
3.1可选命名参数:{params1,params2,params3...}
3.2 可选位置参数:[params1,params2,params3...]
🌰:
void main () {
printPerson("Sunny",age: 20);
printPerson2("Sunshine",20,"Male");
}
// 可选命名参数{}
printPerson(String name,{int age, String gender}) {
print("name = $name, age = $age, gender = $gender"); // 打印结果:name = Sunny, age = 20, gender = null
}
// 位置可选参数[]
printPerson2(String name,[int age, String gender]) {
print("name = $name, age = $age, gender = $gender"); // 打印结果:name = Sunny, age = 20, gender = Male
}
⚠️:如果存在可选参数 可选参数必须要在必选参数后面
4、默认参数值
使用=在可选参数指定默认值 默认参数值只能是编译期常量
🌰:
void main () {
printPerson("Sunny",gender: "Male");
}
// 可选命名参数{}
printPerson(String name,{int age = 20, String gender = "Female"}) {
print("name = $name, age = $age, gender = $gender"); // 打印结果:name = Sunny, age = 20, gender = Male
}
5、方法对象
5.1 方法可以作为对象赋值给其他的对象
🌰:
void main() {
var func = printHello;
func();
List list = [1,2,3,4];
list.forEach(print);// 输出:1,2,3,4
void printHello() {
print("Hello Dart");
}
5.2 方法可以作为参数传递给其他方法
🌰:
void main() {
print(listPrint(["D","a","r","t"], timers)); // 打印结果:[DDD,aaa,rrr,ttt]
}
// 传入一个字符串 把这个字符串打印3次
String timers (str) {
return str * 3;
}
List listPrint(List list,timers) {
for(int index = 0; index < list.length; index++) {
list[index] = timers(list[index]);
}
return list;
}
6、匿名方法
匿名方法的特性:
6.1 可赋值给变量 通过变量来进行调用
6.2 可以在其他方法中直接调用或传递给其他的方法
(参数1,参数2) {
方法体
return 返回值
}
🌰:
void main () {
var func = (){
print("Hello Dart");
};
func();
print(listPrint(["1","2","3","4"], (str){ return str*3;}));// 打印结果:[111,222,333,444]
}
List listPrint(List list,timers) {
for(int index = 0; index < list.length; index++) {
list[index] = timers(list[index]);
}
return list;
}
7、闭包
闭包也是一个方法(对象),闭包定义在其他方法内部,闭包能够访问外部变量的局部变量 并持有其状态
🌰:
void main() {
var func = funca();
func(); // 0
func(); // 1
func(); // 2
}
funca () {
int count = 0;
printCount() {
print(count++);
}
return printCount;
}
也可以是下面的写法:
void main() {
var func = funca();
func(); // 0
func(); // 1
func(); // 2
}
funca () {
int count = 0;
return () {
print(count++);
};
}
五、Dart面向对象编程
1、类与对象
使用关键词class
来声明一个类
使用关键字new
来创建一个类 new
可忽略
所有的对象默认都继承Object
属性与方法:
默认会生成setter
和 getter
使用final
关键字声明的属性 只会生成getter
在Dart中方法是不能被重载的
类及成员的可见性:
在Dart中的可见性是一以library
为单位的
默认情况下 每一个Dart文件就是一个库library
使用表示库的私有性(表示属性、方法的私有性也是通过来表示的)
使用import
导入库
🌰:
import 'person.dart';
void main() {
var person = new Person();
person.name = "Sunny";
person.age = 18;
// person.bookName = "123";
person.work();
print(person.bookName);
}
// person.dart文件
class Person {
String name;
int age;
final String bookName = "《平凡的世界》";
void work() {
print("name = $name, age = $age, She is working...");// name = Sunny, age = 18, She is working...
}
}
⚠️:如果Person前面使用了_
就表示是私有,其他类就找不到这个类了
class _Person {
}
2、 计算属性
计算属性的值是通过计算得来的 本身并不存储值
计算属性赋值 其实是通过计算转换到其他的实例变量
🌰:
void main () {
var rect = Rectangle();
rect.width = 10;
rect.height = 20;
print(rect.area);
rect.area = 200;
print(rect.width);
}
class Rectangle {
num width;
num height;
// 计算属性getter
num get area {
return width * height;
}
// 计算属性setter
set area(value) {
width = value/ 10;
}
}
3、构造方法
如果没有自定义的构造方法,会有一个默认的构造方法
🌰:
void main() {
var person = new Person();
}
class Person {
// 默认的构造方法
Person () {
}
}
如果存在自定义的构造方法,则默认的构造方法就无效
自定义构造方法的写法一🌰:
void main() {
var person = new Person("Sunny", 18);
person.work();
}
class Person {
String name;
int age;
void work() {
print("name = $name, age = $age, She is working...");// name = Sunny, age = 18, She is working...
}
// 构造方法
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
自定义构造方法的写法二🌰:
void main() {
var person = new Person("Sunny", 18,"Female");
person.work();
}
class Person {
String name;
int age;
final gender;
void work() {
print("name = $name, age = $age, She is working...");// name = Sunny, age = 18, She is working...
}
Person(this.name, this.age,this.gender) {
print(this.gender);// Female
}
}
⚠️:如果对person的gender赋值,第一种构造方法就不能使用,因为不能对final
修饰的属性赋值,但是第二种构造方式是可以的,因为第二种的构造方法赋值是在构造方法之前
构造方法不能重载,但是可以使用重命名的构造方法
🌰:
void main() {
var person = new Person.withName("Sunny");
person.work();
}
class Person {
String name;
int age;
final gender;
void work() {
print("name = $name, age = $age, She is working...");// name = Sunny, age = 18, She is working...
}
Person.withName(this.name) {
print(this.name); // Sunny
}
}
4、常量构造方法
如果类是不可变的状态,可以把对象定义为编译时常量
使用const来声明构造方法,并且所有变量都是final
使用const声明对象,可以省略
🌰:
void main() {
const person = const Person("Sunny", 18,"Female");
person.work();
}
class Person {
final name;
final age;
final gender;
void work() {
print("name = $name, age = $age, She is working...");// name = Sunny, age = 18, She is working...
}
const Person(this.name, this.age,this.gender);
}
5、工厂构造方法
工厂构造方法类似于设计模式里面的工厂模式
在构造方法添加factory
实现一个构造方法
在工厂构造方法里面可以返回对象
🌰:
void main() {
var logger = Logger("Sunny");
print(logger.name);
}
class Logger {
final String name;
static final Map<String,Logger> _cache = <String, Logger>{};
factory Logger(String name) {
if(_cache.containsKey(name)) {
return _cache[name];
}else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
// 表示这个方法是私有
Logger._internal(this.name);
}
6、初始化列表
初始化列表会在构造方法之前执行
使用,
分隔初始化表达式
初始化列表常用于设置final
变量的值
🌰:
void main() {
// var person = new Person("Sunny", 18,"Female");
var person = new Person.withMap({"name":"Sunny","age":18});
person.work();
}
class Person {
String name;
final age;
final gender;
void work() {
print("name = $name, age = $age, She is working...");// name = Sunny, age = 18, She is working...
}
Person(this.name, this.age,this.gender);
Person.withMap(Map map):age = map["age"], gender = map["gender"] {
this.name = map["name"];
print("name = $name,age = $age,gender = $gender"); // name = Sunny,age = 18,gender = null
}
}
7、静态成员
使用 static
关键字来实现类级别的变量和函数
静态成员不能访问非静态成员,非静态成员可以访问静态成员
类中的常量需要使用static const
声明
🌰:
void main() {
var page = Page();
Page.scrollDown(); // 不能通过page.scrollDown()来调用
}
class Page {
static const maxPage = 10;
static int currentPage = 1;
// 下滑
static void scrollDown() {
currentPage = 1;
print("scrollDown...");
}
// 上滑
void scrollUp() {
currentPage++;
print("scrollUp...");
}
}
8、对象操作符
条件成员访问:?
类型转换:as
是否是指定类型:is is!
级联操作:..
🌰:
void main () {
// Person person;
// person.work();// 会报错 因为person是空
// person?.work(); // 不会报错 检查到person是nil 就不往下执行
// var person;
// person = "Sunny";
// person = new Person();
// (person as Person).work();
// if(person is Person) {
// print("person is Person...");
// }
// if(person is! Person) {
// print("person is String...");
// }
var person = new Person();
person..name = "Sunny"
..age = 18
..work();
}
class Person {
String name;
int age;
void work() {
print("working...");
}
}
9、对象call方法(不建议使用)
如果类使用了call()方法 则该类的对象可以作为方法使用
🌰:
void main() {
var person = new Person();
person("Sunny",18);
}
class Person {
String name;
int age;
call(String name,int age) {
print("name = $name, age = $age, She is working...");// name = Sunny, age = 18, She is working...
}
}
10、继承
使用extends
表示继承一个类
继承可以继承父类可见的方法和属性,不会继承构造方法
子类能够复写父类的setter 和 getter
单继承、多态
🌰:
void main() {
var student = new Student();
student.name = "Sunny";
student.age = 18;
print(student.isAdult);
student.study();
student.run();
}
class Student extends Person {
void study() {
print("Student is studying...");
}
@override
bool get isAdult => age >15; // 重写父类的方法
@override
void run() {
super.run();
print("Student is running...");
}
}
Person
:
class Person {
String name;
int age;
String _birthday;
bool get isAdult => age > 18;
void run () {
print("person is running...");
}
}
11、继承中的构造方法
子类的构造方法默认会去调用父类的无名无参的构造方法
如果父类没有无名无参的构造方法 则需要显式调用父类的构造方法
在构造方法参数后面使用:
显式调用父类的构造方法
🌰:
void main() {
var student = new Student("Sunny", 18,"Female");
}
class Person {
String name;
int age;
Person(this.name,this.age);
Person.initWithNameAndAge(this.name,this.age);
}
class Student extends Person {
final gender;
// 方式1
// Student(String name, int age) : super(name, age);// 使用快捷键可以自动补全
// 方式2
Student(String name, int age,String gender) :gender = gender, super.initWithNameAndAge(name,age);
// 方式3
// Student.initWithNameAndAge(String name, int age) : super.initWithNameAndAge(name,age);
}
⚠️:初始化列表和`super`的顺序不能交换 会报错
构造方法的执行顺序:父类的构造方法在子类的构造方法开始执行之前去调用
12、抽象类
抽象类使用 abstract
表示 不能直接被实例化
抽象方法不适用 abstract
修饰 无实现
抽象类可以没有抽象方法
有抽象方法的类一定得声明为抽象类
🌰:
void main () {
var student = new Student();
student.run();
}
abstract class Person {
void run();
}
class Student extends Person {
@override
void run() {
// TODO: implement run
print("Student is running....");
}
}
13、接口
在Dart中 类和接口是统一的 类就是接口
每个类都隐式定义了一个包含所有实例成员的接口
如果是复用已有类的实现 使用extends
如果只是使用已有类的一些外在行为 使用接口implements
🌰:
void main () {
var student = new Student();
student.run();
}
abstract class Person {
void run();
}
class Student implements Person {
@override
void run() {
print("Student is running...");
}
}
14、Mixins
Mixins 类似于 多继承 是在多继承中使用一个类代码的方式
Mixins不能有显式声明构造方法
Mixins的类只能继承自Object
使用关键字with连接一个或多个mixin
🌰:
void main () {
var d = new D();
d.a(); // 输出:C...a 跟mixins顺序有关 最后是C 所以会输出C类里面a的打印
}
class A {
void a() {
print("A....a");
}
}
class B {
void a() {
print("B....a");
}
void b() {
print("B....b");
}
}
class C {
void a() {
print("C....a");
}
void c() {
print("C....c");
}
}
// 现在 如果希望一个类D 能够有ABC三个类的方法
class D extends A with B,C {
}
15、操作符覆写
覆写操作符需要在类中定义:
返回类型 operator 操作符 (参数1,参数2...) {
实现体
return 返回值
}
如果需要覆写 == 还需要覆写对象的hashCode getter方法
🌰:
void main () {
var person1 = new Person();
person1.age = 18;
var person2 = new Person();
person2.age = 20;
print(person1 > person2); // false
}
class Person {
int age;
// 覆写操作符
bool operator > (Person person) {
return this.age > person.age;
}
}
六、枚举和泛型
1、枚举
枚举是一种有穷序列集的数据类型
使用关键字 enum 来定义一个枚举
常用于代替常量 和 控制语句
Dart中枚举特性:
index 从0开始 依次累加
不能指定原始值
不能添加方法
🌰:
void main() {
var cuurentSeason = Season.Summer;
switch(cuurentSeason) {
case Season.Spring:
print("Spring...");
break;
case Season.Summer:
print("Summer...");
break;
case Season.Automn:
print("Automn...");
break;
case Season.Winter:
print("Winter...");
break;
Default:
print("None...");
}
}
enum Season {
Spring,
Summer,
Automn,
Winter
}
2、泛型
Dart中类型是可选的 可使用泛型指定类型
使用泛型能有效的减少代码的重复
类的泛型
方法的泛型
🌰:
void main () {
var utils = new Utils();
utils.put<String>("Sunny");
utils.put<int>(1);
}
class Utils {
void put<T>(T element) {
print(element);
}
}