Flutter中的Dart语法

2.1 基础语法介绍

使用VScode学习Dart语言,需要安装几个插件

  • Dart
  • Flutter
  • codeRunner 方便运行Dart

必须有一个main入口函数



//执行dart语法必须要有一个main函数
 main(List<String> args) {
  //在终端运行dart的时候可以参入参数
  //这个参数就是通过args传递的
  //终端命令 dart 名称  参数

  // List<String> args 支持泛型 <String> 

 print('hello word');
  
}

2.1.1 变量

变量的声明有2种大的方式

1.根据类型直接声明 String name = "CC"

2.自动推导类型 var age1 = 20; *//类型自动推导,int

var 声明变量

const 声明常量,声明的时候必须赋值

final也是声明常量,但是可以声明的时候不赋值,一旦赋值就不可以改变了


 //声明变量
 // 1.明确的声明
// 变量类型 变量名称 = 赋值;
String name = "cc"; 
int age = 18;
//拼接字符串
print('我的名字是:${name},年龄是:${age}');

//2.自动推导类型(var/final/const )

var age1 = 20; //类型自动推导,int
print(age1);

// 3.final const声明常量

final str = "AA";
const str1 = "BB";

print('${str},${str1}');
// 区别:
// const 必须赋值 常量值,赋值的内容必须是在编译期间就确定下来的
// final 在赋值时, 可以动态获取, 比如赋值一个函数
// final可以先声明,后赋值

final person = Person("CC");
print(person);

//如果是用const来声明类的话
// 必须是 构造器方法是const修饰才可以
//类的内部属性必须是 final修饰

const stu = Student("TTT");
const stu1 = Student("TTT");
//此时 stu stu1是同一个对象
//但是当构造器 初始化的时候 name不相同就不是同一个对象 
print(identical(stu,stu1));  // true 说明返回的是同一个对象


//定义一个类Pseron
class Person {
  String name;
  Person(String name){
    this.name = name;
  }
}


class Student {
  final String name;
  const Student(this.name);
}

2.1.2 数字类型

对于数值来说,我们也不用关心它是否有符号,以及数据的宽度和精度等问题。只要记着整数用int,浮点数用double就行了。

不过,要说明一下的是Dart中的intdouble可表示的范围并不是固定的,它取决于运行Dart的平台。

// 1.整数类型
  int age = 18;
  int hexAge = 0x12;
  print(age);
  print(hexAge);
// 2.浮点类型
 double height = 1.88;
 print(height);

字符串和数字之间的转化:

// 字符串和数字转化
// 1.字符串转数字
 var one = int.parse('111');
 var two = double.parse('12.22');
 print('${one} ${one.runtimeType}'); // 111 int
  print('${two} ${two.runtimeType}'); // 12.22 double
// 2.数字转字符串
 var num1 = 123;
var num2 = 123.456;
var num1Str = num1.toString();
var num2Str = num2.toString();
var num2StrD = num2.toStringAsFixed(2); // 保留两位小数
print('${num1Str} ${num1Str.runtimeType}'); // 123 String
print('${num2Str} ${num2Str.runtimeType}'); // 123.456 String
print('${num2StrD} ${num2StrD.runtimeType}'); // 123.46 String

2.1.3 布尔类型

布尔类型中,Dart提供了一个bool的类型, 取值为true和false

// 布尔类型
var isFlag = true;
print('$isFlag ${isFlag.runtimeType}');

注意:Dart中不能判断非0即真, 或者非空即真

Dart的类型安全性意味着您不能使用if(非booleanvalue)或assert(非booleanvalue)之类的代码。

  var message = 'Hello Dart'; 
   // 错误的写法 
    if (message) {   
     print(message) 
     }

2.1.4 字符串类型

Dart字符串是UTF-16编码单元的序列。您可以使用单引号或双引号创建一个字符串:

// 1.定义字符串的方式
var s1 = 'Hello World';
var s2 = "Hello Dart";
var s3 = 'Hello\'Fullter';
var s4 = "Hello'Fullter";

可以使用三个单引号或者双引号表示多行字符串:

// 2.表示多行字符串的方式
var message1 = '''哈哈哈呵呵呵嘿嘿嘿''';

  var str = """ 
      多个字符串,换行操作,
      1.这是一个字符串
      2.你是谁
      3.哈哈哈 
   """;

字符串和其他变量或表达式拼接: 使用`${expression}, 如果表达式是一个标识符, 那么{}可以省略

// 3.拼接其他变量
var name = 'coderwhy';
var age = 18;
var height = 1.88;
print('my name is ${name}, age is $age, height is $height');

2.2集合类型

2.2.1 List列表

类型推导定义List列表

   // 类型推导
   var list1 = ['a','b','c'];
   //里面装的事字符串
   print(list1);

明确的类型定义List列表


 // 明确的类型
   //明确的int类型
   List<int> list2 = [1,2,3,4];
   print(list2);

2.2.2 Set集合

Set:无序,元素不能重复的集合

  //自动推导
  var lset = {'q','w','g'};

   print('$lset,${lset.runtimeType}');
 //明确类型
  Set<int> set2 = {1,2,3,4,5};

  print(set2);

利用Set的特性给list去重

  //创建一个String的列表
  List<String> names = ["张三","李四","王二","张三","王二"];
 //利用Set迭代器 泛型String 
  names = Set<String>.from(names).toList();
  print(names);
 // [张三, 李四, 王二]
在这里插入图片描述

2.2.3Map映射

Map类似iOS中的字典

 //自动推动
  var dic = {'name':'cc','age':'18'};

   print('$dic,${dic['name']}');

  //明确类型 里面字符串和对象
   Map<String,Object> info = {'name':'TT'};

   print(info);

2.2.4 几个中常见的操作

长度的获取


//1.获取长度  length
    print('lsit的长度:${list1.length}');
    print('Set的长度:${lset.length}');
    print('Map的长度:${info.length}'); 

增删改查


// 增加的元素的时候  注意类型要一致
  list1.add('cvb');
  print(list1);

  //删除
  list1.remove('a');
  list1.removeAt(0);

  print(list1);

  //是否包含摸个元素
  var isn = list1.contains('cvb');
  print(isn);

 //Map映射的
  //根据key获取元素

 print(dic['name']);

// 获取所有的 entries
print(dic.entries); // (MapEntry(name: cc), MapEntry(age: 18))
//获取第一个
var entry = dic.entries.first;
print(entry.key);

2.3 函数

函数的基本定义


返回值 函数名称(参数列表) {函数体}

无参数 无返回值

void test1(){

  print("无参数 无返回值");
}


int sum(num num1, num num2) {
  return num1 + num2;
}

2.3.1参数类型

函数的参数可以分成两类:

必须参数

可选参数:命名可选参数位置可选参数

命名可选参数: {param1, param2, ...}
位置可选参数: [param1, param2, ...]

位置可选参数 [类型 参数名]

位置可选参数的 类型 必须是一致的


void test4(String name,[int age,double height]){
  print('姓名:${name},年龄:${age},身高:${height}');
}

//位置可选参数, 位置可选参数的 类型 必须是一致的
   test4('CC',18,17.0);

命名可选参数 {类型 参数名}


void test5(String name,{int age, double height}){
 print('姓名:${name},年龄:${age},身高:${height}');
}

// 
test5("TT",age:18,height:1.70);

默认值

只有可选参数,才可以设置默认值


// 3.3函数默认值, 只有可选参数才可以设置默认值
void test6([String name = "TT"]){
  print("name:${name}");
}


test6();

将函数 赋值给一个变量


void test1(){
  print("test函数");
}

var fn = test1;
  fn();

函数作为参数


//函数作为参数 
void test1(){
  print("test函数");
}

void fn1(Function func){

  func();
} 


fn1(test1);


函数作为参数,其函数有返回值 有参数


main(List<String> args) {

  //调用函数 函数有返回值 可以省略的
  test((int num1, int num2) {
    
    return num1 + num2;
  });

}

//重命名
typedef Calculate = int Function(int num1, int num2);


void test (Calculate calc){
  
  //  var result =  calc (20,30);
   final result =  calc (20,30);
   print(result);
   

}

匿名函数

 (){
    print("匿名函数");
  };

//函数作为参数 
void fn1(Function func){

  func();
} 

 //穿入一个匿名函数
 fn1((){
    print('匿名函数作为参数');
  });


函数作为返回值


//函数作为返回值
void getRutern(){
  print("函数作为返回值");
}

// 返回值
 Function getFunc(){
    return getRutern;
  }

 var fun1 = getFunc();
  fun1();


 var movies = ['盗梦空间', '星际穿越', '少年派', '大话西游'];

  // 2.使用forEach遍历: 有名字的函数
  printElement(item) {
    print(item);
  }
  movies.forEach(printElement);

  // 3.使用forEach遍历: 匿名函数
  movies.forEach((item) {
    print(item);
  });

 // 箭头函数 函数体里面只执行一句代码,在dart里面才可以使用箭头函数
  movies.forEach((item) => print(item));

2.4运算符

赋值运算符 ??=

如果name在声明的时候 没有赋值 是nil ,那么在使用 ??= 就可以赋值成功

如果name有值, ??= 就使用原来的值

 var name = "cc";
// 如果name在声明的时候 没有赋值 是nil ,那么在使用 ??= 就可以赋值成功
// 如果name有值, ??= 就使用原来的值
name ??= "TT";
print(name); // 打印的结果是:cc

  name = null;
  name ??= "BB";
  print(name); // 打印的结果是: BB

特殊运算符 ??

  // ?? 运算符类似swift中的 空盒运算符??
  //如果 temp有值 就使用temp的值
  //如果temp为null,就使用BMO
  var temp = "MM";
  var str = temp ?? "BMO";
  print(str);

级联语法


final p = Person()
  ..name = "CC"
  ..eat()
  ..test1();

  print(p);



class  Person {
  String name;

  void test1(){
    print("test1...");
  }

  void eat(){
    print("eat ----");
  }
  
  //重写描述性方法
  @override
  String toString() {
   
    return 'name:${this.name}';
  }
}

2.5类和实例

定义类

使用 class


main(List<String> args) {
   
   //类的定义 class
   var p = Person();

  print(p.name);


}

// 注意: 在定义类的时候,默认会有一个 构造器方法,没有参数
//一旦重写构造器方法,系统自带的就失效
class Person {
  //属性
  String name;
  //方法
  void eat(){
    print('吃东西');
  }


}

2.5.1 构造器


main(List<String> args) {

  //创建实例对象,自定义 构造函数
  var p = Person("CC",18);
  print(p); //  name:CC,age:18,height:null
  //通过 命名构造函数创建对象
  var p2 = Person.withArgement("tt", 18, 1.70);
  print(p2); // name:tt,age:18,height:1.7

  //通过命名构造函数 Map映射 创建对象

  var per = Person.fromMap({"name":"BB","age":17,"height":1.8});

  print(per); // name:BB,age:17,height:1.8


  
}

自定义构造器方法 和 命名构造器函数


class Person {
  String name;
  int age;
  double height;
  //自定义构造函数
  Person(String name, int age) {
    this.name = name;
    this.age = age;
  }
  //语法唐 构造函数
 // Person(this.name,this.age);
  
   // 命名构造函数
 Person.withArgement(String name, int age,double height){
   this.name = name;
   this.age = age;
   this.height = height;
 }
  
  // 命名构造函数2
 Person.fromMap(Map<String,Object> map){
   this.name = map["name"];
   this.age = map["age"];
   this.height = map["height"];
 }
  
  @override
  String toString() {
    
    return 'name:$name,age:$age,height:$height';
  }
  
 
  
}

2.5.1初始化表

在 构造函数后面使用 : 跟上一个语句,来完成初始化列表


// 类的 初始化列表

class Person {
// final修饰的成员变量,只能赋值一次,赋值会后不能在修改
 final String name;
 final int age;
 //final 修饰的变量,在构造函数 初始之前应该是有的值的
  
 // 初始化列表就是在 构造函数后面 使用 : 号,来初始化没有 赋值的变量
 Person(this.name,{int age}):this.age = age ?? 10 ;


}

注意:上面的构造函数,如果按照下面的方式写,是会报错的
原因: 构造函数在执行大括号{},里面的内容时,已经初始变化完毕,和final是有冲突的

Person(this.name){
 this.age = age;
}


2.5.2重定构造函数

重定向函数 就是 用一个构造函数 调用另外一个 构造函数

在一个构造函数中,去调用另外一个构造函数(注意:是在冒号后面使用this调用)


main(List<String> args) {
  
  // 自定义构造函数
  var per1 = Person("CC", 17);

  print(per1); // name:CC,age:17

 // 命名构造函数
  var per2 = Person.formName("BB");
  print(per2); // name:BB,age:18

}


class Person {
   String name;
   int age;

   //自定义构造函数
   Person(String name, int age) {
     this.name = name;
     this.age = age;
   }

   //重定向函数 就是 用一个构造函数 调用另外一个 构造函数
  // 命名构造函数
  // name传入 在定义的构造函数, 18赋值给age
   Person.formName(String name):this(name,18);


@override
  String toString() {
    // TODO: implement toString
    return 'name:$name,age:$age';
  }

}


2.5.3 常量构造函数

常量构造函数 是当 通过构造方法创建对象,传入的参数相同,返回的事同一个对象

条件:

1.属性变量用 final修饰*

2.构造器函数用const修饰*

3.在创建 对象时使用const创建 对象*

4.有const修饰声明的变量时,在创建对象的时候 const Person()中的const可以省略


main(List<String> args) {

  //
  var per1 = const Person("cc");

  var per2 = const Person("cc");

  // identical 函数 判断2个对象是否为 同一个对象
  print(identical(per1, per2));

  // 有const修饰声明的变量时,在创建对象的时候 const Person()中的const可以省略
  const stu1 = Student("CC");
  const stu2 = Student("CC");
  
   print(identical(stu1, stu2));
}



class Person {
  
  final String name;
 
  const Person(this.name);

}


class Student {
  final String name;
  const Student(this.name);
}

2.5.4 工厂构造函数

使用 factory 修饰,可以手动 返回一个 对象


//工厂构造函数
class  Person {
  String name;

 // 声明一个静态的 Map映射 字典
  static final Map<String,Person> _cache = <String,Person>{};
  //声明工厂方法
  factory Person(String name){
    
    //判断字典里面 有没有存储
    if (_cache.containsKey(name)) {
      
      return _cache[name];
    }else {
      final p = Person._instance(name);
      _cache[name] = p;
     return p;
    }

  }
 
  //命名构造函数
  Person._instance(this.name);


}

2.5.5 get和set方法


main(List<String> args) {

  var p = Person();
  // p.name = "tt"; 不会调用 set 方法
  p.setName = "CC";
  print(p.getName);

  var stu = Student();
  stu.name = "SS";

  print(stu.name);
  stu.eat();
  
}



class Person {
  String name;
  
  //get方法 返回值是String 没有()
  String get getName {
    print("进入get方法");
    return name;
  }

 //Set方法
  set setName(String name){
    print("进入set方法");
    this.name = name;
    
  }
 
  void eat(){
    print("person");
  }
  
}


// 继承 extends
class Student extends Person {
  
  @override
  void eat() {
    // TODO: implement eat
    super.eat();
    print("student");
  }

}

2.5.6 继承

关键字: extends
格式: class A类 extends B类 {} A继承与B


class Animal {

  int age;
  //父类有自定义的构造函数方法
  Animal(this.age);
  
}

class Person extends Animal {

  String name;
  // 1.子类的构造方法在执行前,将隐含调用父类的无参默认构造方法(没有参数且与类同名的构造方法) (父类没有自定义构造函数)

  //2.如果父类没有无参默认构造方法,则子类的构造方法必须在 初始化列表 中通过super显式调用父类的某个构造方法。(父类有自定义构造函数)
  Person(String name, int age): name = name,super(age);
  
}

2.5.7 抽象类

其实就是定义了方法的声明,没有实现,用abstract声明一个抽象类

  1. 抽象类不能实例化

  2. 抽象类中的抽象方法必须被子类实现, 抽象类中的已经被实现方法, 可以不被子类重写


//声明一个Person抽象类
abstract class Person {
  //声明了方法没有实现
   getName();
}


class Student extends Person {
  
  //给抽象类实现方法
  @override
  getName() {
    return "CC";
  }
}

//抽象类 不能实例化,但是可以间接实现
// 使用 工厂函数 初始化 它的一个子类

在前面的介绍中,我们知道abstract抽象类,不能实例化,但是如果可以让他实例化呢?
1.使用 工厂函数 factory,手动返回一个
2.external 方法的声明 和实现分离,声明,可以不实现
3.注解 @patch, 可以在要实现的地方,实现 external声明的方法

 //声明一个抽象类
 abstract class Person {
  //声明了方法没有实现
   getName();
  // 可以返回一个 抽象实例
  //external 标识方法声明,可以实现
  external factory Person();
}

class Student extends Person {
  
  //给抽象类实现方法
  @override
  getName() {
    return "CC";
  }

 //会报错 这个就是告诉 可以在需要实现的地方 实现工厂函数 
 @patch factory Person()=> Student();
}

隐式接口

每一个类相当于默认声明了一个接口,可以有其他的类来实现,给别人来实现的类要声明为 抽象类


//main函数
main(List<String> args) {

  var sup = SuperMan();
  sup.run();
  sup.fly();
  
}

//声明一个抽象类
abstract class Person {
  void run();
}

abstract class Flyer {
 void fly();
}

// implements 实现 Person,Flyer 里面的方法,用逗号隔开
class SuperMan implements Person,Flyer {
 
 @override
  void run() {

    print("超人会跑");
  }
  
  @override
  fly() {
   
    print("超人会飞");
  }
}

2.5.7 mixin混入

  1. 在通过implements实现某个类时,类中所有的方法都必须被重新实现(无论这个类原来是否已经实现过该方法)

  2. 一个类可能希望直接复用之前类的原有实现 要通过 Mixin混入,因为Dart中没有 多继承

  3. mixin可以定义声明一个类

  4. 通过mixin定义的类用于被其他类混入使用,通过with关键字来进行混入



main(){
  var p = SuperMan();
  p.run();
  p.fly();
}


//使用 mixin 定义类
mixin Runner {
  void run(){
    print("在奔跑");
  }
}


//mixin 定义类
mixin Flyer{
  void fly(){
    print("会飞");
  }
}

//superMan不用再实现 fly 和 run 方法 直接可以调用
class SuperMan with Runner,Flyer { }

2.5.8 类的成员和类的方法


main(List<String> args) {

   Person.run();
   Person.name = "CC";
  
}


class Person {
  static String name;
  static void run(){
    print("pppppppp");
  }
}

2.6 枚举


main(List<String> args) {
  
  print(Point.x); // Point.x

  // 枚举的属性 
  // 1.index 表示每个枚举常量的索引, 从0开始.
  // 2.values: 包含每个枚举值的List.
  print(Point.x.index); // 0

  print(Point.values); // [Point.x, Point.y]

   var list = Point.values;
   print(list.first); // Point.x

  
  
}

// 枚举
// 使用 enum定义枚举
// 格式 enum name { }  name是枚举的名称

enum Point {
  x,y
}

2.7泛型



main(List<String> args) {

  // 1.list重视用泛型

  var list = [1,'CVB',1.50];
  print(list.runtimeType); // List<Object> 泛型的是Object
  
  // 限制类型
  var list1 = <String>['as','ed']; 
  print(list1.runtimeType); // List<String> 明确类型是String

  // 类的泛型
  var p = Person("CC",18);
  print(p.runtimeType); // Person<String, int> 泛型了String 和 int


  //泛型方法的定义

  T getName<T>(List<T> ts){

    return ts.first;
  }

  var res = getName(['A','b']);
  print(getName.runtimeType); // <T>(List<T>) => T
  print(res);
  
}

// 泛型 :没有明确的类型,什么时候用到 什么时候确定类型


// T,M是泛型
class Person<T,M> {
   T name;
   M age;

   Person(this.name,this.age);

}


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345