Flutter02-Dart基础语法

本文详细介绍了Dart编程的基础知识,包括HelloDart示例、变量定义(显式与类型推导)、数据类型(Int、Double、bool、String及集合类型)、函数(定义、参数、一等公民、匿名函数、作用域)以及运算符。此外,还涵盖了枚举、类(构造方法、setter与getter、继承、抽象类、混入)、泛型和空安全等内容,帮助读者快速掌握Dart语言核心概念。
摘要由CSDN通过智能技术生成

一.Hello Dart

1.1. 打印 print
  print('hello dart');
  // command + s 清理运行缓存
1.2. Dart程序分析
  1. Dart语言的入口也是main函数,并且必须显示的进行定义;
  2. Dart的入口函数main是没有返回值的;
  3. 传递给main的命令行参数,是通过List完成的。
    从字面值就可以理解List是Dart中的集合类型。
    其中的每一个String都表示传递给main的一个参数;
  4. 定义字符串的时候,可以使用单引号或双引号;
  5. 每行语句必须使用分号结尾,很多语言并不需要分号,比如Swift、JavaScript;

二.定义变量

2.1. 定义变量(Explicit)

/**
声明变量
变量类型 变量名称 = 赋值;
*/

  String name = 'xiao ming';
  int age = 18;
  double height = 1.88;
  print('$name, $age, $height');  
2.2. 类型推导(Type Inference)
/**
    var/dynamic/const/final 变量名称 = 赋值;
    const/final 初始化必须赋值
  */
  1. var
  var name = 'name';
  name = 'yh';
  print(name.runtimeType);//String
  1. dynamic 动态类型
  // dynamic可以改变变量类型,通常情况下不使用dynamic, 因为类型的变化会带来潜在的危险
  dynamic age = '180';
  print(age.runtimeType);//String
  age = 180;
  print(age.runtimeType);//int
  1. final & const
    final和const都是用于定义常量的,也就是定义之后不可以修改
final name = 'yh';
// name = 'hy';//错误

const age = 18;
// age = 81;//错误

final和const区别
const在赋值时,赋值的内容必须是在编译期间就确定下来的
final在赋值时,可以动态获取,比如赋值一个函数;final一旦被赋值后就有确定的结果,不会再次赋值

void main(List<String> args) {
  const name = getName();//错误的做法,因为要执行函数才能获取到值
  final name2 = getName();
}

String getName() {
  return 'yh';
}

const修饰赋值语句,只会使用同一份内存,可提高性能:

void main(List<String> args) {
  final a = const Person();
  final b = const Person();
  print(identical(a, b));//true

  final c = Person();
  final d = Person();
  print(identical(c, d));//false
}

class Person {
  const Person();
}

三.数据类型

3.1. Int Double
  //1.整数类型int
  int age = 12;
  int hexAge = 0x12;
  print('$age,$hexAge');//12,18
  //2.浮点型double
  double height = 1.88;

  //字符串与数字转换
  //1.字符串转数字
  var one = int.parse('111');
  print('$one ${one.runtimeType}');//111 int

  //2.数字转字符串
  var num1 = 123;
  var num2 = 123.456;
  var num1Str = num1.toString();
  var num2Str = num2.toString();
  var num2StrD = num2.toStringAsFixed(1);
  print('$num1Str,$num2Str,$num2StrD');//123,123.456,123.5
3.2. bool

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

var isFlag = true;
print('$isFlag,${isFlag.runtimeType}');//true,bool

var message = 'dart';
//错误写法
if (message) {
	print(message);
}
3.3. String

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

//单行字符串
var str1 = 'str1';
var str2 = "str2";
//多行字符串
var str3 = '''
1
2
3
''';
//字符串拼接
var str4 = '$str1,$str2,$str3';
print(str4);
}
3.4. 集合类型
  1. 集合类型的定义
    List:数组 / Set:集合 / Map:字典(映射)
var letters = ['a','b','c'];
List<int> numsList = [1,2,3];
print('$letters,${letters.runtimeType},$numsList,${numsList.runtimeType}');
//[a, b, c],List<String>,[1, 2, 3],List<int>

Set<int> numsSet = {1,2,3,4};
print('$numsSet,${numsSet.runtimeType}');
//{1, 2, 3, 4},_CompactLinkedHashSet<int>

Map<String, Object> map = {'name': 'yh', 'height': 1.88};
print('$map,${map.runtimeType}');
//{name: yh, height: 1.88},_InternalLinkedHashMap<String, Object>
  1. 集合的常见操作
print(letters.length);
print(numsSet.length);
print(objsMap.length);

//list操作
//增,删,包含
numsList.add(5);
numsSet.add(5);

numsList.remove(1);
numsList.removeAt(1);

numsList.contains(4);

print(numsList);//[2, 5]

//map操作
//1.根据key获取value
print(objsMap['name']);//yh
//2.获取所有的entries
print('${objsMap.entries},${objsMap.entries.runtimeType}');//(MapEntry(name: yh), MapEntry(height: 1.88)),MappedIterable<String, MapEntry<String, Object>>
//3.all keys
print(objsMap.keys);//(name, height)
//4.all values
print(objsMap.values);//(yh, 1.88)
//5.contain key || contain value
print('${objsMap.containsKey('name')},${objsMap.containsValue('yh')}');//true,true
//6.remove from key
objsMap.remove('name');

print(objsMap);//{height: 1.88}

四.函数 Function

4.1 函数定义
//函数返回值可以省略

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

void main(List<String> args) {
  print(sum(1, 2));
  print(sum2(1, 2));
}

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

//注意:这里只能是一个表达式,不能是一个语句
sum2(num1, num2) => num1 + num2;
4.2 函数的参数

可选参数
注意, 只有可选参数才可以有默认值, 必须参数不能有默认值

//命名可选参数: {param1, param2, ...}
//位置可选参数: [param1, param2, ...]
  
//命名可选参数
optionParamsFun1(String name, {int age = 10, double height = 1.8}) {
    print('$name,$age,$height');
}
//调用
optionParamsFun1('yh');
optionParamsFun1('yh',age: 20);
optionParamsFun1('yh',age: 20,height: 1.88);
// yh,10,1.8
// yh,20,1.8
// yh,20,1.88

//位置可选参数
optionParamsFun1(String name, [int age = 10, double height = 1.8]) {
    print('$name,$age,$height');
}
optionParamsFun1('yh');
optionParamsFun1('yh', 20);
optionParamsFun1('yh', 20, 1.88);
// yh,10,1.8
// yh,20,1.8
// yh,20,1.88
4.3. 函数是一等公民

函数可以作为参数、返回值

//调用
test(getFunc());

//1.定义一个函数
foo(String name) {
  print(name);
}
//2.将函数作为另一个函数的返回值
getFunc() {
 return foo; 
}
//3.将函数作为另一个函数的参数
test(Function func) {
  func("func");
}

4.4. 匿名函数
void main(List<String> args) {
//匿名函数
  var movies = ['盗梦空间', '星际穿越', '少年派', '大话西游'];
  //1.定义匿名函数
  printElement(item) {
    print(item);
  }
  movies.forEach(printElement);

  //2.使用forEach遍历:匿名函数
  movies.forEach((element) {
    print(element);
  });
  movies.forEach((element) => print(element));
}
4.5. 词法作用域

dart中的词法有自己明确的作用域范围,它是根据代码的结构({})来决定作用域范围的
优先使用自己作用域中的变量,如果没有找到,则一层层向外查找。

var name = 'global';
main(List<String> args) {
  // var name = 'main';
  void foo() {
    // var name = 'foo';
    print(name);
  }
  foo();
}
4.6. 闭包作用域

闭包可以访问其词法范围内的变量,即使函数在其他地方被使用,也可以正常的访问。

void main(List<String> args) {

  sum(num m) {
    return (num n) {
      return m + n;
    };
  }

  var func = sum(10);
  print(func(10));//20
}
4.7. 返回值问题

所有函数都返回一个值。如果没有指定返回值,则语句返回null;隐式附加到函数体。

main(List<String> args) {
  print(foo()); // null
}

foo() {
  print('foo function');
}

五.运算符

5.1.普通运算符
  1. 除法、整除、取余
  var num = 7;
  print(num / 3);//除 2.3333
  print(num ~/ 3);//整除 2
  print(num % 3);//取余 1
  1. ??=
//当变量不为null时使用变量,当变量为null时,后面的值将被赋值给变量
  var name = 'lucy';
  name ??= 'sala';
  print(name);//lucy

  var name2 = null;
  name2 ??= 'Toms';
  print(name2);//Toms
  1. ??
//当变量不为null时使用变量,当变量为null时使用后面的值
  var name = 'lucy';
  print(name ?? 'sala');//lucy

  var name2 = null;
  print(name2 ?? 'Toms');//Toms
5.2. 级联语法:…

对一个对象进行连续的操作,这个时候可以使用级联语法。

class Person {
  String name = 'Tom';
  void eat() {
  }
  void drink() {
  }
  void sleep() {
  }
}

void main(List<String> args) {

  final p1 = Person();
  p1.name = 'Lucy';
  p1.eat();
  p1.drink();
  p1.sleep();
  //级联
  final p2 = Person()
            ..name = "Tom"
            ..eat()
            ..drink()
            ..sleep();

}
5.3. if else

dart不支持非零即真,判断语句中必须有明确的bool类型

  var isBool = true;
  if (isBool) {
  } else {
  }
5.4. switch-case
  var direction = 'east';
  switch (direction) {
    case 'east':
      print('东方');
      break;
    case 'west':
      print('西方');
      break;

    default:
      print('其他方');
  }
  //东方
5.5. 循环

for、for in

  var list = ['1','2','3'];
  for (var i = 0; i < list.length; i++) {
    print(list[i]);
  }
  
  for (var str in list) {
    print(str);
  }
  //1 2 3

while do-while 与其他语法一致
break continue 与其他语法一致

六.枚举 enum

6.1.枚举的定义

枚举使用 enum关键字 来定义:

void main(List<String> args) {
  print(Colors.red);
  //枚举属性 index索引,从0开始;values包含所有枚举值的list
  print(Colors.red.index);
  print(Colors.values);
}

enum Colors {
  red,
  green,
  blue
}

七.类 class

7.1. 类的定义
  1. 定义类用class关键字
  • 类通常有两部分组成:成员(member)和方法(method)。
  • dart没有public,private等关键字,使用下划线“_”来区分公有参数私有参数。
class 类名 {
  类型 成员名;
  返回值类型 方法名(参数列表) {
    方法实现
  }
}
  1. Dart2.0后,创建类对象可以省略 关键字new;
    类中访问类属性一般省略this,但是有命名冲突时,不可省略。
void main(List<String> args) {
  var p1 = Person();
  p1.eat();
}

class Person {
  String name = 'Tom';

  void eat() {
    String name = 'lucy';
    print(name);//lucy
    print(this.name);//Tom
  }
}
7.2. 构造方法
  1. 普通构造方法
    Dart为类提供了默认的构造函数,当有了自己的构造函数,默认的构造方法将会失效,不能再使用。
    这是因为Dart不支持函数重载
void main(List<String> args) {
  var p1 = Person('Tom');
}

class Person {
  var name;

  Person(String name1) {
    this.name = name1;
  }
  //等同于
  Person(this.name);
}
  1. 命名构造方法
class Person {
  var name;
  var age;
  var height;
  
  //命名构造方法
  Person.withArgments(String name, int age) {
    this.name = name;
    this.age = age;
  }
  //命名构造方法2
  Person.withArgments2();
    
  //命名构造方法,传入map
  Person.withMap(Map<String, Object>map) {
    this.name = map['name'];
    this.age = map['age'];
  }
  
  String toString() {
    return '$name, $age, $height';
  }
}

void main(List<String> args) {
  var p = Person.withMap({'name':'Frank','age':18});
  print(p);//Frank, 18, null

  Person p2 = Person.withArgments2();
  print(p2);//null, null, null
}
  1. 初始化列表 Initializer list
    final 初始化时必须赋值
//初始化列表
class Point {
  final num x;
  final num y;
  final num distant;

  Point(this.x,this.y) : distant = sqrt(x * x + y * y);
  //这种初始化变量的方法, 我们称之为初始化列表(Initializer list)
}

  var point = Point(3, 4);
  print(point.distant);
  1. 重定向构造方法
//重定向构造方法
class Person {
  String name;
  int age;

  Person(this.name,this.age);
  //重定向
  Person.withName(String nameStr) : this(nameStr, 10);
}
  1. 常量构造方法
  • 拥有常量构造方法的类中,所有的成员变量必须是final修饰的.
  • 为了可以通过常量构造方法,创建出相同的对象,不再使用 new关键字,而是使用const关键字
  • 如果是将结果赋值给const修饰的标识符时,const可以省略.
class Person {
  final String name;
  final int age;

  const Person(this.name,this.age);
}


  Person p = const Person('lucy', 18);
  Person p2 = const Person('lucy', 18);
  print(identical(p, p2));//true

  const Person p = Person('lucy', 18);
  const Person p2 = Person('lucy', 18);
  print(identical(p, p2));//true

  Person p3 = Person('lucy', 18);
  Person p4 = Person('lucy', 18);
  print(identical(p3, p4));//false
  1. 工厂构造方法(factory)
  • Dart提供了factory关键字, 用于通过工厂去获取对象
  • 最大的特点就是可以手动返回一个对象,可以创建单例
class Person {
  final String name;

  static final Map<String, Person> cache = <String, Person>{};

  factory Person(String nameStr) {
    if (cache.containsKey(nameStr)) {
      final Person? p = cache[nameStr];
      return p!;
    } else {
      final p = Person.withName(nameStr);
      cache[nameStr] = p;
      return p;
    }
  }
  Person.withName(this.name);
}

  Person p3 = Person('lucy');
  Person p4 = Person('lucy');
  print(identical(p3, p4));//false
  1. 单例模式
//写法一
class Singleton {
  const Singleton._internal();
  factory Singleton() => const Singleton._internal();
}
Singleton single = Singleton();

//写法二
class Singleton {
  Singleton._privateInstance();
  static final Singleton instance = Singleton._privateInstance();
  factory Singleton(){
    return instance;
  }
}
//使用
Singleton single = Singleton();

//写法三
class Singleton {
  Singleton._internal();
  static final Singleton _instance = Singleton._internal();
  static Singleton getInstance() {
    return _instance;
  }
}
//使用
var instance = Singleton.getInstance();

//写法四
class Singleton {
	// 私有化构造方法
	Singleton._privateConstructor();
	static final Singleton _instance = Singleton._privateConstructor();
	//同下 : static Singleton get instance => _instance;
	static Singleton get instance { return _instance;}
}
//使用
var instance = Singleton.instance;

//写法五
class Singleton {
	Singleton._privateConstructor();
	static final Singleton instance = Singleton._privateConstructor();
}
//使用
void mian(){
	var instance = Singleton.instance;
    var instance2 = Singleton.instance;
    print(instance == instance2);
}
7.3 setter和getter
class Person {
  var name;

  set setName(String nameStr){
    name = nameStr;
  }

  String get getName{
    print('getName');
    return name;
  }
}

  Person p = Person();
  p.name = '123';
  print(p.getName);//getName  123
7.4 继承 extends

面向对象的其中一大特性就是继承,也是多态的使用前提。

  • Dart中的继承是单继承;
  • Dart中的继承使用extends关键字,子类中使用super来访问父类;
  • 父类中的所有成员变量和方法都会被继承,,但是构造方法除外。

子类中可以调用父类的构造方法,对某些属性进行初始化:

  • 子类的构造方法在执行前,将隐含调用父类的无参默认构造方法(没有参数且与类同名的构造方法)。
  • 如果父类没有无参默认构造方法,则子类的构造方法必须在初始化列表中通过super显式调用父类的某个构造方法。
class Person {
  var name;

  Person(this.name);

  set setName(String nameStr){
    name = nameStr;
  }

  String get getName{
    print('getName');
    return name;
  }

  eat() {
  }

  run(){
    print('person run');
  }
}

class Student extends Person {
  int age;
  Student.withAge(String name, int age): this.age = age, super(name);

  @override
  run() {
    // TODO: implement run
    super.run();
    print('student run');
  }
}

  Student s =  Student.withAge('Tom', 18);
  s.name = '123';
  print(s.getName);//getName  123
  s.run();
  //person run
  // student run
7.5 抽象类 abstract

注意事项:

  • 注意一:抽象类不能实例化.
  • 注意二:抽象类中的抽象方法必须被子类实现, 抽象类中的已经被实现方法, 可以不被子类重写.
abstract class Animal {
  eat();
  run(){
  }
}

class Dog extends Animal {

  @override
  eat() {
    // TODO: implement eat
  }

}

class SmallDog extends Dog {
  @override
  run() {
    // TODO: implement run
  }
}
7.6 隐式接口 implements

Dart中的接口比较特殊, 没有一个专门的关键字来声明接口.

  • 默认情况下,定义的每个类都相当于默认也声明了一个接口,可以由其他的类来实现(因为Dart不支持多继承)
  • 必须实现抽象类中的所有方法;即在通过implements实现某个类时,类中所有的方法都必须被重新实现(无论这个类原来是否已经实现过该方法):
abstract class Eat {
  eat();
}
abstract class Run {
  run() {

  }
}

class Animal implements Eat,Run {

  @override
  eat() {
    // TODO: implement eat
  }
  @override
  run() {
    // TODO: implement run
  }

}
7.7 Mixin混入 mixin with

Mixin混入的方式

  • 除了可以通过class定义类之外,也可以通过mixin关键字来定义一个类。
  • 只是通过mixin定义的类用于被其他类混入使用,通过with关键字来进行混入。
mixin Eat {
  eat();
}
mixin Run {
  run(){
  }
}

class Animal with Eat,Run {

  @override
  eat() {
    // TODO: implement eat
  }
  // @override
  // run() {
  //   // TODO: implement run
  // }

}
7.8 类的成员和方法
  • 对象级别的的成员和方法
class Person {
  var name;
  int age;
  eat() {
  }
}
  • 类级别的成员和方法
class Person {
  static var name;
  static final age = 18;
  static eat() {
  }
}

八.泛型

8.1. List和Map泛型
  //泛型写法 
  // List<Object>
  //_InternalLinkedHashMap<String, Object>
  var list = ['a','b','c',123];
  var dic = {'key1':'value1', 'key2':123};
  //限制类型
  var list2 = <String>['a','b','c'];
  var dic2 = <String, String>{'key1':'value1', 'key2':'value2'};
8.2. class泛型
  • Object类型
//object
class Person {
  Object name;
  Object age;
  Person(this.name, this.age);
}

  Person p = Person('yh',18);
  print(p.name.runtimeType);
  print(p.age.runtimeType);
  • T泛型
//T
class Person<T extends num> {
  T age;
  T height;
  Person(this.age, this.height);

  double sum(){
    double s = (this.age as int) * (this.height as double);
    return s;
  }
}

  Person p = Person(10,1.88);
  print(p.age.runtimeType);// int
  print(p.sum());// 18.799999999999997

9.空安全 “?”、“!”

为什么需要空安全?

  • 目标:对于空安全而言,我们的目标是让您对代码中的 null 可见且可控,并且确保它不会传递至某些位置从而引发崩溃。
String? == String|Null
  • 如果您能确定一条可空的表达式不为空, 您可以在其后添加 !让 Dart 处理为非空。
void main(List<String> arguments) {

  int? age = null;
  age = 10;
  double height = age! * 10.0;
  print(height);

  print('Hello world!');
}

与swift中的“?”、“!”基本相同。

10.库

在Dart中,库的使用可以使代码的重用性得到提高,并且可以更好的组合代码。

Dart中任何一个dart文件都是一个库,即使你没有用关键字library声明

10.1.库的导入

import语句用来导入一个库,后面跟一个字符串形式的Url来指定表示要引用的库,语法如下:

import '库所在的url';

常见的库URI有三种不同的形式

  • 来自dart标准版,比如dart:io、dart:html、dart:math、dart:core(但是这个可以省略)
//dart:前缀表示Dart的标准库,如dart:io、dart:html、dart:math
import 'dart:io';
  • 使用相对路径导入的库,通常指自己项目中定义的其他dart文件
//当然,你也可以用相对路径或绝对路径的dart文件来引用
import 'lib/student/student.dart';
  • Pub包管理工具管理的一些库,包括自己的配置以及一些第三方的库,通常使用前缀package
//Pub包管理系统中有很多功能强大、实用的库,可以使用前缀 package:
import 'package:flutter/material.dart';
  • 库文件中内容的显示和隐藏:
    如果希望只导入库中某些内容,或者刻意隐藏库里面某些内容,可以使用show和hide关键字
//show关键字:可以显示某个成员(屏蔽其他)
//hide关键字:可以隐藏某个成员(显示其他)
import 'lib/student/student.dart' show Student, Person;
import 'lib/student/student.dart' hide Person;
//库中内容和当前文件中的名字冲突
  • 当各个库有命名冲突的时候,可以使用as关键字来使用命名空间
import 'lib/student/student.dart' as Stu;
Stu.Student s = new Stu.Student();
10.2. 库的定义
  • library关键字

通常在定义库时,我们可以使用library关键字给库起一个名字。

但目前我发现,库的名字并不影响导入,因为import语句用的是字符串URI

library math;
  • part关键字

在之前我们使用student.dart作为演练的时候,只是将该文件作为一个库。

在开发中,如果一个库文件太大,将所有内容保存到一个文件夹是不太合理的,我们有可能希望将这个库进行拆分,这个时候就可以使用part关键字了

不过官方已经不建议使用这种方式了:
mathUtils.dart文件

part of "utils.dart";

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

dateUtils.dart文件

part of "utils.dart";

String dateFormat(DateTime date) {
  return "2020-12-12";
}

utils.dart文件

part "mathUtils.dart";
part "dateUtils.dart";

test_libary.dart文件

import "lib/utils.dart";

main(List<String> args) {
  print(sum(10, 20));
  print(dateFormat(DateTime.now()));
}
  • export关键字

官方不推荐使用part关键字,那如果库非常大,如何进行管理呢?

将每一个dart文件作为库文件,使用export关键字在某个库文件中单独导入
mathUtils.dart文件

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

dateUtils.dart文件

String dateFormat(DateTime date) {
  return "2020-12-12";
}

utils.dart文件

library utils;

export "mathUtils.dart";
export "dateUtils.dart";

test_libary.dart文件

import "lib/utils.dart";

main(List<String> args) {
  print(sum(10, 20));
  print(dateFormat(DateTime.now()));
}

最后,也可以通过Pub管理自己的库自己的库,在项目开发中个人觉得不是非常有必要,所以暂时不讲解这种方式。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值