MirrorYuChen
MirrorYuChen
Published on 2025-08-19 / 1 Visits
0
0

Flutter入门学习笔记(二):dart基本语法

Flutter入门学习笔记(二):dart基本语法

1.Hello World

  • (1) vscode安装 dart插件
  • (2) 创建项目

​ 首先 ctrl+shift+p打开命令面板,输入 dart,选择 Dart: New Project;然后选择 Console Application及项目存放路径;最后输入项目名 hello_world

  • (3) 运行项目

​ 命令行输入如下命令,运行项目

>> dart run
Building package executable... 
Built hello_world:hello_world.
Hello world: 42!
  • (4) 源码解析

​ 项目层级结构如下:

├───bin
├───lib
└───test

​ 入口函数为 bin/hello_world.dart文件中的main函数:

// 导入hello_world包
import 'package:hello_world/hello_world.dart' as hello_world;

void main(List<String> arguments) {
  // 调用hello_world包中的calculate()函数
  print('Hello world: ${hello_world.calculate()}!');
}

​ hello_world包对应于 lib/hello_world.dart文件:

int calculate() {
  return 6 * 7;
}

​ 这里有个 calculate函数,返回42,这也就得到了最终的运行后结果:Hello world: 42!

2.变量

​ 在Dart中,可以使用显式声明方法,或使用 varObjectdynamic来声明变量,但它们在类型检查、使用方法和编译器行为上有显著区别。

2.1 显式声明

​ 直接在声明是显式指定变量类型:

String name = 'Bob';

2.2 var

​ var声明变量,可以让编译器根据初始值自动推断类型,类型推断完成后,赋值必须是相同类型。

var name = 'Bob';
print(name.runtimeType);

// name = 20; 编译错误,类型不匹配
name = 'mirror'; // 合法

2.3 Object

​ Object是所有类的基类,可以存储任何对象(包括基本类型和自定义类),但是需要显式转换,才能调用子类的特定方法。使用时,可以通过 is判断其类型,然后使用 as来完成类型转换:

Object obj = 42;
if (obj is int) {
  print(obj + 1);
}

int value = obj as int;
print('value: $value');

2.4 dynamic

​ dynamic会关闭类型检查,允许变量在运行时持有任何类型,并调用任何方法(即使调用不存在的方法,也能编译通过,这可能导致运行时错误),通常适用于动态场景(如,Json解析和反射):

dynamic d = 42;
print(d.foo());  // 编译通过,但运行时报错:NoSuchMethodError
d = 'hello';
print(d.length); // 合法(运行时类型为 String)

3.空安全

​ Dart语言要求以健全的控安全方式编写代码。空安全能防止意外访问 null变量而导致的错误,这样的错误也被称为空解引用错误。在空安全的基础上,Dart编译器可以在编译期检测这些潜在错误。

​ 空安全引入三个关键更改:

  • (1) 在类型声明末尾添加 ?控制类型是否允许 null
String? name  // 可空类型,name可以为'null',也可以为String
String name   // 不可空类型,name不可以为'null',但是可以为String
  • (2) 变量使用前必须先进行初始化。可空变量默认初始化为 null
  • (3) 不可对可空类型表达式上访问属性或调用方法。例外情况适用于 null支持的属性或方法,如,hashCodetoString()

4.三个关键字

4.1 const

​ const编译期常量,值在编译时就确定,永远不会改变。只能用于字面量、构造函数被标记为 const的对象:

const pi = 3.1415926;
const list = [1, 2, 3];
const point = Point(0, 0);

class Point {
  final int x, y;
  const Point(this.x, this.y);
}

4.2 final

​ 运行时一次性赋值,只能赋值一次,对象本身可内部可变:

final now = DateTime.now();
final list = [1, 2, 3];
list.add(4);   // 合法
// list = [5, 6]  // 编译错误:不能第二次赋值

4.3 late

​ 延迟初始化,先声明,后赋值,但是使用前必须赋值,否则会运行时抛 LateError

class Service {
  late final String config;   // 先不赋初值
  void init(String path) {
    config = path;            // 运行期再赋值
  }
}

class Lazy {
  late final heavy = _compute();   // 第一次访问时才执行 _compute
  int _compute() {
    print('compute once');
    return 42;
  }
}

void main() {
  var l = Lazy();
  print('before first use');
  print(l.heavy);   // 这里才触发 compute
  print(l.heavy);   // 第二次直接用缓存结果
}

5.操作符

5.1 基本算术运算符和逻辑运算符

assert(2 + 3 == 5);    // 加
assert(2 - 3 == -1);   // 减
assert(2 * 3 == 6);    // 乘
assert(5 / 2 == 2.5);  // 除
assert(5 ~/ 2 == 2);   // 整除
assert(5 % 2 == 1);    // 求余

assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');

int a;
int b;

a = 0;
b = ++a;        // 先自增后赋值
assert(a == b); // 1 == 1

a = 0;
b = a++;        // 先赋值后自增.
assert(a != b); // 1 != 0

a = 0;
b = --a;        // 先自减,后赋值.
assert(a == b); // -1 == -1

a = 0;
b = a--;        // 先赋值后自减.
assert(a != b); // -1 != 0

assert(2 == 2); // 等于
assert(2 != 3); // 不等于
assert(3 > 2);  // 大于
assert(2 < 3);  // 小于
assert(3 >= 3); // 大于等于
assert(2 <= 3); // 小于等于

5.2类型测试运算符

​ as(类型转换),is(是否有特定类型),is!(是否没有特定类型)

5.3 赋值运算符

​ 常见的赋值运算符有:

= *= %= >>>= ^=
+= /= <<= &= `
-= ~/= >>=
a = value;   // 将value赋值给a
b ??= value; // 当b为null时,将value赋值给b,否则,b保持原始值
a *= 2;      // 乘法复合赋值
a /= 2;     // 除法复合赋值

5.4逻辑运算符

操作符 描述
!expr 逻辑非
`
&& 逻辑与

5.5 位运算和移位运算

操作符 描述
&
` `
^ 异或
~expr
<< 左移
>> 右移
>>> 无符号右移

5.6 条件表达式

  • (1) condition满足返回 expr1的值,否则,返回 expr2的值

condition ? expr1 : expr2

  • (2) expr1非空,返回 expr1的值,否则,返回 expr2的值

expr1 ?? expr2

6.控制流

6.1 循环

// 1.for循环
var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
  message.write('!');
}

var callbacks = [];
for (var i = 0; i < 2; i++) {
  callbacks.add(() => print(i));
}

// 2.for-in循环
for (final c in callbacks) {
  c();
}

// 3.forEach循环
var collection = [1, 2, 3];
collection.forEach(print); // 1 2 3

// 4.while循环
while (!isDone()) {
  doSomething();
}

// 5.do-while循环
do {
  printLine();
} while (!atEndOfPage());

// 6.break和continue
while (true) {
  if (shutDownRequested()) break;
  processIncomingRequests();
}

for (int i = 0; i < candidates.length; i++) {
  var candidate = candidates[i];
  if (candidate.yearsExperience < 5) {
    continue;
  }
  candidate.interview();
}

6.2 分支

// 1.if-else
if (isRaining()) {
  you.bringRainCoat();
} else if (isSnowing()) {
  you.wearJacket();
} else {
  car.putTopDown();
}

// 2.if-case
if (pair case [int x, int y]) {
  print('Was coordinate array $x,$y');
} else {
  throw FormatException('Invalid coordinates.');
}

// 3.switch-case
var command = 'OPEN';
switch (command) {
  case 'CLOSED':
    executeClosed();
  case 'PENDING':
    executePending();
  case 'APPROVED':
    executeApproved();
  case 'DENIED':
    executeDenied();
  case 'OPEN':
    executeOpen();
  default:
    executeUnknown();
}

6.3 错误处理

// 1.Throw
throw FormatException('Expected at least 1 section');
// 2.try-catch-finally
try {
  breedMoreLlamas();
} catch (e) {
  print('Error: $e'); // Handle the exception first.
} finally {
  cleanLlamaStalls(); // Then clean up.
}
// 3.assert
assert(text != null);

7.参考资料


Comment