764b02862217ac24cdbeb065854104d3
Flutter-从入门到项目 05:Dart语法快速掌握(下)

Flutter 专栏目录直通车

Flutter-从入门到项目 01: Flutter重要性

Flutter-从入门到项目 02: 环境配置

Flutter-从入门到项目 03: Flutter初体验

Flutter-从入门到项目 04:Dart语法快速掌握(上)

Flutter-从入门到项目 05:Dart语法快速掌握(下)

Flutter-从入门到项目 06: 微信项目搭建

Flutter-从入门到项目 07: 微信项目-发现页面

这一篇继续接 Flutter-从入门到项目 04:Dart语法快速掌握(上) 分析 , 从上一篇文章可以得出大家不太喜欢看语法相关类的文章. 但是没有关系 我还是继续写: 毕竟工欲善其事必先利其器 大家可以先收藏备用

⑦ 函数

Dart是一种面向对象语言,因此即使函数也是对象,也有一个类型 Function 。这意味着 函数可以赋值给变量,也可以作为参数传递给其他函数。您还可以像调用函数一样调用 Dart类 的实例。有关详细信息,请参见: callable-classes

// 函数 类型测试
// void 代表返回值类型
// funcFunc 代表函数名称
// () 参数
void funcFunc(){
}

// 还可以省略 : 没有声明类型也是可以的
funcFunc1(){
}
// 对于仅含有一个表达式的方法,你可以使用一种简写的语法:
funcFunc2() => print("=> 表达式;语法是{ return 表达式 }的简写");

注意:只有一个表达式能够在箭头符(=>)和分号(;)之间出现,语句是不可以这样使用的。比如,你不能把if 语句放在这两个符号之间,但是一个三元运算符(?:)是可以的。

  • 一个函数可以有两种类型的参数:必要参数可选参数。所有的必要参数都应放在可选参数之前,当必要参数已经全部列出时,才能在后面加入可选参数。

  • 可选参数可以是可选位置参数或者可选命名参数,但不能既是可选位置参数又是可选命名参数。

  • 这两种可选参数都可以定义默认值但是默认值必须是编译时的常量,比如字面值。如果没有为之提供默认值,那么该参数的默认值将会是 null

/// 将 bold 和 hidden 作为你声明的参数的值
funcFunc3({bool bold, bool hidden}) {
  print('$bold,$hidden');  // true,null
}
// 调用
funcFunc3(bold: true);

/// 将 bold 和 hidden 作为你声明的参数的值 默认值分别是 false 和 true
funcFunc4({bool bold = false, bool hidden = true}) {
  print('$bold,$hidden');   // false,true
}
// 可选参数 默认值测试
funcFunc4();


// 可选的位置参数,用[]它们标记为可选的位置参数:
String funcFunc5(String person , String word, [String device]) {
  var result = "$person say : $word"; 
  if (device != null){
    result = "$person say : $device"; 
  }
  print(result);
  return result;
}
// 函数调用
funcFunc5("KC","和谐学习,不急不躁");  // KC say : 和谐学习,不急不躁
funcFunc5("KC","和谐学习,不急不躁","等风来不如追风去"); // KC say : 等风来不如追风去
  • 函数作为一个类对象的功能 -> 将一个函数作为参数传递给另一个函数。函数式编程思想
// 函数式编程思想
funcFunc6(int num) => print(num);

funcFunc7(){
  var list = [1,2,3,4];
  list.forEach(funcFunc6);
  /**
      flutter: 1
      flutter: 2
      flutter: 3
      flutter: 4
   */
}
  • 匿名函数

大多数函数都能被命名为匿名函数,如 main()printElement()。您还可以创建一个名为匿名函数的无名函数,有时也可以创建 lambda闭包。您可以为变量分配一个匿名函数,例如,您可以从集合中添加或删除它。

一个匿名函数看起来类似于一个命名函数 - 0或更多的参数,在括号之间用逗号和可选类型标注分隔。

下面的代码块包含函数的主体:

 ([[Type] param1[, …]]) { 
     codeBlock; 
  }; 

下面的示例定义了一个具有无类型参数的 匿名函数item,该函数被 list 中的每个 item` 调用,输出一个字符串,该字符串包含指定索引处的值。

var list = ['apples', 'bananas', 'oranges'];
 list.forEach((item) {
    print('${list.indexOf(item)}: $item');
 });

⑧ 操作符

介绍 符号
一元后缀符 expr++ expr-- () [] .
一元前缀符 -expr !expr ~expr ++expr --expr
乘法类型 * / % ~/
加法类型 + -
位操作符 << >>
按位与 &
按位异或 ^
按位或 \
比较和类型测试 >= <= > < as is is!
等价 == !=
逻辑与 &&
逻辑或 \
条件运算符 expr1 ? expr2 : expr3
级联运算符 ..
赋值 = *= /= /= ~/= %= += -= <<= >>= &= ^= \

无论这些 操作符 还是 算数运算符等价和关系操作符类型测试操作符赋值运算符逻辑运算符位操作与移位运算符 与其他语言基本无异! 所以大家瞄一眼就OK

级联 : .. 允许你在单个对象的成员上执行多个操作,具体可见

⑨ 控制流语句

  • if 和 else
  • for 循环
  • while 和 do-while循环
  • break和continue
  • switch和 case
  • assert

你也可以通过使用 try-catchthrow 来改变控制流,具体说明请见 异常 部分。

这里涉及的语法内容和我们iOS开发基本一致 , 如果你想熟练的同学,可以移步 Flutter 学习

🔟 异常语句

void excFunc(){
  try {
    print("KCFlutter");
  } on Exception catch (e) {
    // 任意一个异常
    print('来了异常: $e');
  } catch (e) {
    // 非具体类型
    print('非具体类型: $e');
  }
}

异常三部曲: throw 抛出异常 + catch 捕获异常 + finally 就是要执行

11 泛型

如果你在API文档寻找基本数组类型或者 List 类型,你将会看到该类型实际上为List<E>,其中<...>标记表示此表为一个泛型类型(或为参数化结构)—— 一种含有正规类型参数的类型。按照惯例,类型变量通常为单字符名称,例如 E,T,S,K,以及V。

  • 比如,如果你打算使用一个仅仅包含字符串的 List,你可以声明它为 List<String>(可理解为“字符串类型组成的List”),通过这种方式,你的程序员同事,以及你的工具(比如Dart编辑器和调试模式下的Dart虚拟机)能检测到将一个非字符串的变量分配到List中很可能是错误的,这里给出一个样例:
// 泛型
void genericsFunc(){
  var names = List<String>();
  names.addAll(['Hank', 'Cooci', 'CC']);
  // names.add(100); // 这里就会报错,因为通过泛型就确定了list 的内容的类型
}
  • 另外一个使用泛型的原因是 为了减少代码的重复泛型可以让你能共享多个类型的一个接口和实现方式 它在调试模式以及静态分析的错误预警中仍然很有优势。举个例子,当你在创建一个接口来缓存一个对象时:
// 泛型可以让你能共享多个类型的一个接口和实现方式,
// 它在调试模式以及静态分析的错误预警中仍然很有优势
abstract class KCObjectCache{
  Object getByKey(String key);
  setByKey(String key,Object value);
}
// 你发现你想要一个字符串专用的接口,所以你创建了另外一个接口:
abstract class KCStringCache{
  String getByKey(String key);
  setByKey(String key,String value);
}
// 接下来,你决定你想要一个这种接口的数字专用的接口...你想到了这个方法.
// 泛型类型可以减少你创建这些接口的困难。取而代之的是,你只需要创建一个带有一个类型参数的接口即可:
// 泛型接下来就牛逼了
abstract class Cache<T>{
  // 在这个代码中,T是一个替代类型,即占位符,你可以将他视为后续被开发者定义的类型。
  T getByKey(String key);
  setByKey(String key,T value);
}

12 类

这个内容也是最重要的额! 平时大家开发也是必须的内容,希望大家好好感受~~☺️

12.1 对象

  • Dart 是一种面向对象的语言,并且支持基于 mixin 的继承方式。
  • Dart 语言中所有的对象都是某一个类的实例,所有的类有同一个基类--Object
  • 基于 mixin 的继承方式具体是指:一个类可以继承自多个父类。
// 类相关测试
class LGPerson {
  int age;
  String name;
  String hobby;
  double height;
}

void classFunc(){
  // 实例变量创建测试
  var person = LGPerson();
  person.age = 18;
  person.name = "Cooci";
  person.height = 182.0;
  person.hobby  = "iOS";

  print(person.runtimeType); // LGPerson
}
  • 使用 .(dot)来调用实例的变量或者方法。

  • 使用 ?. 来确认前操作数不为空, 常用来替代. , 避免左边操作数为 null 引发异常。

  • 使用 runtimeType 方法,在运行中获取对象的类型。该方法将返回 Type` 类型的

12.2 实例化变量(Instance variables)

  • 在类定义中,所有没有初始化的变量都会被初始化为null。

  • 类定义中所有的变量, Dart语言都会隐式的定义 setter 方法,针对非空的变量会额外增加 getter 方法

  var person2 = LGPerson();
  person2.hobby = "Flutter";  // Use the setter method for hobby.
  print(person2.hobby);       // Use the getter method for hobby.
  print("age = ${person2.age}, name = ${person2.name}"); //age = null, name = null

12.3 构造函数(Constructors)

要声明一个构造函数,只需创建一个与类同名的方法(或者加上一个额外的标识符命名构造函数的描述)。构造函数最常见的形式,就是自动生成的构造函数,下面创建一个类的新实例:

class LGStudent {
  int age;
  String name;
  String hobby;
  double height;

  // LGStudent(int age, String name, String hobby){
  //   // height 没有构造赋值
  //   this.age   = age;
  //   this.name  = name;
  //   this.hobby = hobby;
  // }
  // this关键字指向了当前类的实例, 上面的代码可以简化为:
  LGStudent(this.age,this.name,this.hobby);
}

  // 构造函数
  var student1 = LGStudent(18, "KC", "构造函数");
  print("age = ${student1.age}, name = ${student1.name}"); // age = 18, name = KC
  • 如果你不声明一个构造函数,系统会提供默认构造函数。默认构造函数没有参数,它将调用父类的无参数构造函数。: LGStudent ()

  • 子类不继承父类的构造函数。子类只有默认构造函数。(无参数,没有名字的构造函数)。

  • 使用命名构造函数可以为一个类声明多个构造函数,或者说是提供额外的声明:

  // 命名构造函数
  LGStudent.fromMap(Map stuMap){
    age    = stuMap['age'];
    name   = stuMap['name'];
    hobby  = stuMap['hobby'];
    height = stuMap['height'];
  }

  // 初始化列表
  LGStudent.fromMaplist(Map stuMap):
        age = stuMap['age'],
        name = stuMap['name'],
        hobby = stuMap['hobby'],
        height = stuMap['height']{
    // age = 18, name = 酷C, hobby = 大师底层, height = 180.0
    print("age = $age, name = $name, hobby = $hobby, height = $height");
  }

  var stuMap   = {'age': 18,'name': '酷C','hobby': "大师底层",'height': 180.0,};
  var student2 = LGStudent.fromMap(stuMap);
  print("age = ${student2.age}, name = ${student2.name}"); // age = 18, name = 酷C

重定向构造函数

有时一个构造函数的目的只是重定向到同一个类中的另一个构造函数。如果一个重定向的构造函数的主体为空,那么调用这个构造函数的时候,直接在冒号后面调用这个构造函数即可。

```Dart
// this关键字指向了当前类的实例, 上面的代码可以简化为:
LGStudent(this.age,this.name,this.hobby);
// 重定向构造函数
LGStudent.rediconstructor(int age, String name, String hobby) : this(age,
"哭C", hobby); // : 后面就是调用上面的构造函数
var student4 = LGStudent.rediconstructor(20, "KC", '185.');
print("age = ${student4.age}, name = ${student4.name}, hobby = ${student4

top Created with Sketch.