Vscode
Vscode上练习dart 安装这三个插件
flutter dart Code Runner
Ctrl+Alt+n 执行 C
基本语法
声明变量
类型推导(var/final/const)
类型推导方式虽然没有明确的指定变量类型,但是变量是有自己明确的类型
var
var age = 20;
// age = "aaa" 声明过后可以改变值 但是不能改变类型
age = 30;
final
final height = 1099;
// height = 2000;
const 常量声明
const add = 'szs';
// add = 'gzs'
const 和 final 的区别
const 必须赋值 在声明期间;常量值(编译期间需要有一个确定的值)
final 可以通过计算/函数获取一个值(运行期间来去确定一个值) 可以先声明后赋值
const data1 = DateTime.now(); //DateTime.now()这个函数需要运行的时候才会返回一个值 所以不能使用const error
final data2 = DateTime.now(); // final 就可以先声明 等他计算出来结果时再赋值
final的更多用法
main(List<String> args){
//Dart2.0之后,new可以省略
//final p1 = new Person("penny");
final p1 = Person("penny"); //只要就表示我们创建了Person对象
final p2 = Person("penny");
// 判断 p1 和 p2 是否为同一个对象?
// 不是同一个对象,因为使用了两次new,在内存内分配了两个Person对象,用两个不同的指针对象这两个对象
print(identical(p1, p2)); //identical()用于判断两个对象是否相同
//在我们开发当中我们可能会遇到这种需求,当我们传入相同的信息时,在不同的地方new这个对象的时候可以创建出来同一个对象,类似于单例模式,我传入相同属性的时候,创建同一个对象
}
class Person{
Stirng name;
Person(String name){
this.name = name
}
}
当我们将final换成const时
我希望我传入 penny 你可以给我创建同一个对象
当我们把鼠标放到报错上时
- 第一个错误显示,const这个变量必须被初始化一个常量
- 第二个错误(红色线条画出来的部分),当前的构造函数被调用的时候不是常量构造函数
const 可以接受一个常量也可以通过构造器创建对象但是有要求构造器本身得用 const 进行修饰
当我们在构造器上加上 const 时就会发现 声明变量时不会报错了
但是构造器上会报错
报错信息
不能定义一个常量构造器为一个类(不包括final的成员变量)
就是说Person这个函数里的构造函数是const意味着里面的所有成员必须使用final进行修饰的
还是会报错
我们将他改写成这样
这样我们在创建构造函数时,我们就能创建同一个对象当传入的属性值相同时 (const可以省略下图中的代码 Dart2.0之后,const可以省略)
print(identical(h1, h2)); // true
print(identical(h1, h3)); // false
这样有利于我们节省堆内存
字符串
定义字符串
var str1 = 'abc';
var str2 = "abc";
var str3 = """
asd,
asd,
asd
""" //可以换行
字符串和表达式进行拼接
var name = "penny";
var age = 18;
var height = 1.99;
// 强调:${变量} 那么{}可以省略 表达式不可以省略
// runtimeType 可以判断变量类型
var msg1 = "my name is $name, age is $age, height is $height";
var msg2 = "my us ${name}, type is ${name.runtimeType}";
print(msg1);
print(msg2);
集合
-
列表 List : [];
var names = ["asd","zxc","Qwe"]; name.add('aaaa') -
集合 Set : {}
var Cloud = {"七牛云",“阿里云”,"腾讯云"} //set用得比较多的地方就是去除数组当中重复的元素 names = Set<String>.from(names).toList(); -
映射Map
var info = { "name":"penny", "age":19 }
函数的使用
基本使用
main(List<String> args) {
print(sum(10, 20));
}
int sum(int num1, int num2) {
return num1 + num2;
}
dart当中没有函数的重载
函数的可选参数
main(List<String> args){
say("penny");
}
// 必选参数:必须传
void say(String name) {
print(name);
}
可选参数: 位置可选参数 - 命名可选参数
只有可选参数才有默认值
位置可选参数: [int age , double height]
实参和形参在进行匹配时,是根据位置匹配的 []里的可传可不传 如果有的话 按照位置在传
main(List<String> args){
say2("penny",18,1.99); //必须按照顺序传值
}
void say2(String name, [int age, double height]) {
print("name is $name , age is $age");
}
命名可选参数
可以乱序的传入参数
main(List<String> args){
sa3y("penny",content:"Hello World",age:13);
}
void say3(String name, {int age, String content}) {
print("name is $name , return $age");
}
参数默认值
可选参数才能设置默认值
void say2(String name, [int age = 15, double height = 2.11]) {
print("name is $name , age is $age");
}
void say3(String name, {int age = 17, String content = “Hello Flutter}) {
print("name is $name , return $age");
}
函数是一等公民
函数A可以作为另外一个函数的参数,也可以作为函数的返回值
函数可以作为另外一个函数的参数
main(List<String> args){
test(bar);
//匿名函数
test((){
print('匿名函数被调用')
});
//箭头函数:条件:函数体只有一行代码
test(() => print("箭头函数被调用"));
}
void test(Function foo){
foo();
}
void bar(){
print("bar函数被调用");
}
希望别人传入的参数既要有参数又要有返回值
main(List<String> args){
test((){}); //报错 没有传入参数
test((num1,num2){
return num1 + num2;
});
}
//函数签名
void test(int foo(int num1 ,int num2)){
foo(20.30);
}
// typedef 可以增强开发的阅读性
typedef Calculate = int Function(int num1, int num2);
void test(Calculate calc){
calc(20,30)
}
函数作为返回值
main(List<String> args){
var demo1 = demo()
print(demo1(20,30))
}
Calculate demo(){
return (n1,.n2){
return num1 * num2
}
}
特殊运算符
??=
当原来的变量有值时,那么??= 不执行
原来的变量为null时,那么将值赋给这个变量
var test = null;
test ??= "参数为null,已改变";
print(test);
??
??前面的数据有值时。那么就使用??前面的数据
??前面的数据为null,那么就使用后面的值
var test2 = null;
var temp = test2 ?? "已改变??";
print(temp);
级联运算符
main(List<String> args) {
// 一般的写法
// var p = Person();
// p.run();
// p.eat();
// 级联运算符 链式调用
var p = Person()
..name = "penny"
..eat()
..run();
}
class Person {
String name;
void run() {
print("running");
}
void eat() {
print("eating");
}
}
面向对象
类的定义
main(List<String> args) {
var p = Person("penny", 18);
}
class Person {
String name;
int age;
// Person(String name, int age) {
// this.name = name;
// this.age = age;
// }
// dart 提供了语法糖
Person(this.name, this.age);
}
类的构造函数
main(List<String> args) {
// 创建Person对象
// var p = Person();
// Object和dynamic的区别
// 父类应用指向子类对象
// Oject调用方法时,编译时会报错
// dynamic调用方法时,编译时不报错,但是运行时会存在安全隐患
// Object
// Object obj = "penny";
// print(obj.substring(1));
// dynamic 明确声明
// dynamic obj = "aaa";
// print(obj.substring(1)); //substring(1) 表示将obj这个变量的值 减去一位值 "aa"
var a = Person.formMap({
"name": "penny",
"age": 18,
"height": 1.99
});
print(a);
}
class Person {
String name;
int age;
double height;
Person(this.name, this.age);
// 命名式构造函数
Person.withNameAgeHeight(this.name, this.age, this.height);
Person.formMap(Map<String, dynamic> map) {
this.name = map["name"];
this.age = map["age"];
this.height = map["height"];
}
// type 'String' is not a subtype of type 'int'
// 需要重写toString
@override
String toString() {
return "$name $age $height";
}
}
dynamic
任意类型 -> typescript当中的any
dynamic是一种明确的声明,不是推导类型
dynamic 调用方法时,编译时不报错,但是运行时会存在安全隐患
所有的类都继承自Object
类的初始化列表
-
main(List<String> args) { var p = Person("penny"); } class Person{ String name; int age = 10; //可以让age有一个初始化的值 但是是定义死的 不可改变 Person(this.name){ this.age = age } } -
main(List<String> args) { var p = Person("penny"); } class Person{ final String name; final int age; Person(this.name){ this.age = 10; //这段{this.age = 10}执行之前,已经完成了初始化 所以使用了final进行修饰的时候 不能在这里赋值 } } -
main(List<String> args) { var p = Person("penny"); } const temp = 20; class Person{ final String name; final int age; Person(this.name,{int age}):this.age = temp > 20? 30 : 50 { //这种赋值方式和第四钟方法的区别就是可以写入表达式 } } -
main(List<String> args) { var p = Person("penny"); } const temp = 20; class Person{ final String name; final int age; Person(this.name,{this.age=10}); //这里只能赋值一个确定的值 // {this.age=10} 这个位置只能做赋值操作 {this.age = temp ?? 30} 这种也是一个赋值语句 }
工厂构造函数
Dart提供了factory关键字,用于通过工厂去获取对象
普通的构造函数,会默认返回创建出来的对象,不能手动返回
工厂构造函数,需要(可以)自己手动的返回一个对象,也是最大的特点
//需求:传入相同的name时,那么返回同一个对象,传入相同的color时,返回同一个对象
main(List<String> args) {
}
class Person{
String name;
String color;
//常量构造函数一般类当中只有一个
Person(String )
}
main(List<String> args) {
final a1 = Person.withName("penny");
final a2 = Person.withName("penny");
print(identical(a1, a2));
}
class Person{
String name;
String color;
// Person(String name);
static final Map<String,Person> _nameCache = {};
static final Map<String,Person> _colorCache = {};
factory Person.withName(String name){
if(_nameCache.containsKey(name)){
return _nameCache[name];
}else{
final p = Person(name,'default');
_nameCache[name] = p;
return p;
}
}
factory Person.withColor(String color){
if(_colorCache.containsKey(color)){
return _colorCache[color];
}else{
final p = Person("default",color);
_colorCache[color] = p;
return p;
}
}
Person(this.name,this.color);
}
类的继承
main(List<String> args){
}
class Animal{
int age;
Animal(this.age)
}
class Person{
String name;
Person(this.name,int age):super(age);
}
抽象类
继承自抽象类后,必须实现抽象类的抽象方法
抽象类不能实例化
main(List<String> args){
var p = Reatangle();
print(p.getInfo());
}
abstract class Shape{
void getArea(); //可以放方法的声明 未实现也行 普通的类不可以
String getInfo(){
return "形状";
}
}
//继承自抽象类后,必须实现抽象类的抽象方法
class Reatangle extends Shape{
@override
int getArea(){
return 10;
}
}
关键字external 的作用,将方法的声明和实现分离
方法的实现用到了一个关键字 @patch
mixin混入
混入的写法
- 定义可混入的类时,不能使用
class, 使用mixin - 使用
with进行混入
类属性和类方法
main(List<String> args) {
}
class Person{
// 成员变量
String name;
// 静态属性(类属性)
static String courseTime;
// 对象方法
void eating(){
print('eating');
}
// 静态方法(类方法)
static void gotoCourse(){
print('gotoCourse');
}
}
库的导入
Dart当中默认情况下,一个dart文件就是一个模块(库文件)
import 语句用来导入一个库,后面跟着一个字符串形式的URI来指定表示要引用的库
import '库的url'
export 关键字
官方已经不推荐使用 part 关键字,如果库非常的巨大,如何管理呢?
将每一个dart文件作为库文件,使用 export 关键字在某一个文件中单独导入
_ 下划线 关键字 是用来区分私有和公有的一种方式
补充
- @require 必须的,