首页 > 其他分享 >Flutter/Dart第06天:Dart基础语法详解(变量)

Flutter/Dart第06天:Dart基础语法详解(变量)

时间:2023-10-01 21:55:38浏览次数:48  
标签:初始化 const 变量 final Dart 06 null Flutter

Dart官网文档:https://dart.dev/language/variables

重要说明:本博客基于Dart官网文档,但并不是简单的对官网进行翻译,在覆盖核心功能情况下,我会根据个人研发经验,加入自己的一些扩展问题和场景验证。

Dart中的变量

变量是一个对象的引用,引用名就是变量的名称;就算引用是null的变量也一样。

变量有3种定义方式:var关键字,显示类型Object/dynamic类型。

var varName = 'Tom';
String strName = 'Tom';
Object objName = 'Tom';
dynamic dynName = 'Tom';

最佳实战:对于局部变量,优先使用var关键字,其次为显示类型,再次为Object,不推荐使用dynamic(原因:容易引发运行时错误,后续的学习会讲到)。

当使用var关键字定义的变量,Dart会根据值内容,推导出变量的实际类型,如上诉代码varName变量最终为String类型。

Null safety空安全

Dart语言强制健壮空安全。空安全可以防止意外使用null而导致的错误(还记得在Java编程中,在很多对象使用的地方,我们都需要进行null判断,以防止NPE的发生)。Dart在编译期间,就会进行null潜在错误检测分析,从而防止这些错误的发生(注意:并不是所有场景都能检测分析到,后面章节会讲到)。

代码样例:如下代码,变量strName的默认值为null,在其他编程语言如Java语言中,下面的代码是合法的,但是在运行时,当执行strName.length时会引发NPE异常;但是在Dart语言中,以下代码是非法的(无法编译),因此阻止发生NPE等这些潜在的错误。

String strName;
print(strName.length)

Dart为了强制执行空安全,有3个关键改变

  1. 如果明确希望某个变量、参数或者其他组件是可以为null的,那么需要在类型后面增加一个?标识:
String? name  // `name`的值可能为`null`, 或者为某个字符串
String name   // `name`的值只能是某个字符串,不能为`null`
  1. Dart的变量在使用之前,必须被初始化。可空变量(含有?标识)的默认值为null,即默认初始化为null,因此无需显示的赋值初始化;而非空变量因没有默认值,因此必须显示赋值初始化。
  2. 禁止直接访问可空类型的属性或者表达式方法,包括访问null对象的hashCodetoString()方法(记住:Dart中一起皆对象,null也是),也会引发错误。

Dart空安全通过以上3个关键改变,保证null潜在错误在代码编写阶段就能被前置发现,而不是等到代码运行时。

变量默认值

第2章节中,其实已经提到一点:任何变量在使用之前,必须被初始化;可空变量因为默认值为null,因此可无需显示初始化;非空变量必须显示初始化。

特别注意:非空变量只需要确保它在被使用时已经初始化即可,而不是必须在申明的时候。如下代码,变量lineCount在申明时并未初始化,但是在print被使用时,Dart语言检测到它已经被初始化了,因此如下代码是空安全有效代码。

// 申明:未被初始化
int lineCount;

if (weLikeToCount) {
  lineCount = countLines();
} else {
  lineCount = 0;
}

// 使用:Dart检测到已经被初始化,因此是可以使用
print(lineCount);

late延迟变量

顶级变量和类变量会延迟初始化,当第一次使用到这些变量时,初始化代码的逻辑才会被执行(即:延迟初始化)。

在大多数情况下,Dart可以检测并分析一个非空变量在使用时已经初始化,但是在有些场景下,Dart无法检测分析或者检测分析会失效。最常见的2种场景:顶级变量实例变量,Dart无法确定它们在被使用时是否已经被初始化了。

如果我们明确一个非空变量在被使用之前能完成初始化(但Dart却无法检测到),可通过增加late关键字,告诉Dart该变量为延迟变量,在被使用之前确保能被初始化。当然,对于late延迟变量,在被使用时却并没有初始化,那么使用它同样会导致运行时错误

late String description;

void main() {
  description = 'Feijoada!';
  print(description);
}

late延迟变量主要处理以下2种场景:

  1. 这些变量并不是必须的,同时初始化它们非常耗时或者浪费资源(如网络交互等)。
  2. 在初始化实例变量时,需要用到实例本身。

代码样例:如下代码,当变量temperature在第1次被使用时,才会被调用readThermometer()方法,即该方法仅仅被调用1次。

late String temperature = readThermometer();

final变量和const常量

最佳实践:如果我们明确一个变量在被初始化之后,它的引用值再也不会变化,那么使用final或者const修饰,而不是使用var者显示类型

  1. const变量隐式为final变量
  2. const变量是编译期的常量变量
  3. 实例变量可以是final变量但不能是const变量(原因:实例在运行时才能确定,因此其变量无法作为编译期常量)
final name = 'Bob';
final String nickname = 'Bobby';
const bar = 1000000;
const double atm = 1.01325 * bar;

特别注意:const不仅可以申明如上代码的常量变量,它也可以用于申明创建常量值,也可以用于申明创建常量值的构造器(还记得第2天学习内容:const构造函数?);同时,任何变量,都可以有常量值。

// 1. 常量值
var foo = const [];
final bar = const [];
const baz = []; // 等同:`const []`

// 2. 非final/const变量,它的常量值可以更新
foo = const [1, 2, 3];

特别注意:常量的定义,可以包含类型检测、类型转换、集合过滤和集合展开操作符。

// `i`是一个`Object`类型常量,它的值是int数字值
const Object i = 3;

// 1. 类型转换
const list = [i as int];

// 2. 类型检测和集合过滤
const map = {if (i is int) i: 'int'};

// 3. 类型检测、集合过滤、集合展开
const set = {if (list is List<int>) ...list};

final变量const常量总结:

  1. final变量不可修改,但是它的值是可以更新
  2. const常量不可修改,同时它的值也不可以更新,即它的值是不可变的(immutable)。
void main() {
  // 1. final变量
  final finalList = [1, 2, 3];
  print('1.1 final变量: $finalList');

  // 输出:1.1 final变量: [1, 2, 3]

  finalList
    ..add(4)
    ..add(5);
  print('1.2 final变量: $finalList');

  // 输出:1.2 final变量: [1, 2, 3, 4, 5]

  // 2. const常量
  const constList = ['a', 'b', 'c'];
  print('2.1 const常量: $constList');

  // 输出:2.1 const常量: [a, b, c]

  constList
    ..add('c')
    ..add('d');
  print('2.2 const常量: $constList');

  // 错误:
  // Unhandled exception:
  // Unsupported operation: Cannot add to an unmodifiable list
  // #0      UnmodifiableListMixin.add (dart:_internal/list.dart:114:5)
}

我的本博客原地址:https://ntopic.cn/p/2023100101


标签:初始化,const,变量,final,Dart,06,null,Flutter
From: https://www.cnblogs.com/obullxl/p/NTopic2023100101.html

相关文章

  • CF906C Party
    CF906CParty洛谷:CF906CPartyCodeforces:CF906CPartyProblem有\(n\)个人,给定他们的初始认识情况,每次操作可以选择一个人,让他当前认识的所有的人都相互认识。问至少操作几次使得所有人都相互认识,并给出任意合法且次数最少的操作方案。保证操作方案存在。Solution\(n\le......
  • 2023-2024-1 20211306 密码系统设计与实现课程学习笔记4
    20211306密码系统设计与实现课程学习笔记4任务详情自学教材第7,8章,提交学习笔记知识点归纳以及自己最有收获的内容,选择至少2个知识点利用chatgpt等工具进行苏格拉底挑战,并提交过程截图,提示过程参考下面内容“我在学***X知识点,请你以苏格拉底的方式对我进行提问,一次一个问......
  • flutter windows使用多窗口方法
    最近研究flutter在Windows和MacOs操作系统上使用多窗口方法,总结一下开发心得。众所周知,flutter使用skia将像素点,通过opengl,software,metal等方式渲染到一个窗口上,不像原生开发的可以指定控件添加到具体窗口内。在flutterpub仓库管理中,看了几个大神写的多窗口方案,无一例外都是通......
  • Flutter/Dart第04天:Dart异步编程(Future和async/await)
    Dart官网代码实验室:https://dart.dev/codelabs/async-await重要说明:本博客基于Dart官网代码实验室,但并不是简单的对官网文章进行翻译,我会根据个人研发经验,在覆盖官网文章核心内容情况下,加入自己的一些扩展问题和问题演示和总结,包括名称解释、使用场景说明、代码样例覆盖、最后完......
  • 06. 系统滴答定时器
    一、SysTick定时器简介  SysTick,即系统滴答定时器,是属于CM3内核中的一个外设,内嵌在NVIC中。系统定时器是一个24bit的向下递减的计数器,SysTick的时钟源自HCLK。当计数值减到0时,将从RELOAD寄存器中自动重装载定时初值,开始新一轮计数。只要不把它在SysTick控制及状......
  • flutter编译安卓/ios命令
    一、flutter打包编译命令1、编译安卓apkflutterbuildapk--debug--flavorbeta--build-number=123--build-name=1.2.3--target-platformandroid-arm--split-per-abi--dart-define=APP_CHANNEL=vivo--dart-define=APP_NAME=TestApp 2、编译安卓AppBundle ......
  • 玩一玩“baichuan2”,很强的中文开源模型,2060s即可流畅运行!
    OpenAIChatGPT出来后,热闹了好一阵子!先是一波大厂闭源PK。然后Meta不按套路出牌,直接放出来开源的Llama1-2 后来就百花齐放了。但是外国的模型默认情况下中文支持都不好。另外很多开源模型,最简单的对话都一塌糊涂。今天来玩一个不错的中文开源模型。先来简......
  • Flutter/Dart第03天:Dart可迭代集合
    Dart官网代码实验室:https://dart.dev/codelabs/iterables重要说明:本博客基于Dart官网代码实验室,但并不是简单的对官网文章进行翻译,我会根据个人研发经验,在覆盖官网文章核心内容情况下,加入自己的一些扩展问题和问题演示和总结,包括名称解释、使用场景说明、代码样例覆盖等。可迭代......
  • Flutter开发中的一些Tips
    学习Flutter也有一阵子了。闲着没事,用了公司一个已经凉凉的App设计图来练手。当然了接口不可能用的了,所以都是些死数据,实现效果可以说是很完美了(得到了设计的认可。。。)。当然自己也是边查边写,也借鉴了许多Github上优秀的Flutter项目。现在开源出来(附带设计图),供大家交流学习。希望......
  • Postman06-前置代码块
    pre-requestscript在发送测试请求之前所要执行的代码常用于设置域名、IP,保存多个请求共用的数据等......