这节我们学习下Dart语言的主要语法
需要说明的是,文章只做主要的摘录
具体参考:Dart 编程语言概览
可以在线运行Dart语句的编译器DartPad
- 在 Dart 中一切都是对象,数字类型 也不例外
主函数
main(){
print("你好啊");
}
变量
-
未初始化的变量默认值是 null。
即使变量是数字 类型默认值也是 null,因为在 Dart 中一切都是对象,数字类型 也不例外。 -
定义一个变量可以使用:明确声明(显式声明)和隐式声明
main(){
//明确变量类型
String name = "你好";
//隐式声明
var name2 = "nihao222";
print("$name, $name2");
}
显式声明没啥说的,我们常常使用
隐式声明定义变量的时候,不需要具体指出变量的类型。可以通过后面的变量类型推导出来变量的具体类型。
- 隐式声明又分为两大类:可变和不可变类型
var修饰的是可变类型
const和final修饰不可变类型变量
也就是,不管是const还是final修饰的变量,都不可变
两者的区别:
Final 变量的值只能被设置一次;
Const 变量在编译时就已经固定 ;
可以使用final修饰的变量,在运行时确定。或者说可以使用函数返回值赋值给final修饰的变量
类比OC,普通的定义int a = 10;a都是可变类型
想要a不变,一般使用const int a = 10;但不常用
因此,一般对象可变情况的居多,也就是使用var居多
-
如果 Const 变量是类级别的,需要标记为 static const
-
Dart没有非零即真
也就是,必须是true或者false
变量类型
Dart 语言支持以下类型:
Number
String
Boolean
List (也被称为 Array)
Map
Set
Rune (用于在字符串中表示 Unicode 字符)
Symbol
标记为黄色的两个没见过
Number分为int和double
Number与String之间的转换:
main() {
//String->int
var one = int.parse("10");
print(one.runtimeType);
//String->double
var two = double.parse("10.9");
print(two.runtimeType);
//int->String
String str1 = 1.toString();
print("$str1, ${str1.runtimeType}");
//double->String
//保留4位小数
String str2 = 3.1415926.toStringAsFixed(4);
print("$str2, ${str2.runtimeType}");
}
运行结果:
int
double
1, String
3.1416, String
- 字符串和其他变量或表达式拼接:使用${expression},
如果表达式是一个标识符, 那么{}可以省略 - == 运算符用来测试两个对象是否相等。 在字符串中,如果两个字符串包含了相同的编码序列,那么这两个字符串相等。
换行
main() {
String moreLineString = '''
你好
哈喽
www
''';
print(moreLineString);
}
这个相当于OC中的\n
试了下
main() {
String moreLineString = '你好\n哈喽\nwww\n111';
print(moreLineString);
}
结果:
你好
哈喽
www
111
换行也识别
函数
Dart的函数不支持函数重载
函数的参数:可以分为必传参数、可选参数
可选参数分为:
位置可选参数、命名可选参数
位置可选参数
位置可选参数,使用[]括起来。在使用的时候,必须按顺序书写。不同类型的参数,不能乱序传
命名可选参数
命名可选参数使用{}括起来,在使用的时候必须把变量名放前面。(例如height: )
命名可选参数,里面的参数都可以赋值,也可以都不赋值,也可以单独调用某一个参数
main() {
sayHello("你好",height: 19.3);
}
void sayHello(String name, {int age, double height})
{
print("$name, $age, $height");
}
只有可选参数才可以设置默认值
void sayHello(String name, {int age = 10, double height = 19.2})
{
print("$name, $age, $height");
}
Dart中函数是第一公民,即:可以作为函数的参数或返回值
匿名函数
main() {
niMingFunction((){
print("匿名函数被调用了");
});
//niMingFunction();是调用这个函数
//里面的参数是一个匿名函数,没有返回值,没有参数,没有名字,有函数体
}
//定义一个函数,该函数的参数是一个函数,并且调用这个函数就执行foo();
void niMingFunction(Function foo){
foo();
}
除了匿名函数外,还有一个:箭头函数
调用箭头函数的条件是:函数体只有一行代码
main() {
test(() => print("箭头函数被调用"));
}
void test(Function foo){
foo();
}
Dart可以将函数作为参数和返回值,这个还是挺不错的
遇到参数有返回值,有参数,如何写,如何传递呢?
main() {
test((num1, num2){
return num1 * num2;
});
}
//test函数里面的参数是一个函数
//test函数里面的函数体是打印test参数函数
void test(int foo(int num1, int num2)){
print("${foo(2, 6)}");
}
??=运算符
如果当前变量有值,则??=不执行
如果当前变量为null,则??=执行
main(){
var name = null;
name ??= "456";
print(name);//456
}
class
初始化的语法糖:
class Person {
String? name;
Person(String name){
this.name = name;
}
//写成这样:
Person(this.name)
}
命名构造函数
当我们有两个参数,然后去初始化,现在增加1个参数,现在还需要初始化
如果之前有10个地方用到了这个对象,那么需要将10个地方,都重新初始化
当然,可以借助可选参数,将新增加的参数设置为可选的
但是,如果要求,新的参数就是必填的。就是,旧的可以是两个参数,而新的必须是三个参数,怎么办呢?
这就用到了命名构造函数
import 'dart:ffi';
main(){
Person p1 = Person("丽丽", 11);
Person p2 = Person.withNameAgeHeight("小丽", 12, 12.0);
print(p1.age);
print("${p2.name}, ${p2.height}");
}
class Person {
String name;
int age;
double? height;
Person(this.name, this.age);
//命名构造函数
Person.withNameAgeHeight(this.name, this.age, this.height);
}
Object和dynamic的区别
所有类,都继承父类Object,即:Object 是所有类的顶层父类
区别就在于:
使用Object的时候,编译的时候就会查看是什么类型
dynamic 类型告知编译器“关闭类型检查”
使用dynamic的时候,编译的时候不报错,但是在运行的时候有安全隐患
Object obj = "12345";
//print(obj.substring(0));编译报错
dynamic obj2 = "12345";
print(obj2.substring(0));//编译不报错
工厂构造函数
使用factory修饰的构造函数,最大的特点是:可以手动返回一个对象
而普通的构造函数:会自动返回创建出来的对象,不能手动返回
set、get方法
main(){
var p1 = Person();
p1.setName = "123";
print(p1.getName);//123
}
class Person {
String _name = "";
//set方法
set setName(String name){
_name = name;
}
//get方法
String get getName{
return _name;
}
}
继承
Dart只支持单继承
main(){
Person p1 = Person("123", 12);
print(p1.name);
print(p1.age);
}
class Animal{
int age = 0;
Animal(this.age);
}
class Person extends Animal {
String name = "";
//子类需要初始化父类的age属性(固定写法)
Person(this.name, int age) : super(age);
}
抽象类abstract
抽象类里面的方法可以只声明。 (普通类不可以只声明)
方法也可以直接实现
当类继承抽象类的时候,就必须实现里面的抽象方法
abstract class Square{
//仅声明,不实现
int getArea();
//也可以实现
String getInfo(){
return "形状";
}
}
class Rectangle extends Square{
//必须实现
int getArea() {
return 10;
}
}
抽象类不能实例化,即直接final s = Square()
❌
隐式接口
Dart中没有interface/protocol这种接口关键字
而是,默认情况下,所有的类都是隐式接口
class Runner {
void running(){
}
}
class Flyer{
void flying(){
}
}
//同时实现两个类的所以方法
class SuperMan implements Runner, Flyer{
void flying() {
// TODO: implement flying
}
void running() {
// TODO: implement running
}
}
mixin混入
类属性、类方法
static 修饰的属性,就是类属性
static 修饰的方法,就是静态(类)方法
库的导入
系统库的导入:import 'dart:math';
三方库的导入:import 'utils/xxx.dart;'
当系统库与自己定义库的函数名重名的时候,可以将三方库起别名,然后通过别名去调用三方库里面的函数
import 'utils/xxx.dart' as mUtils;
print(mUtils.sum(10, 20));
当导入一个库的时候,默认会将里面所以的内容(除了_开头的)都导入进去,如果只想导入某个函数,或者不导入某个函数的话,可以使用关键字show
或hide
import 'utils/xxx.dart' show sum, sum2
import 'utils/xxx.dart' hide sum, sum2
yaml
配置信息在.yaml文件里面
很多三方库在:pub.dev
里面
顶级函数
Dart 支持顶级函数
理解的顶级函数,即不属于任何类的函数,比如下面的例子:
void foo() {} // 顶级函数
class A {
static void bar() {} // 静态方法
void baz() {} // 示例方法
}
void main() {
var x;
// 比较顶级函数。
x = foo;
assert(foo == x);
// 比较静态方法。
x = A.bar;
assert(A.bar == x);
// 比较实例方法。
var v = A(); // A的1号实例
var w = A(); // A的2号实例
var y = w;
x = w.baz;
// 两个闭包引用的同一实例(2号),
// 所以它们相等。
assert(y.baz == x);
// 两个闭包引用的非同一个实例,
// 所以它们不相等。
assert(v.baz != w.baz);
}
参考:Kotlin顶级函数
-
Dart支持函数内创建函数
即函数嵌套 或 局部函数 -
Dart 支持顶级变量
-
Dart 没有关键字 “public” , “protected” 和 “private” 。 如果标识符以下划线(_)开头,则它相对于库是私有的。