编程语言虽然千差万别,但归根结底,它们的设计思想无非就是回答两个问题:

1、如何表示信息;

2、如何处理信息;

函数

函数是一段用来独立地完成某个功能的代码。函数是对象类型,它的类型叫做Function。这意味着函数也可以被定义为变量,甚至可以被定义为参数传递给另一个函数。
bool isZero(int number) => number == 0;
void printInfo(int number, Function check) => print("$number is Zero: ${check(number)}");
如果函数体只有一行表达式,就可以像JavaScript语言那样用箭头函数来简化这个函数

一个函数中可能需要传递多个参数。如何让这类函数的参数声明变得更加优雅、可维护,同时降低调用者的使用成本?

C++与Java的做法是,提供函数的重载,即提供同名但参数不同的函数。但Dart认为重载会导致混乱,因此从设计之初就不支持重载,而是提供了可选命名参数和可选参数。
bool isZero(int number) => number == 0;
void printInfo(int number, Function check) => print("$number is Zero: ${check(number)}"); // 要达到可选命名参数的用法,那就在定义函数的时候给参数加上{}
void enableFlagsA({bool bold, bool hidden}) => print("$bold, $hidden"); // 定义可选命名参数时增加默认值
void enableFlagesB({bool bold = true, bool hidden = false}) => print("$bold, $hidden"); // 可忽略的参数在函数定义时用[]符号指定
void enableFlagesC(bool bold, [bool hidden]) => print("$bold, $hidden"); // 定义可忽略参数时增加默认值
void enableFlagesD(bool bold, [bool hidden = false]) => print("$bold, $hidden");

类是特定类型的数据和方法的集合,也是创建对象的模版。

类的定义及初始化

Dart是面向对象的语言,每个对象都是一个类的实例,都继承自顶层类型Object。 Dart中并没有public、protected、private这些关键字,只要在声明变量与方法时,在前面加上_即可作为private方法使用,如果不加_,则默认为public。不过_的限制范围并不是类访问级别的,而是库访问级别。

class Point {

  num x, y;
static num factor = 0;
// 语法糖,等同于在函数体内:this.x = x; this.y = y;
Point(this.x, this.y);
void printInfo() => print('($x,$y)');
static void printZValue() => print('$factor');
}
有时候类的实例化需要根据参数提供多种初始化方法。除了可选命名参数和可选参数之外,Dart还提供了命名构造函数的方式,使得类的实例化过程语义更清晰。

此外,与C++类似,Dart支持初始化列表。在构造函数的函数体真正执行之前,还有机会给实例变量赋值,甚至重定向至另一个构造函数。

class Point {
num x, y, z;
Point(this.x, this.y) : z = 0; // 初始化变量z
Point.bottom(num x) : this(x, 0); // 重定向构造函数
void printInfo() => print('($x, $y, $z)');
} var p = Point.bottom(100);
p.printInfo(); // 输出(100,0,0)

复用

在面向对象的编程语言中,将其他类的变量与方法纳入本类中进行复用的方式一般有两种:继承父类和接口实现。

在Dart中,可以对同一个父类进行继承或接口实现:
  • 继承父类意味着,子类由父类派生,会自动获取父类的成员变量和方法实现,子类可以根据需要覆写构造函数及父类方法;
  • 接口实现则意味着,子类获取到的仅仅是接口的成员变量符号和方法符号,需要重新实现成员变量,以及方法的声明和初始化,否则编译器会报错。
class Point {
num x = 0, y = 0;
void printInfo() => print('($x, $y)');
} // Vector 继承自 Point
class Vector extends Point { num z = 0;
@override
void printInfo() => print('($x,$y,$z)'); // 覆写了printInfo实现
} // Coordinate 是对 Point 的接口实现
class Coordinate implements Point { num x = 0, y = 0; // 成员变量需要重新声明
void printInfo() => print('($x, $y)'); // 成员函数需要重新声明实现
} var xxx = Vector();
xxx
..x = 1
..y = 2
..z = 3; // 级联运算符,等同于 xxx.x = 1; xxx.y = 2; xxx.z = 3;
xxx.printInfo(); // 输出(1,2,3) var yyy = Coordinate();
yyy
..x = 1
..y = 2; // 级联运算符,等同于 yyy.x = 1; yyy.y = 2;
yyy.printInfo(); // 输出 (1,2)
print(yyy is Point); // true
print(yyy is Coordinate); // true
除了继承和接口实现之外,Dart还提供了另一种机制来实现类的复用,即“混入"(Mixin),混入鼓励代码重用,可以被视为具有实现方法的接口。不仅可以解决Dart缺少对多重继承的支持问题,还能够避免由于多重继承可能导致的歧义(菱形问题)。

要使用混入,只需要with关键字即可。

class Coordinate with Point {

}

  var yyy = Coordinate();
yyy
..x = 1
..y = 2; // 级联运算符,等同于 yyy.x = 1; yyy.y = 2;
yyy.printInfo(); // 输出 (1,2)
print(yyy is Point); // true
print(yyy is Coordinate); // true
可以看到,通过混入,一个类里可以以非继承的方式使用其他类中的变量与方法。

运算符

Dart和绝大多数编程语言的运算符一样,除外,Dart多了几个额外的运算符,用于简化处理变量实例缺失(即null)的情况。
  • ?. 运算符:假如Point类有printInfo()方法,p是Point的一个可能为null的实例。那么,p调用成员方法的安全代码,可以简化为p?.printInfo(),表示p为nul的时候跳过,避免抛出异常。
  • ??= 运算符:如果a为null,则给a赋值value,否则跳过。这种用默认值兜底的赋值语句在Dart中我们可以用a ??= value表示。
  • ?? 运算符:如果a不为null,返回a的值,否则返回b。在Java或者C++中,我们需要通过三元表达式(a != null)? a:b 来实现这种情况。而在Dart中,这类代码可以简化为 a ?? b。
在Dart中,一切都是对象,就连运算符也是对象成员函数的一部分。
对于系统的运算符,一般情况下只支持基本数据类型和标准库中提供的类型。而对于用户自定义的类。如果想要支持基本操作,比如比较大小、相加相减等,则需要用户自己来定义关于这个运算符的具体实现。

Dart提供了类似C++的运算符覆写机制,使得我们不仅可以覆写方法,还可以覆写或者自定义运算符。

class Vector {
num x, y;
Vector(this.x, this.y);
// 自定义相加运算符,实现向量相加
Vector operator + (Vector v) => Vector(x + v.x, y + v.y); // 覆写相等运算符,判断向量相等
bool operator == (dynamic v) => x == v.x && y == v.y;
} final x = Vector(3,3);
final y = Vector(2,2);
final z = Vector(1,1);
print(x==(y+z)); // 输出 true
operator 是 Dart 的关键字,与运算符一起使用,表示一个类成员运算符函数。在理解时,我们应该把 operator 和运算符作为整体,看作是一个成员函数名。

Dart函数、类和运算符-处理信息的更多相关文章

  1. 编写可维护的JavaScript—语句和表达式&变量、函数和运算符

    语句和表达式 所有的块语句都应当使用花括号.包括: if for while do…while… try…catch…finally //不好的写法 if (condition) doSomethin ...

  2. 使用工厂方法模式设计能够实现包含加法(+)、减法(-)、乘法(*)、除法(/)四种运算的计算机程序,要求输入两个数和运算符,得到运算结果。要求使用相关的工具绘制UML类图并严格按照类图的设计编写程序实

    2.使用工厂方法模式设计能够实现包含加法(+).减法(-).乘法(*).除法(/)四种运算的计算机程序,要求输入两个数和运算符,得到运算结果.要求使用相关的工具绘制UML类图并严格按照类图的设计编写程 ...

  3. 1、使用简单工厂模式设计能够实现包含加法(+)、减法(-)、乘法(*)、除法(/)四种运算的计算机程序,要求输入两个数和运算符,得到运算结果。要求使用相关的工具绘制UML类图并严格按照类图的设计编写程

    1.使用简单工厂模式设计能够实现包含加法(+).减法(-).乘法(*).除法(/)四种运算的计算机程序,要求输入两个数和运算符,得到运算结果.要求使用相关的工具绘制UML类图并严格按照类图的设计编写程 ...

  4. C++友元函数和运算符重载

    非成员友元函数.成员友元函数和友元类 1.友元的作用: (1)友元提供了不同类的成员函数之间.类的成员函数与一般函数之间进行了数据共享的机制: 2.友元的优点和缺点 优点:提高程序的运行效率: 缺点: ...

  5. Shell编程基础教程2--变量和运算符

    2.变量和运算符 2.1.变量的类型 本地变量:环境变量:变量替换(显示变量):位置变量:标准变量:特殊变量: 2.2.本地变量 本地变量在用户现在的shell生命周期的脚本中使用 在命令行, LOC ...

  6. Javascript学习2 - Javascript中的表达式和运算符

    原文:Javascript学习2 - Javascript中的表达式和运算符 Javascript中的运算符与C/C++中的运算符相似,但有几处不同的地方,相对于C/C++,也增加了几个不同的运算符, ...

  7. JavaScript深入浅出补充——(一)数据类型,表达式和运算符

    项目基本做完,在进行下一阶段学习之前先看视频学习回顾一下JavaScript 一.数据类型 JavaScript中有五种原始类型和一种对象类型 JavaScript弱类型语言中隐式转换 num-0 字 ...

  8. Java 第二章 变量、数据类型和运算符

    第二章      变量.数据类型和运算符 什么是变量: 变量代表一块内存区域,变量类型不一样,这一块内存的大小也不一样. #在编程语言里面,你可以通过定义变量,向内存里添加数据或者修改内存已有的数据. ...

  9. C#图解教程 第八章 表达式和运算符

    表达式和运算符 表达式字面量 整数字面量实数字面量字符字面量字符串字面量 求值顺序 优先级结合性 简单算术运算符求余运算符关系比较运算符和相等比较运算符递增运算符和递减运算符条件逻辑运算符逻辑运算符移 ...

随机推荐

  1. 如果有人问你 Dubbo 中注册中心工作原理,就把这篇文章给他

    注册中心作用 开篇首先想思考一个问题,没有注册中心 Dubbo 还能玩下去吗? 当然可以,只要知道服务提供者地址相关信息,消费者配置之后就可以调用.如果只有几个服务,这么玩当然没问题.但是生产服务动辄 ...

  2. 强烈推荐 GitHub 上值得前端学习的开源实战项目

    强烈推荐 GitHub 上值得前端学习的开源实战项目. Vue.js vue-element-admin 是一个后台前端解决方案,它基于和 element-ui 实现 基于 iView 的 Vue 2 ...

  3. 程序与CPU

    CPU中共有四大组件: 寄存器 控制器 运算器 时钟 寄存器:存取数值(存东西的) 控制器:负责将内存(寄存器)中的数据进行读入和写出(控制寄存器 协调者) 运算器:里面是逻辑运算单元,协助寄存器和控 ...

  4. net core WebApi——文件分片下载

    目录 前言 开始 测试 小结 @ 前言 上一篇net core WebApi--文件分片上传与跨域请求处理介绍完文件的上传操作,本来是打算紧接着写文件下载,中间让形形色色的事给耽误的,今天还是抽个空整 ...

  5. 跟我学SpringCloud | 第十六篇:微服务利剑之APM平台(二)Pinpoint

    目录 SpringCloud系列教程 | 第十六篇:微服务利剑之APM平台(二)Pinpoint 1. Pinpoint概述 2. Pinpoint主要特性 3. Pinpoint优势 4. Pinp ...

  6. 设计模式(C#)——08组合模式

    推荐阅读:  我的CSDN  我的博客园  QQ群:704621321       游戏通常包含许多视图.主视图中显示角色.有一个子视图,显示玩家的积分.有一个子视图,显示游戏中剩下的时间.      ...

  7. babel-loader与babel-core的版本对应关系

    babel-loader 8.x对应babel-core 7.xbabel-loader 7.x对应babel-core 6.x如何解决1. 卸载旧的babel-corenpm un babel-co ...

  8. 新手学习FFmpeg - 调用API完成录屏并进行H.264编码

    Screen Record H.264 目前在网络传输视频/音频流都一般会采用H.264进行编码,所以尝试调用FFMPEG API完成Mac录屏功能,同时编码为H.264格式. 在上一篇文章中,通过调 ...

  9. 深入理解 Handler 消息机制

    记得很多年前的一次面试中,面试官问了这么一个问题,你在项目中一般如何实现线程切换? 他的本意应该是考察 RxJava 的使用,只是我的答案是 Handler,他也就没有再追问下去了.在早期 Andro ...

  10. 2019 Multi-University Training Contest 9

    A. Rikka with Quicksort 题意 求 EX 快速排序复杂度. 做法 根据线性期望可加性,独立考虑长度为 \(m\) 的区段对答案的贡献.进行简单的公式推导,对 \(s(x)=\su ...