在学习Dart语言的过程中,发现很多语法点和Swift有异曲同工之妙,所以就顺便记录下,已便更好的理解掌握。
打印、注释、分号
打印
Dart和Swift都用print函数,输出内容到console
面板上。
注释
相同点:
单行注释: 以//
开始,所有在//
和改行结尾
之间的内容被编译器忽略。
多行注释: 以/*
开始,以*/
结尾,所有在/*
和*/
之间的内容被编译器忽略,注意多行注释可以嵌套。
文档注释: 以///
或者/**
开始。在调用时候,有提示信息。
不同点:
Dart中的文档注释,除非用中括号括起来,否则Dart编译器会忽略所有文本。使用中括号可以引用类、方法、字段、顶级变量、函数、和参数。括号中的符号会在已记录的程序元素的词法域中进行解析。
分号
Dart强制要求在每条语句的结尾处使用分号;
,而Swift则可加可不加,但是如果你在同一行内写多条独立的语句,就必须要用分号。
声明常量和变量
相同点:
1,都使用var来声明变量,都具备类型推断功能。
1 | var dartStr = "hello world" // 类型推断为String |
也都可以通过添加类型注解
来显示指定类型。
1 | String dartStr = "hello world" |
不同点:
1,常量声明方式。
如果不打算更改变量值,dart中可以使用final或者const。一个final变量只能被赋值一次,而const变量是编译时常量,定义时必须赋值。而Swift中使用let,一个let变量只能被赋值一次,最迟在构造器。
1 | const maximumNumber = 10 // 定义时必须赋值 |
final和const有什么区别呢?
const在赋值时,赋值的内容必须是在编译期间就确定下来的。
final在赋值时,可以动态获取, 比如赋值一个函数。
Dart中使用dynamic或Object来定义的变量,其类型相当于Swift中的Any。
内建类型
Swift 包含了 Int
表示整型值; Double
和Float
表示浮点型值;Bool
是布尔型值;String
是文本型数据。 还提供了三个基本的集合类型,Array
、Set
和 Dictionary
。
Dart包含了 int
表示整型值; double
表示浮点型值;bool
是布尔型值;String
是文本型数据。 还提供了三个基本的集合类型,List
、Set
和 Map
。
Swift
和Dart
中不能判断非0即真,或者非空即真。
默认值
未初始化的变量默认值是null
。即使变量是数字类型默认值也是 null,因为在 Dart 中一切都是对象,数字类型也不例外。
控制流
你可以通过下面任意一种方式来控制 Dart 程序流程:
1.条件语句
if and else
switch and case
2.循环
for loops
while and do-while loops
3.控制转移语句
break and continue
return and throw
assert
:该语句只在开发环境中有效,在生产环境是无效的;
而Swift也提供了多种流程控制结构:
1.条件语句
if and else
switch and case
2.循环
for loops
while and repeat-while loops
3.控制转移语句
break and continue
return and throw
fallthrough
总结: 1,在循环语句中,Dart
是do-while
而Swift
是repeat-while
。2,在Swift里,switch语句不会从上一个case分支跳转到下一个case分支中,fallthrough
可以实现C风格的贯穿的特性。
运算符
前提:只介绍相对其他语言比较特殊的运算符。
1.除法、整除、取模运算符
1 | var num = 7; |
2.赋值运算符
在dart
中,有一个很多语言都不具备的赋值运算符??=
- 当变量有值时,使用自己的值,当变量为null时,使用后面的内容进行赋值。
1 | main(List<String> args) { |
在swift
中,如果赋值的右边是一个多元组,它的元素可以马上被分解成多个常量或变量:
1 | let (x, y) = (1, 2) |
3.条件运算符
在dart
中,有一个比较特殊的条件运算符:expr1 ?? expr2
- 如果expr1是null,则返回expr2的结果,如果expr1不是null,直接使用expr1的结果。
1 | // var temp = 'why'; |
在swift
中,没有条件运算符,只能通过三目运算符实现。
4.级联语法
在dart
中,通过级联语法,可以对一个对象进行连续的操作。
1 | class Person { |
函数
Dart
是一门真正面向对象的语言,甚至其中的函数也是对象,并且有它的类型Function
。且函数是一等对象可以被赋值给变量、作为参数传递或者作为函数的返回值。
函数的定义方式:
1 | int sum(num num1, num num2) { |
Effective Dart
建议对公共的API使用类型注解,但是如果我们省略掉了类型,依然是可以正常工作的。
1 | sum(num1, num2) { |
箭头语法与隐式返回
如果函数中只有一句表达式,可以使用简写语法:
Dart中箭头语法:=> expr
是{ return expr; }
的简写。
1 | String greeting(String person) => "Hello, " + person + "!"; |
在箭头(=>)和分号(;)之间只能使用一个表达式,不能是语句。
Swift中隐式返回:如果一个函数的整个函数体是一个单行表达式,这个函数可以隐式地返回这个表达式。
1 | func greeting(person: String) -> String { |
可选参数
在Dart
中,定义函数如下:
1 | String magicBox(int kind, String name) { |
在调用时必须传入实参,称为必选参数。
也存在可选参数的方式定义函数。
- 命名可选参数。
1 | String magicBox(int kind, {String name}) { |
name
被设置为可选参数,所以在调用该方法时,实参可传可不传。
可以使用=
来定义可选参数的默认值。默认值只能是编译时常量。如果没有提供默认值,则默认值为null
。
1 | String magicBox({@required int kind, String name}) { |
这种可选参数的写法与上面写法的效果是一模一样的。推荐这种写法。
- 位置可选参数:
1 | String magicBox(int kind, [String name]) { |
在Swift
中,没有可选参数的概念,但是可以通过默认参数值
的方式来达到可选参数的效果。
1 | func magicBox(kind: Int, name: String="") -> String { |
将不带有默认值的参数放在函数参数列表的最前。一般来说,没有默认值的参数更加的重要,将不带默认值的参数放在最前保证在函数调用时,非默认参数的顺序是一致的,同时也使得相同的函数在不同情况下调用时显得更为清晰。
顺便介绍下,Swift
中每个函数参数都有一个参数标签(argument label)以及一个参数名称(parameter name)。默认情况下,函数参数使用参数名称来作为它们的参数标签。如果你不希望为某个参数添加一个标签,可以使用一个下划线(_)来代替一个明确的参数标签。
1 | func someFunction(argumentLabel parameterName: Int) {} |
someFunction
函数的参数标签是argumentLabel
在函数外部调用的时候使用,参数名称是parameterName
在函数体内使用。
1.二者都可以给参数设置默认值。2.在
Dart
中,支持可选参数,而Swift
中不支持,但是可以通过设置默认值方式实现可选参数功能。
类
在Dart
中,每个对象都是一个类的实例,所有的类都继承于Object
。
构造方法
1.Dart
和Swift
中,类没有明确指定构造方法时,将默认拥有一个无参的构造方法。我们也可以根据自己的需求,定义构造方法,当有了自己的构造方法时,默认的构造方法将会失效,不能使用。
2.Dart
不支持函数的重载(名称相同, 参数不同),而Swift
支持。
3.在实现构造方法时,通常做的事情就是通过参数给属性赋值,为了简化这一过程,Dart提供了一种更加简洁的语法糖形式。
1 | Person(String name, int age) { |
4.命名构造方法
在开发中,我们确实希望实现更多的构造方法,怎么办呢?
因为不支持方法的重载,所以我们使用命名构造方法。
1 | class Person { |
5.初始化列表
我们来重新定义一个类Point, 传入x/y,可以得到它们的距离distance:
1 | class Point { |
6.重定向构造方法
在一个构造函数中,去调用另外一个构造函数(注意:是在冒号后面使用this调用)
1 | class Person { |
7.常量构造方法
在某些情况下,传入相同值时,我们希望返回同一个对象,这个时候,可以使用常量构造方法.
将构造方法前加const进行修饰,那么可以保证同一个参数,创建出来的对象是相同的
1 | main(List<String> args) { |
注意点:
一:拥有常量构造方法的类中,所有的成员变量必须是final修饰的。
二: 为了可以通过常量构造方法,创建出相同的对象,不再使用new关键字,而是使用const关键字。如果是将结果赋值给const修饰的标识符时,const可以省略。
8.工厂构造方法
Dart提供了factory关键字, 用于通过工厂去获取对象
1 | main(List<String> args) { |
访问器与设置器
在Dart
中使用方式如下:
1 | main(List<String> args) { |
继承
面向对象的三大特性之一就是继承,不仅提高了代码的复用性,也是多态的前提。
Dart中,父类的所有成员变量和方法都会被继承,但是构造方法除外。
1 | main(List<String> args) { |
子类可以拥有自己的成员,并且可以对父类的方法进行重写:
1 | // 所有的类都继承自Object,即使没有显示声明。 |
子类的构造方法在执行前,将隐式调用父类的无参默认构造方法,如果父类没有无参默认构造方法,则子类的构造方法必须在初始化列表中通过super显式调用父类的某个构造方法。
1 | main(List<String> args) { |
抽象类
约束子类共同的行为。
1 | // 抽象类Shape |
1.抽象类中有声明没有实现的方法是抽象方法。
2.抽象类中的抽象方法必须被子类实现,抽象类中已经被实现方法,可以不被子类重写。
3.抽象类只能通过工厂构造器实例化。
隐式接口
Dart中,接口比较特殊,没有一个专门的关键字来声明接口。
默认情况下,定义的每个类都相当于也声明了一个接口,可以由其他的类来实现。
1 | abstract class Run { |
当类做接口使用时, 那么实现这个接口的类, 必须实现这个接口中所有方法。
Mixin混入
Dart中,通过implements实现某个类时,类中所有的方法都必须被重新实现,无论这个类原来是否已经实现过该方法。
但是某些情况下,一个类可能希望直接复用之前类的原有实现方案,Dart提供了Mixin混入的方案。
- 除了可以通过class定义类之外,mixin关键字也可以定义一个类。
- mixin定义的类用于被其他类混入使用,通过with关键字来进行混入。
1 | main(List<String> args) { |
枚举类型
枚举类型中有两个比较常见的属性:
index: 用于表示每个枚举常量的索引,从0开始。
values: 包含所有枚举值的List。
1 | main(List<String> args) { |
泛型
库的使用
在Dart中任何一个dart文件都是一个库,即使你没有用关键字library声明。
导入
import语句用来导入一个库,后面跟一个字符串形式的Uri来指定要引用的库,语法如下:
1 | import '库所在的uri'; |
1,常见的库URI有三种不同的形式
- dart标准库
1 | // `dart:`前缀表示Dart的标准库。 |
- 自定义库
使用相对路径导入。
1 | // 可以用相对路径或绝对路径的dart文件来引用 |
- 第三方库
Pub包管理工具管理的一些库,包括自己的配置以及一些第三方的库,通常使用前缀package。
1 | // Pub包管理系统中有很多功能强大、实用的库 |
2,库文件中内容的显示和隐藏
如果希望只导入库中某些内容,或者刻意隐藏库里面某些内容,可以使用show
和hide
关键字。
show关键字:可以显示某个成员(屏蔽其他)
hide关键字:可以隐藏某个成员(显示其他)
1 | import 'lib/student/student.dart' show Student, Person; |
3,库中内容和当前文件中的名字冲突
当各个库有命名冲突的时候,可以使用as关键字来使用命名空间。
1 | import 'lib/student/student.dart' as Stu; |
自定义
1,在定义库时,可以使用library
关键字给库起一个名字。
1 | library math; |
2,part关键字
在开发中,如果一个库文件太大,将所有内容保存到一个文件是不太合理的,我们有可能希望将这个库进行拆分,这个时候就可以使用part关键字了。不过官方已经不建议使用这种方式了。
mathUtils.dart文件
1 | part of "utils.dart"; |
dateUtils.dart文件
1 | part of "utils.dart"; |
utils.dart文件
1 | part "mathUtils.dart"; |
3,export关键字
官方不推荐使用part关键字,那如果库非常大,如何进行管理呢?
将每一个dart文件作为库文件,使用export关键字在某个库文件中单独导入。
mathUtils.dart文件
1 | int sum(int num1, int num2) { |
dateUtils.dart文件
1 | String dateFormat(DateTime date) { |
utils.dart文件
1 | library utils; |