Dart基础(一)

2023-03-16  本文已影响0人  seph_von

基础类型

Number类型

Number中包含了两个类型intdouble。分别代表整数类型和双精度浮点类型。

int a = 1;
int b = 0xDEFF0;
var c = 2;

注意:通过int类型来定义变量时,如果定义的是全局变量一定要赋值(或声明late),否则编译器会报错。如果是定义局部变量,则在使用前必须赋值,否则使用时会抛出异常。这是因为在dart的空安全机制的限制。

    var a = 1.0;
    double b = 2.0;
    double c = 1; 

其他

Number类型的变量都支持基本的运算符+ - * /等,还有ceil() abs() floor()等方法。整型支持传统的位移操作,比如移位(<<>>>>>)、补码 (~)、按位与 (&)、按位或 (|) 以及按位异或 (^)。

print((3 << 1) == 6); // true; 0011 << 1 == 0110
print((3 | 4) == 7); // true; 0011 | 0100 == 0111
print((3 & 4) == 0); // true; 0011 & 0100 == 0000

String

Dart中的字符串包含了 UTF-16 编码的字符序列。可以使用单引号或者双引号来创建字符串

var str1 = '我是一个字符串';
var str2 = "我也是一个字符串"

'"的区别:在'中需要使用\来转义那些与单引号冲突的字符:

var str1 = 'it\'s easy to escape the string delimiter';

模版字符串

在字符串中,请以 ${表达式} 的形式使用表达式,如果表达式是一个标识符,可以省略掉 {}。如果表达式的结果为一个对象,则 Dart 会调用该对象的 toString 方法来获取一个字符串。

var s = 'string interpolation';
print('Dart has $s, which is very handy.' ==
    'Dart has string interpolation, '
        'which is very handy.'); // true
print('That deserves all caps. '
        '${s.toUpperCase()} is very handy!' ==
    'That deserves all caps. '
        'STRING INTERPOLATION is very handy!'); // true

字符串字面量是一个编译时常量,只要是编译时常量 (null、数字、字符串、布尔) 都可以作为字符串字面量的插值表达式:

// 这里定义为常量是可行的
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';

// 非常量的字符串是不被允许使用在定义字符串的模版内
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];

const validConstString = '$aConstNum $aConstBool $aConstString';
// const invalidConstString = '$aNum $aBool $aString $aConstList';

字符串拼接

我们可以使用+号或者并列放置在多行的字符串来拼接字符串。

var str1 = 'the + operate' + ' works';
var str2 = 'String '
    'concatenation'
    " works even over line breaks.";

多行字符串

使用三个' 或者三个"来定义多行字符串

var s1 = '''
You can create
multi-line strings like this one.
''';
var s2 = """This is also a
multi-line string.""";

raw字符串

通过在字符串前加上r做前缀可创建raw字符串,即字符串不会被做任何处理(如转义)。

var s = r'In a raw string, not even \n gets special treatment.';
print(s); // In a raw string, not even \n gets special treatment.

String与Number类型转换

下面是字符串与数字类型的转换方式:

// String -> int
var one = int.parse('1');
print(one == 1); // true

// String -> double
var onePointOne = double.parse('1.1');
print(onePointOne == 1.1); // true

// int -> String
String oneAsString = 1.toString();
print(oneAsString == '1'); //true

// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
print(piAsString == '3.14'); //true

布尔型

Dart 使用 bool 关键字表示布尔类型,布尔类型只有两个对象 truefalse,两者都是编译时常量

Dart的类型安全检查不允许出现一个非bool型的判断,例如if(0) assert(1);

List

Dart使用 bool 关键字表示数组类型,字面量是由逗号分隔的一串表达式或值并以方括号 [] 包裹而组成的:

var lList = [1,2,3]; // 编译器会自动推断出数组的类型List<int>,如果向数组里添加一个非int类型,会报错

在字面量前面加上关键字 const,会定义一个编译时常量,那么就不能执行赋值操作,如:

var list = const [1,2,3];
list[1] = 0; // 报错!!

索引

跟其他语言一样,在Dart里,List的索引也是从0开始的,最后一个元素的索引位置位length-1,可以通过[]来获取对应索引的值。

var list = [1, 2, 3];
print(list.length); // 3
print(list[1]); // 2

list[1] = 1;
print(list[1]); // 1

扩展符

Dart提供了 ......?的扩展操作,可以将数组中所有元素插入另一个数组内, 而 ...? 空判断扩展可以避免将null插入到目标数组。

var list = [1, 2, 3];
var list2 = [0, ...list];
print(list2.length); // 4
print(list2); // [0,1,2,3] 

List? list3 = null;
var list4 = [0, ...?list3];
print(list4); // 1

控制语句

Dart 还同时引入了 集合中的 if 和 集合中的 for 操作,在构建集合时,可以使用条件判断 if和循环 for

var promoActive = false;
var nav = ['Home', 'Furniture', 'Plants', if (promoActive) 'Outlet'];
print(nav); // ['Home', 'Furniture', 'Plants'];

var listOfInts = [1, 2, 3];
var listOfStrings = ['#0', for (var i in listOfInts) '#$i'];
print(listOfStrings[1]); // #1

集合

Dart中使用Set来表示集合类型,它是一组特定集合的无序集合。可以通过字面量{}Set类来定义

var set = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};

Dart 会根据字面量来推断变量是一个Set<String>类型,如果往set对象中添加其他类型的元素,会抛异常

可以通过在{}前加上类型来定义一个空的集合,或者通过将{}赋值给一个Set类型的变量来实现。

var set = <String>{};
Set set2 = {};

Map的字面量语法和Set的字面量语法很接近,因为现有Map的字面量语法,因此{}定义的是一个Map而不是Set,Dart会为{}创建一个Map<dynamic, dynamic>对象。

常用用法

Map

Map 是用来关联 keysvalues 的对象。其中键和值都可以是任何类型的对象。每个键只能出现一次但是值可以重复出现多次。 Dart中 Map 提供了 Map 字面量以及 Map 类型两种形式的 Map

    var gifts = {
      // Key:    Value
      'first': 'partridge',
      'second': 'turtledoves',
      'fifth': 'golden rings'
    };
    var nobleGases = {
        2: 'helium',
        10: 'neon',
        18: 'argon',
    };

Dart 将gifts 推断为Map<String, String>类型,而将nobleGases推断位Map<int, String>类型,如果向其中添加不正确的类型,则会抛出异常。

    var gifts = Map<String, String>();
    gifts['first'] = 'partridge';
    gifts['second'] = 'turtledoves';
    gifts['fifth'] = 'golden rings';
    var nobleGases = Map<int, String>();
    nobleGases[2] = 'helium';
    nobleGases[10] = 'neon';
    nobleGases[18] = 'argon';

Map的常用用法

函数

Dart是一种真正面向对象的语言,所以即便函数也是对象并且类型为 Function,这意味着函数可以被赋值给变量或者作为其它函数的参数。

我们可以像这样定义一个函数 :

bool isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

也可以省略 返回类型和参数类型(不建议这样做)

 isNoble(atomicNumber) {
   return _nobleGases[atomicNumber] != null;
}

如果函数内只包含一个表达式,那么也可以简写成:

bool isNoble(int atomicNumber)=> _nobleGases[atomicNumber] != null;

语法 => 表达式是 { return 表达式; } 的简写, => 有时也称之为箭头函数; =>后面只能跟表达式,不能跟if判断语句

参数

函数的参数主要分两种: 必要参数可选参数。必要参数必须定义在参数列表前面,可选参数定义在必要参数的后面。可选参数可以是「命名的」也可以是「位置的」。

命名参数

命名参数默认时可选的,除非使用了required关键字标记。
命名参数使用 {param1, param2}来定义,如果没有指定默认值,没有required标记,默认值为null

void enableFlags({bool? bold, bool? hidden}){
    ...
}
//使用
enableFlags(bold:true, hidden:false);

可以使用 = 来给参数指定默认值,指定的默认值必须时一个常量

void enableFlags({bool bold = false, bool hidden = false}) {...}

// hidden参数位false
enableFlags(bold: true);

如果希望某个参数时必须要传的,那么就可以使用required来修饰,例如:

const Scrollbar({super.key, required Widget child});

如果创建一个Scrollbar不包含child的时,编译器就会报错

required 参数也是可以为null的。

位置参数

使用 [] 将一系列参数包裹起来,即可将其标记为位置参数,因为它们的默认值是 null,所以如果没有提供默认值的话,它们的类型必须得是允许为空 nullable 的类型

String say(String from, String msg, [String? device]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  return result;
}
//不使用位置参数调用函数
print(say('Bob', 'Howdy')); // Bob says Howdy
//使用位置参数调用函数
print(say('Bob', 'Howdy', 'smoke signal')); //Bob says Howdy with a smoke signal

可以使用 = 来为一个位置可选参数指定除了 null 以外的默认值。指定的默认值必须要为编译时的常量

String say(String from, String msg, [String device = 'carrier pigeon']) {
  var result = '$from says $msg with a $device';
  return result;
}

print(say('Bob', 'Howdy'));  //Bob says Howdy with a carrier pigeon

mian()

main() 顶级函数作为程序的入口, main() 函数返回值为 void 并且有一个 List<String> 类型的可选参数。

函数是一级对象

可以将函数作为参数传递给另一个函数。例如:

void printElement(int element) {
  print(element);
}

var list = [1, 2, 3];

// 将printElement作为一个参数
list.forEach(printElement); // 1 2 3

也可以将函数赋值给一个变量,比如:

var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
print(loudify('hello')); // !!! HELLO !!!

匿名函数

顾名思义,就是没有名字; 通常称为 匿名函数Lambda 表达式Closure 闭包;可以将匿名函数赋值给一个变量然后使用。
匿名函数的定义如下

(param1, params2) {
    ...
}

下面例子就是定义了一个只有一个参数item的匿名函数用来打印List中每个字符串和字符串长度:

const list = ['apples', 'bananas', 'oranges'];
list.map((item) {
  return item.toUpperCase();
}).forEach((item) {
  print('$item: ${item.length}'); // APPLES: 6 BANANAS: 7 ORANGES: 7
});

运算符

下表中是常用的运算符,表中从上到下也表示运算符的优先级顺序。

描述 操作符
一元后缀 expr++ expr-- () [] ?[] . ?. !
一元前缀 -expr !expr ~expr ++expr --expr await expr
乘除运算 * / % ~/
加减运算 + -
位移 << >> >>>
位运算AND &
位运算异或 ^
位运算或 |
关系类型判断 >= > <= < as is is!
相等 == !=
逻辑与 &&
逻辑或
如果空 ??
三元运算 expr1 ? expr2 : expr3
级联 .. ?..
复合运算 = *= /= += -= &= ^= etc.

类型判断

|操作符|含义|
|--|--|
|as|类型转换|
|is|如果对象是指定对象返回true|
|is!|如果对象是指定对象返回false|

obj 实现了 T 接口时, obj is T 才会返回 true
只有当obj明确是某个对象类型时,才使用as

// 1
(employee as Person).firstName = 'Bob';
// 2
if (employee is Person) {
  // 类型检查
  employee.firstName = 'Bob';
}

在上面例子中,如果 employeenull 或者不是Person类型时, 注释1处语句就会抛出异常,而注释2处不会抛出异常。

赋值运算

??= 使用场景 obj ??= 123 ,当objnull时,才会赋值 123否则不处理。

条件表达式

表达式1 ?? 表达式2

如果表达式 1 为非 null 则返回其值,否则执行表达式 2 并返回其值

级联表达式

级联运算符 .., ?.. 可以在同一个对象上连续调用多个对象的变量或方法

var paint = Paint()
  ..color = Colors.black
  ..strokeCap = StrokeCap.round
  ..strokeWidth = 5.0;

等同于代码:

var paint = Paint();
paint.color = Colors.black;
paint.strokeCap = StrokeCap.round;
paint.strokeWidth = 5.0;

如果对象可能为null的话,可以使用?..

querySelector('#confirm') 
  ?..text = 'Confirm' 
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'))
  ..scrollIntoView();

代码等同于

var button = querySelector('#confirm');
button?.text = 'Confirm';
button?.classes.add('important');
button?.onClick.listen((e) => window.alert('Confirmed!'));
button?.scrollIntoView();

级联对象可以嵌套使用:

final addressBook = (AddressBookBuilder()
      ..name = 'jenny'
      ..email = 'jenny@example.com'
      ..phone = (PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();

在调用返回对象的函数时,一定要谨慎使用级联操作;如果函数返回void,那么就不能使用级联操作。

其他运算符

操作符 含义
?[] 判空访问List,不为空时访问List中元素
?. 条件访问成员,不为空时访问成员
断言操作,认为一定不为空访问相关成员,如果为空抛出异常

控制语句

if-else

与其他语言类似,通过条件判断执行代码块 其中 elseelse if 是可选判断。但是判断的条件一定是bool型,不可以是其他类型。

if(表达式1){
...
}else if(表达式2){
...
}else{
...
}

for循环

while 和 do-while循环

whiledo-while的区别是:

contin 和 break

continue 表示跳过此次循环,break表示跳出循环

如果在Iterable对象中,可以使用where代替continue

candidates
    .where((c) => c.yearsExperience >= 5)
    .forEach((c) => c.interview());

switch-case

Switch 语句在Dart中使用 == 来比较整数、字符串或编译时常量,比较的两个对象必须是同一个类型且不能是子类并且没有重写 == 操作符。 枚举类型非常适合在 Switch 语句中使用。

非空case想要实现穿透可通过continue来实现:

var command = 'CLOSED';
switch (command) {
  case 'CLOSED':
    executeClosed();
    continue nowClosed;

  nowClosed:
  case 'NOW_CLOSED':
    executeNowClosed();
    break;
}

每个case内都可以有局部变量,并且只在当前case可见。

注释

单行注释

单行注释以//开始,所在行的内容都属于注释内容

// 这是一个单行注释

多行注释

多行注释以/*开头,以*/结尾,在/**/之间的内容都会被编译器忽略,认为是注释内容

/*
这是一个多行注释
注释第二行内容
...
*/
/*
嵌套注释的外层
  /*
    嵌套注释内层
  */
嵌套注释外层
*/

文档注释

文档注释使用/// 或者是/**,多个连续///注释与多行注释效果一致。多行文档注释,编译器会忽略注释的内容,但是如果使用了[],则编译器会产生引用括号内的内容如类、方法、字段、顶级变量、函数和参数。

///这是一个文档注释举例
///如果使用了中括号,则会解析括号内容,引用相关内容[feed]

上面举例中[feed]将会生成一个链接,指向feed的方法文档

上一篇下一篇

猜你喜欢

热点阅读