Flutter开发之Dart语言

Dart是Flutter框架的官方开发语言,Flutter应用几乎完全使用Dart编写。Flutter的跨平台特性使得Dart在移动应用开发中非常受欢迎。Dart是面向对象的、类定义的、单继承的语言,支持面向对象编程,包括封装、继承和多态等特性;Dart支持接口(interfaces)、混入(mixins)、抽象类(abstract classes)、具体化泛型、可选类型。Dart中很多概念跟其他语言基本一致。

目录

一、常量与变量

1. 常量

2. 变量

二、数据类型

1. int、double、num

2. String

3. bool

4. List

5. Map

6.可空类型

7. 类型判断is

8.类型转换as

三、运算符

四、条件语句、循环语句

五、函数

1. 函数的定义

2. 函数的参数

2.1. 位置可选参数

2.2. 命名可选参数

2.3. 可选参数默认值        

3. 匿名函数

六、类

1. 类的定义

2.类的属性

2.1 实例变量

2.2 私有变量

2.3 静态变量

3.类的构造函数

3.1 默认构造函数

3.2 普通构造函数

3.3 命名构造函数

3.4 工厂构造函数

3.5 常量构造函数

3.6 重定向构造函数(构造函数传递)


一、常量与变量

1. 常量

Dart的常量使用 const 和 final 修饰,赋值后不可更改。

const‌:必须在声明时赋值,且值在编译时确定(编译常量),不能是计算值;

final‌:可以在声明时赋值;也可以选择不赋值,后续赋值,只可赋值一次。

        编译常量:可以在编译时就能确定其值,那么可以将其视为编译时常量
        运行时常量:计算值,即在被使用到的时候才会进行初始化

void main() {//程序入口方法
  const p = 3.14;//定义时必须初始化,编译常量
  final q; q = 3.14;//可以后赋值,编译常量
  final time = new DateTime.now();//可以用方法返回值赋值,运行时常量
  print(time);//每次打印时time被初始化打印当前时间
}

2. 变量

通过var关键字声明变量(类型推断),也可通过显式类型String,int等来声明

  String name; int age;//显式类型定义
  String? name2; int? age2;//使用?来声明可空类型,变量可以赋值为null。
  var myName = 'lucy';//赋值后类型确定
  var map = {'key':'value'};//定义Map、List对象类型
  var studentName, studentAge, studentHeight;//同时声明多个变量,用逗号分隔

二、数据类型

Dart是一种面向对象、强类型的程序设计语言,所有类型都是对象。常见的数据类型有int,double,num,String,bool,List,Map,null

1. int、double、num

num为int、double的父类,可以赋值任意数字类型

  int x = 2;
  double y = 2.5;
  double y2 = 3;// 即使没有小数部分,也默认为double类型
  print(y2);//打印结果:3.0

  //num是int和double的父类,它可以存储任何数值(整数和浮点数)
  num z = 2;//num赋值后类型可变,随值类型可变化
  print(z.runtimeType);//打印结果:int
  z = 2.5;//num赋值后类型可变,随值类型可变化
  print(z.runtimeType);//打印结果:double

2. String

字符串String定义可以使用单引号、双引号、单三引号、双三引号,其中三引号可以定义换行的字符串。

  String s1 = 'this is str1';
  String s2 = "this is str2";
  String s3 = '''this is str3''';
  String s4 = """this is str4
  this is str4
  this is str4""";//这将允许您在字符串中直接嵌入换行符,而不需要使用 \n。
  print(s4);//打印结果会换行打印

字符串常见操作如下:

  //1.字符串拼接
  String str1 = 'Hello, ';
  String str2 = 'World!';
  String pinjie1 = str1 + str2;//方式1,打印结果:Hello, World!
  String pinjie2 = '$str1$str2';//方式2,打印结果:Hello, World!
  //2.字符串长度、字符串大小写
  var str = 'Hello, World!';
  var length = str.length; //长度,打印结果:13
  var upper = str.toUpperCase(); // 打印结果:'HELLO, WORLD!'
  var lower = str.toLowerCase(); // 打印结果:'hello, world!'
  //3.字符串分割
  var names = 'jack,lucy,lili';
  var nameList = names.split(', '); // 打印结果:[jack,lucy,lili]
  //4.判断包含
  var test = 'Hello, World!';
  var index = test.indexOf('X'); // 判断字符串位置,为-1不包含
  var isHasX = test.contains('Hello');//打印结果:true
  //5.字符串替换、截取
  var newStr = test.replaceAll('World', 'Dart'); // 'Hello, Dart!'
  var substring = newStr.substring(7, 12); //substring接受一个或两个参数:一个是开始索引,另一个是可选的结束索引。
  var substring2 = newStr.substring(7); //只提供开始索引,则substring会从开始索引到字符串末尾提取子串。
  print(substring);//打印结果:Dart!

3. bool

同其他语言一致,使用bool、var定义

  bool isTrue = true;
  var isFalse = false;
  if(isTrue){
    print(isFalse);//false
  }

4. List

List 是一个有序的集合[ ],可以包含重复的元素。可以通过索引来访问和修改列表中的元素。与之对应的Set不常用,为无序的,不可重复集合{ }.

List常用操作如下:

  //1.创建List
  var list = [1, 2, 3]; // var创建一个List
  List list2 = ['Hello', 'World']; // 创建一个指定类型的List
  //2.添加
  list.add(4);//末尾添加元素[1, 2, 3, 4]
  list.insert(1, 5);//在指定索引插入元素 [1, 5, 2, 3, 4]
  //3.删除
  list.remove(4);//删除指定元素[1, 5, 2, 3]
  list.removeAt(1);//删除指定位置[1, 2, 3]
  //4.连接
  var newList = list + [9,8,7];//[1, 2, 3, 9, 8, 7]
  //5.排序
  newList.sort();// [1, 2, 3, 7, 8, 9]
  //6.遍历
  newList.forEach((element) {
    print(element);//123789
  }); // 遍历List中的所有元素

5. Map

Map 是一种集合类型,用于存储键值对形式的数据。

  //1.创建Map
  var map1 = {
    'key1':'value1',
    'key2':'value2',
  };
  Map map2 = Map();
  //2.添加键值对
  map1['key3'] = 'value3';
  map1.addAll({
    'key4':'value4',
    'key5':'value5'
  });
  //3.删除键值对
  map1.remove('key1');
  //4.判断包含
  map1.containsKey('key1');
  //5.遍历
  map1.forEach((key, value) {
    print('$key: $value');
  });

6.可空类型

使用 ? 后缀可以创建可空类型,允许变量可能为 null。例如:String?、int?

使用??、!取出其值;

使用?. 、!.来访问它的属性或调用它的方法;

  String? name = 'lucy';
  String displayName = name ?? 'lucy2';//??判断name是否为空,不为空取出name值;为空,将lucy2赋值给displayName
  String displayName2 = name!;//非空断言,已知非空,取出name值
  print(name?.length);//name为空不会调用方法,不会异常
  print(name!.toUpperCase());//非空断言,已知非空,调用方法;若为空使用!异常

7. 类型判断is

is运算符来检查一个对象是否是特定类型的实例。如果对象是指定类型的实例,is运算符将返回true,否则返回false

  var num = 123;
  // 检查num是否是String类型的实例
  if (num is String) {
    print('num是String类型');
  } else {
    print('num不是String类型');
  }

8.类型转换as

类型转换通常使用as关键字进行。as为强制转换,如果转换失败,会抛出异常,应确保类型正确;

  dynamic value = "123"; // 假设这是一个可能是字符串也可能是其他类型的变量
  // int number = value as int; // 尝试将其转换为int类型,异常
  if (value is String) {
    String values = value as String;
  }

常用的数字与字符串之间的转换

  String integerString = '12345';
  String doubleString = '123.45';
  int integerValue = int.parse(integerString);// 转换为整数输出: 12345
  double doubleValue = double.parse(doubleString);// 转换为双精度浮点数 输出: 123.45
  String newIntegerString = integerValue.toString();
  String newDoubleString = doubleValue.toString();

三、运算符

Dart支持一般语言的运算符:

        算术运算符:加法 +、减法 -、乘法 *、除法 /、取余 %、取整 ~/

        关系运算符:等于 ==、不等 !=、大于 >、小于 <、大于等于 >=、小于等于 <=

        逻辑运算符:取反!、且 &&、或 ||   

        复合赋值运算符(+=,-=,*=,/=,%=,~/=,??=)

        三目运算( ?:)、??运算、as(类型转换),is(类型判断)

  String? name;
  name ??= 'test';//如果左边的操作数为null,则将其赋值为右边的操作数;否则保持不变。
  name = name ?? 'test2';//与上同
  print(name);//test

四、条件语句、循环语句

Dart支持一般语言的条件语句、循环语句:

        条件语句:if.. else..    switch.. case..

        循环语句:for..  while.. do..while..

不再赘述

五、函数

Dart 中的函数与一般语言的函数定义相同。

1. 函数的定义

  返回类型  方法名称(参数1,参数2,...){
    方法体
    return 返回值;
  }

2. 函数的参数

在Dart中函数的参数有一些新的定义

2.1. 位置可选参数

位置可选参数:在参数中用中括号[ ] 包含的参数,一般写在默认参数后方;调用的时候可以不带[ ]中的参数,也可以按序带上[]上的部分或全部参数;([]内不可跳跃传参)

  String getName(String name,[int? age, String? sex]){
    return "name : $name   ;    age : $age    ;    sex : $sex";
  }
  String test1 = getName('xiaoming');// name : xiaoming   ;    age : null    ;    sex : null
  String test2 = getName('xiaoming',18);//xiaoming   ;    age : 18    ;    sex : null
  // String test3 = getName('xiaoming','男');//报错,传参错误
  String test4 = getName('xiaoming',null,'男');//xiaoming   ;    age : null    ;    sex : 男
  String test5 = getName('xiaoming',18,'男');//xiaoming   ;    age : 18    ;    sex : 男
2.2. 命名可选参数

命名可选参数:在参数中用{ }包含的参数,一般写在默认参数后方;调用的时候可以不带{}中的参数,也可以带上{}上的部分或全部参数;(需要传递参数名)

  String getName(String name,{int? age, String? sex}){
    return "name : $name   ;    age : $age    ;    sex : $sex";
  }
  String test1 = getName('xiaoming');//xiaoming   ;    age : null    ;    sex : null
  String test2 = getName('xiaoming',age: 18);//xiaoming   ;    age : 18    ;    sex : null
  String test3 = getName('xiaoming',sex: '男');// xiaoming   ;    age : null    ;    sex : 男
  String test4 = getName('xiaoming',age: 18,sex: '男');//xiaoming   ;    age : 18    ;    sex : 男
2.3. 可选参数默认值        

可选参数可以通过"="赋一个默认值;默认值在该参数传参后更改

  String getName(String name,[int age = 20, String? sex]){
    return "name : $name   ;    age : $age    ;    sex : $sex";
  }
  String test1 = getName('xiaoming');// name : xiaoming   ;    age : 20    ;    sex : null
  String test2 = getName('xiaoming',18);//name : xiaoming   ;    age : 18    ;    sex : null

  String getName2(String name,{int age = 20, String? sex}){
    return "name : $name   ;    age : $age    ;    sex : $sex";
  }
  String test3 = getName2('xiaoming',sex: '男');// name : xiaoming   ;    age : 20    ;    sex : 男
  String test4 = getName2('xiaoming',age: 18,sex: '男');// name : xiaoming   ;    age : 18    ;    sex : 男

3. 匿名函数

Dart 中的函数也是对象,并且有它的类型 Function 。 这意味着函数可以被赋值给变量或者作为参数传递给其他函数。

匿名函数,顾名思义,即是没有名字的函数

  Function f = (String name){
    var t = 'name:' + name;
    print(t);
  };
  f('xiaoli');//name:xiaoli

在传参的时候,把匿名函数作为参数传递,内部调用该函数,实现回调功能。

六、类

1. 类的定义

在Dart中,定义一个类可以使用class关键字,后面跟着类名,然后是类体,包含在一对花括号中。类体内部可以包含属性、构造函数、自定义方法。

class Person {
  //自定义属性(又名实例属性、实例变量、成员变量)
  String? name;
  int? age;

  //自定义方法
  getInfo(String? sex){
    print('name:$name  age: $age  sex:$sex');
  }
}

2.类的属性

类的属性用于存储对象的状态或数据,可以是实例变量、私有变量、静态变量。

2.1 实例变量

所有实例变量都会生成一个隐式的getter、setter方法。所有未初始化的实例变量的默认值都为null。实例变量需要保证空安全,需要加?可空类型或者late延迟初始化。

可以使用get、set关键字添加新的getter、setter,不影响原getter、setter。

class Person {
  //保证空安全:实例属性需要加可空标志?或者 late(延迟初始化)
  String? name;
  int? age;//变量可空标志?
  late String sex;//变量延迟初始化
  late final String nickName;//常量必须初始化或添加late,只可赋值一次

  get myName{
    return name;
  }//用get修饰的方法块,使用的时候通过调用属性的方式使用

  set shezhiName(newName){
    name = newName;
  }//通过“对象.属性 = 值”的方式调用set修饰的方法体

  //自定义方法
  getInfo(String? sex){
    print('name:$name  age: $age  sex:$sex nickName:$nickName');
  }
}

  var person = Person();
  person.name= 'lucy';
  person.nickName = 'baobao';//final修饰可以被初始化一次
  person.getInfo(null);// name:lucy  age: null  sex:null nickName:baobao

  print(person.myName);//打印结果:lucy  用get修饰的方法块,使用的时候通过调用属性的方式使用
  print(person.name);//打印结果:lucy 添加get方法不影响原get

  person.shezhiName = 'jack';//通过“对象.属性 = 值”的方式调用set修饰的方法体
  print(person.name);//打印结果:jack
  person.name = 'leilei';
  print(person.name);//打印结果:leilei 添加set方法不影响原set
2.2 私有变量

私有属性‌是通过在属性名前加上下划线(_)来定义的。这种属性只能在定义它们的类内部访问,不能在类的外部直接访问。(私有方法同理)

class Person {
  String? _name;
  setName(value){
    _name = value;
  }
  getInfo(){
    print('name:$_name');
  }
}

  var person = Person();
  person.setName('lucy');
  person.getInfo();//name:lucy
2.3 静态变量

类的静态变量是该类的所有实例共享的变量,通过类名访问静态变量。使用static 关键字来实现类级别的变量。(静态方法同理)

非静态方法可以访问静态成员;静态方法不能访问非静态成员。

class Person {
  String? name;
  static String? nickName;
  getInfo(){
    print('name:$nickName');
  }
  static getInfo2(){
    // print('name:$name');//静态方法无法访问实例变量
    print('name:$nickName');//只可访问静态变量
  }
}

  Person.nickName  = 'lucy';
  var person = Person();
  person.getInfo();//打印结果:name:lucy  实例方法获取静态属性
  Person.nickName  = 'leilei';
  Person.getInfo2();//打印结果:name:leilei  静态方法获取静态属性

3.类的构造函数

3.1 默认构造函数

如果没有显式定义任何构造函数,Dart会自动生成一个无参数的默认构造函数。

  Person p = Person();//默认构造函数,无法穿参
  p.getInfo('男');//name:null  age: null  sex:男

如果显式定义任何构造函数,默认构造函数就不会生成。

3.2 普通构造函数

使用类名作为函数名来定义构造函数

class Person {
  //自定义属性
  String? name;
  int? age;

  Person(String name, int age){
    this.name = name;
    this.age = age;
  }//普通构造函数
  //简写Person(this.name,this.age);
  
  //自定义方法
  getInfo(String? sex){
    print('name:$name  age: $age  sex:$sex');
  }
}
3.3 命名构造函数

命名构造函数允许你为构造函数指定一个名称,这有助于区分不同的构造函数。命名构造函数可以有多个。

class Person {
  //自定义属性
  String? name;
  int? age;

  //普通构造函数
  Person(this.name,this.age);

  // 命名构造函数1
  Person.Init(){
    print('name:$name  age: $age');
  }
  // 命名构造函数2
  Person.fromJson(Map json) {
    name = json['name'];
    age = json['age'];
  }

  //自定义方法
  getInfo(String? sex){
    print('name:$name  age: $age  sex:$sex');
  }
}

  // 使用普通构造函数
  var person1 = Person('Alice', 30);
  person1.getInfo(null);//name:Alice  age: 30  sex:null
  // 使用命名构造函数
  var person2 = Person.Init();//name:null  age: null
  // 使用命名构造函数
  var person3 = Person.fromJson({'name': 'Bob', 'age': 25});
  person3.getInfo(null);// name:Bob  age: 25  sex:null
3.4 工厂构造函数

在构造方法前添加 factory 关键字,使构造方法可以返回值。常用在单例模式

class Person {
  static Person? _instace;
  factory Person() => _instace ??= Person._init();
  Person._init();
}

  Person p1 = Person();
  Person p2 = Person();
  print(p1 == p2);//true
3.5 常量构造函数

常量构造函数指返回不可变对象的构造函数;

主要用途是创建不可变的对象,确保对象的属性在编译时就被确定,并且在运行时无法修改。这种构造函数通过使用const关键字声明,使得对象在编译时就已经确定,从而在运行时无法更改其属性值。创建大量相同对象节省内存。

class Person {
  //保证所有的实例变量为final修饰
  final String name;
  final int age;
  //构造函数必须加const,不能有函数体
  const Person(this.name, this.age);
}

  //参数改变或者不加const,均非同一对象
  var p1 = const Person('Jane', 28);
  var p2 = const Person('Jane', 28);
  print(identical(p1, p2)); // 输出 true,表示 p1 和 p2 是同一个对象

  const p3 = Person('John', 30);
  const p4 = Person('John', 30);
  print(identical(p3, p4)); // 输出 true,表示 p3 和 p4 是同一个对象

3.6 重定向构造函数(构造函数传递)

重定向构造函数用于将调用重定向到同一个类的其他构造函数,或者到从父类继承的构造函数。

调用本类构造函数:

class Person{
  String? name;
  int? age;
  Person(this.name, this.age);
  //使用:调用其他构造函数,并可将参数传递
  Person.chongdingxiang(String nowName, int nowAge) : this(nowName,nowAge);
}

  Person p = Person.chongdingxiang('lucy', 30);
  print('name:${p.name}  age: ${p.age}');//name:lucy  age: 30

在继承关系的子类中,一般需要调用父类的构造函数;这种分2种情况:

隐式调用:父类只有默认构造函数,默认在子类的构造函数前调用父类的构造函数

class Person{
  String? name;
  int? age;
}

class Student extends Person{
  
}

Student xiaoming = Student();

显示调用:显式调用父类构造函数,应该在初始化列表中完成

class Person{
  String? name;
  int? age;
  //1.普通构造函数
  Person(this.name,this.age);
  //2.命名构造函数
  Person.myInit(String myName){
    this.name = myName;
    this.age = 18;
    print('Person init');
  }
}

class Student extends Person{
  String? nickName;
  //1.重定向到父类普通构造函数,传递参数
  Student(String name, int age) : super(name,age);
  //简写Student(super.name, super.age);

  //2.重定向到父类命名构造函数,传递参数
  Student.myInit2(String nowName) : super.myInit(nowName);

  //3.重定向到父类命名构造函数,传递参数,后执行自带函数体(初始化列表)
  Student.myInit3(String nowName) : super.myInit(nowName) {
    print('Student init');
  }

  //4.初始化列表:构造函数方法体之前,初始化一些成员变量(重定向到父类普通构造函数)
  Student.myInit4(super.name,super.age) : nickName = 'xxx' {
    print('Student init');
  }
}

常见用例解析:const MyApp({super.key}),综合了常量与重定向构造函数

//简写: const MyApp({super.key});
//展开: const MyApp({Key? key}) : super(key: key);
//如下例子相同:
class Person{
  //将参数定义可选?,此时常量构造函数也可用可选命名参数
  final String? name;
  //常量构造函数
  const Person({this.name});
}

class Student extends Person{
  //在子类创建普通构造函数重定向到父类常量构造函数
  // Student({String? canshu}) : super(name: canshu);
  //简写 Student({super.name});
  //添加const,定义为子类的常量构造函数;即如常见的类
  const Student({super.name});
}

  Student s1 = const Student(name: '11');
  Student s2 = const Student(name: '11');
  print(s1 == s2);//true

你可能感兴趣的:(Flutter,flutter,开发语言)