关于dart:实现Dart版本对象存储COS插件

前言在 Flutter Web 在《一起漫部》的性能优化摸索与实际 一文中,在做加载优化时须要实现资源文件cdn化,意味着要将资源文件上传到腾讯的COS或者阿里的OSS这样的第三方对象存储服务器。 目前公司应用的是腾讯的对象存储(COS),本来想用官网提供的SDK去实现资源上传性能,然而官网并没有提供Dart版本的SDK, 去pub.dev搜了下对于cos的相干插件,也没有找到性能绝对欠缺的插件,于是便打算手写一个Dart版本对象存储(COS)插件。 简介在官网提供的API性能过于丰盛和工夫无限的状况下,只实现了局部性能: 反对Bucket接口的基本操作,减少、删除、查问存储桶等反对Bucket接口的访问控制(acl)反对Bucket接口的跨域资源共享(cors)反对Bucket接口的防盗链(referer)反对Object接口的基本操作,上传、删除、查问存储对象等反对Object接口的访问控制(acl)构造工程次要包含示例(example)、外围代码(lib)和单元测试(test)三局部 ├── CHANGELOG.md├── LICENSE├── README.md├── analysis_options.yaml├── example // 示例├── lib // 外围代码│ ├── src│ │ ├── api│ │ ├── client│ │ ├── model│ │ └── src.dart│ └── tencent_cos_plus.dart├── pubspec.lock├── pubspec.yaml├── tencent_cos_plus.iml└── test // 单元测试示例示例目前仅包含tencent_cos_plus_example.dart文件,次要是介绍如何应用插件,包含初始化配置、存储桶Api调用和存储对象 Api调用。 ├── example│ └── tencent_cos_plus_example.dart外围代码外围代码(lib)局部由client、api和model三层形成: client层封装了http申请和接口签名性能api层实现了存储桶(bucket)和存储对象(object)局部api的调用model层负责xml数据和实体对象的解析├── api│ ├── api.dart│ ├── cos_abstract_api.dart│ ├── cos_api_factory.dart│ ├── cos_api_mixin.dart│ ├── cos_bucket_api.dart│ └── cos_object_api.dart├── client│ ├── client.dart│ └── cos_client.dart├── model│ ├── common│ │ ├── cos_access_control_policy.dart│ │ ├── cos_common.dart│ │ ├── cos_config.dart│ │ ├── cos_cors_configuration.dart│ │ ├── cos_exception.dart│ │ └── cos_referer_configuration.dart│ ├── model.dart│ ├── request│ │ ├── cos_bucket_acl_header.dart│ │ ├── cos_create_bucket_configuration.dart│ │ ├── cos_delete.dart│ │ ├── cos_get_object.dart│ │ └── cos_restore_request.dart│ └── response│ ├── cos_copy_object_result.dart│ ├── cos_delete_result.dart│ ├── cos_list_all_my_buckets_result.dart│ ├── cos_list_bucket_result.dart│ └── cos_list_versions_result.dart单元测试单元测试包含cos_bucket_api_test.dart和cos_object_api_test.dart两个文件,次要是笼罩了存储桶(bucket)和存储对象(object)局部api的单元测试 ...

October 21, 2022 · 1 min · jiezi

关于dart:Dart的混入概念和Vue3的混入概念

Dartmixin即mix in,中文翻译过去是“混入”,就是在类中混入其余性能 在Dart官网中的定义是Mixins are a way of reusing code in multiple class hierarchies.翻译过去就是“Mixins是一种在多类层次结构中复用代码的一种形式” Dart的mixins应用首先用mixin关键字定义一个mixin类对于mixin关键字能够这样了解,定义类用class,定义接口用interface,而定义Mixins用的就是mixin A {void a() {print('A');}}而后用with关键字混入一个mixin类对于with关键字也能够这样了解,集成类用extends,实现接口用implements,而混入Minxins用的就是withvoid main() { Mix m = Mix(); m.a();} 多混入Mixins反对多混入,这样就能够应用多个Mixin类的性能如下的Mix类混入了A、B两个类mixin A { void a() { print('A'); }}mixin B { void b() { print('B'); }}class Mix with A, B { //混入多个类}void main() { Mix m = Mix(); m.a(); m.b();} 注意事项Mixins除了继承Object外,不能够继承任何其余类Mixins不能够定义构造方法办法笼罩,后盖前vue3的混入混入 (mixins)定义了一部分可复用的办法或者计算属性。混入对象能够蕴含任意组件选项。当组件应用混入对象时,所有混入对象的选项将被混入该组件自身的选项。 const myMixin = { created() { this.hello() }, methods: { hello() { console.log('wdada!') } }} // 定义一个利用,应用混入const app = Vue.createApp({ mixins: [myMixin]}) app.mount('#app') 混入合并当组件和混入对象含有同名选项时,这些选项将以失当的形式混合。比方,数据对象在外部会进行浅合并 (一层属性深度),在和组件的数据发生冲突时以组件数据优先。以下实例中,Vue 实例与混入对象蕴含了雷同的办法。从输入后果能够看出两个选项合并了。 ...

July 19, 2022 · 1 min · jiezi

关于dart:Dart-学习笔记

语法篇九种内置类型Numbers (int, double)Dart 反对两种 Number 类型:int(整数值) double(双精度浮点数字)整型反对传统的位移操作,移位(<<、>> 和 >>>)、补码 (~)、按位与 (&)、按位或 (|) 以及按位异或 (^) assert((3 << 1) == 6); // 0011 << 1 == 0110assert((3 | 4) == 7); // 0011 | 0100 == 0111assert((3 & 4) == 0); // 0011 & 0100 == 0000Strings (String)应用三个单引号或者三个双引号也能创立多行字符串在字符串中,请以 ${表达式} 的模式应用表达式,如果表达式是一个标识符(var s = 'string'),能够省略掉 {}能够应用 + 运算符或并列搁置多个字符串来连贯字符串应用三个单引号或者三个双引号也能创立多行字符串在字符串前加上 r 作为前缀创立 “raw” 字符串, 则不会被本义 Booleans (bool) Lists (也被称为 arrays) var list = [1, 2, 3];在 List 字面量前增加 const 关键字会创立一个编译时常量 ...

July 11, 2022 · 4 min · jiezi

关于dart:dart系列之和null说再见null使用最佳实践

简介null可能是大家在编写程序中最为头疼的一个货色,稍不注意的状况下就有可能应用到了这个空字符。所以dart在2.12引入了nll safety,默认状况下强制所有的类型都不为null,只有在你认为它能够为null的时候才能够设置为null。 尽管有了null safety,然而这里还有一些咱们须要思考的null的最佳实际。 不须要初始化对象为null在dart2.12之后,所有的对象都强制为非空的,除非你显示指定其为可空的对象。 如果一个对象能够为空,那么咱们能够这样指定: String? name;如果定义一个对象能够为空,那么对dart来说会隐式对其初始化为null。 所以上面的显示初始化为null是齐全没有必要的: String? name=null;同样的,如果参数是一个能够为空的对象,那么dart也会将其初始化为null,咱们也没有必要显示去设置其值: void echoName(String? name){ print(name);}null的三元操作符所谓三元就是有三个变量,咱们常见的三元操作符就是?:,通常来说是这样用的: name==null?true:false;下面的逻辑实际上是把一个null转换成了一个bool类型。 为了实现这个性能,dart提供了一个更加简洁的操作符??, 能够这样应用: name??false;下面的代码示意如果name是空,则返回false。 留神,这里只是返回值扭转了,然而name值自身并没有变动,也不会将name从一个可为空的类型,变成不为空的类型。所以如果咱们在if语句外面对字符进行判断,则还是须要显示进行null的比拟: int measureMessage(String? message) { if (message != null && message.isNotEmpty) { // dart晓得message不为空 return message.length; } return 0;}如果这样编写,则会出现异常: int measureMessage(String? message) { if (message?.isNotEmpty ?? false) { //dart并不知道message不为空 return message!.length; } return 0;}如果在应用中须要判断类型是否为空,则不要应用latelate是做什么用的呢?late示意该类型目前不会初始化,然而会在将来的某个工夫对其进行初始化。 所以,如果你用late示意某个类型,那么在后续应用的时候是不须要进行手动判断该类型是否为空的。 如果你依然要手动判断,那么就没必要设置该类型为late。 本地变量的类型晋升dart有一个十分好的个性,就是当咱们判断一个变量不为空之后,该变量就会被晋升为非空变量。 当晋升为非空变量之后,就能够自在拜访该非空变量外部的属性和办法了。 然而惋惜的是,dart中的类型晋升只是针对与local变量或者参数而言的,对于类变量或者是top level的变量并不实用,所以咱们须要将这些变量拷贝到本地变量,从而应用类型晋升的个性。 咱们看上面的例子: class UploadException { final Response? response; UploadException([this.response]); @override String toString() { var response = this.response; if (response != null) { return 'Could not complete upload to ${response.url} ' '(error code ${response.errorCode}): ${response.reason}.'; } return 'Could not upload (no response).'; }}其中UploadException中的response是一个顶级变量,尽管咱们对其进行测试是否为空,然而在应用的过程中还是不能间接拜访其外部的属性,因为response可能为空。 ...

January 17, 2022 · 1 min · jiezi

关于dart:dart系列之手写LibraryLibrary编写最佳实践

简介Library是dart用来组织代码的一种十分有用的形式,通过定义不同的Library,能够将十分有用的dart代码进行封装,从而提供给其余的我的项目应用。尽管咱们能够自在应用import或者export来对library进行导入和导入。然而什么样的用法才是最合适的用法呢? 一起来看看吧。 应用part和part of尽管很多程序员厌恶应用part,然而dart的确提供了part这种性能用来将一个大的lib拆分成多个小的文件。 没错,和part的中文含意一样,part就是将lib文件进行拆分用的。 part of示意以后文件是另外一个主文件的一部分。part示意主文件是由援用的文件组成的。 咱们举个例子,如果当初有三个文件student_age.dart,student_name.dart和student.dart. 其中后面两个文件是前面一个文件的组成部分。 student_age.dart: part of student;int getAge(){ return 18;}student_name.dart: part of student;String getName(){ return "jack";}student.dart: library student;part 'some/other/student_age.dart';part 'some/other/student_name.dart';下面的代码有什么问题呢? 下面代码的问题在于对于student_age.dart来说,外面的part of只是指定了所属的library,然而咱们读起来会一头雾水,因为不晓得具体的library到底在什么中央。 所以应该这样写: part of '../../student.dart';src中的文件默认状况下lib目录下的src文件只是package外部应用的,不容许被内部的我的项目所调用。 所以咱们肯定不要间接引入lib包中的src文件。 package中的lib文件对于package来说,lib中的文件是能够被导出的文件,然而咱们在引入package的时候最好不要应用绝对路径或者相对路径间接导入lib中的文件。 而是须要应用import 'package:'. 举个例子,如果咱们有上面构造的library文件: my_package└─ lib └─ api.dart test └─ api_test.dartapi.dart就是咱们要导出的文件。如果咱们在api_test.dart中须要援用api.dart,则能够有上面两种形式: import 'package:my_package/api.dart';和: import '../lib/api.dart';其中下面一种形式是官网举荐的形式,为什么不应用上面一种形式呢?这是因为相对路径的形式只能在包外部应用。并且dart官网不倡议将lib放在援用门路中,如果要援用lib外部的文件, 肯定要应用package:。 当然,如果是package外部的援用,则优先应用相对路径,比方: my_package└─ lib ├─ src │ └─ stuff.dart │ └─ utils.dart └─ api.dart test │─ api_test.dart └─ test_utils.dart那么对应lib/api.dart来说,能够这样援用: import 'src/stuff.dart';import 'src/utils.dart';对于utils.dart来说,能够这样援用: ...

January 10, 2022 · 1 min · jiezi

关于dart:dart系列之dart代码最佳实践

简介每种语言都有本人的代码格调,这种代码格调是跟语言个性非亲非故的。如果在编码的过程中遵循这种对立的编码规定,会给咱们的业务带来十分多的便当。 同样的,对应dart而已,也有属于本人的编码格调,一起来看看吧。 命名规定一般来说,这个世界上有三种命名规定,别离是UpperCamelCase,lowerCamelCase和lowercase_with_underscores. UpperCamelCase示意的是驼峰格局,也就是首字母大写,其余的字母小写。 而lowerCamelCase也是驼峰格局,不同的是它的第一个单词的首字母是小写的。 lowercase_with_underscores则是将单词用下划线进行连贯。 对于类,typedef,枚举这些类型,个别都应用的是UpperCamelCase模式: class ClassRoom {}typedef Predicate<T> = bool Function(T value);对于类的实例来说,应用lowerCamelCase: const classRoom = ClassRoom();对于办法名来说,也应用lowerCamelCase: void main() {}之前咱们讲到了dart 2.7引入的extension,extension也须要应用UpperCamelCase: extension StringCompare on String { ... }对于libraries, packages, 目录和源文件来说,应用lowercase_with_underscores,如下所示: library common_convert.string_convert;import 'lib_one.dart';import 'lib_two.dart';如果要将import的lib进行重命名,则须要应用lowercase_with_underscores,如下所示: import 'lib_one.dart' as lib_one;对于某些回调函数中的参数,如果并没有应用到的话,则能够用_来代替: futureOfVoid.then((_) { print('Operation complete.');});如果是private属性,则举荐在名字后面加上_,示意它是一个公有值。 import中的程序在dart中,咱们须要应用到其余的package,一般来说咱们在编码过程中并不会特地留神到import的程序。 不过dart对于import的程序也是有举荐的。 首先 “dart:”,须要放在所有其余的import之前: import 'dart:html';import 'package:bar/bar.dart';而"package:" 须要放在外部我的项目援用之前: import 'package:foo/foo.dart';import 'util.dart';如果须要导出的话,export须要和import辨别开: import 'src/foo_bar.dart';export 'src/error.dart';而后依照下面提到的程序对具体的import按字母表的程序进行排序。 格式化对于dart来说,dart语言自身是不辨认空格的,然而对于人类来说,须要通过空格来格式化代码,从而达到可良好浏览的目标。 为了对立格局,dart提供了dart format命令. 尽管dart format命令为你做了99%的工作,然而还有1%的工作是你须要本人做的 。 比方:一行不超过80个字符,所有的流控制语句都用大括号括起来等等其余一些要留神的工作。 总结以上就是dart中的代码格调总结。 本文已收录于 http://www.flydean.com/27-dart-style/ 最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现! 欢送关注我的公众号:「程序那些事」,懂技术,更懂你! ...

January 4, 2022 · 1 min · jiezi

关于dart:dart系列之你的地盘你做主使用Extension对类进行扩展

简介个别状况要扩大一个类,须要继承这个类,这是在大多数java或者其余面向对象语言中要做的事件。 然而有些时候扩大类并不是特地好用,首先在有些语言中,有些类是禁止被扩大的。即便能够被扩大,然而扩大之后的类是一个新的类,而不是原来的父类,所以在应用的过程中可能会呈现一些类型转换的问题。 那么在dart中是怎么解决这个问题的呢? dart中extension的应用dart在2.7之后,引入了extension,用来对类的办法进行扩大。 到底怎么扩大呢?咱们举个例子. 咱们能够将字符串转换为int,通过调用int的parse办法,如下所示: int.parse('18')然而通过int类来进行转换通常不太直观,咱们心愿可能在String类中提供一个toInt的办法,能够间接调用,将字符串转换成为int。 '18'.toInt()然而很遗憾,String并没有提供toInt的办法,所以咱们能够通过extension来对String进行扩大: extension StringToNumber on String { int toInt() { return int.parse(this); } // ···}如果这个文件的名字叫做string_to_number.dart,那么咱们能够这样应用: import 'string_to_number.dart';// ···print('18'.parseInt()); dart中办法扩大最为不便的是,你只有引入对应的lib,应用的时候甚至都不晓得在应用lib的扩大。 当然,并不是所有的类都能够应用extention进行扩大。比方dynamic类型就不能进行扩大。 然而应用var类型,只有该类型能够被推断进去,那么就能够应用extention扩大。 API抵触既然能够对lib进行扩大,那么就有可能呈现API抵触的状况。那么怎么解决API抵触呢? 比方咱们须要应用两个lib扩大文件,extention1.dart和extention2.dart.然而两个扩大文件中都定义了parseInt办法对String进行扩大。 如果同时援用的话,就会呈现问题。 这时候能够应用show或者hide来限度具体应用哪一个扩大文件的中的办法。 import 'extention1.dart';import 'extention2.dart' hide StringToNumber2;print('18'.parseInt());还有一种状况就是显示调用extension,如下所示: import 'extention1.dart';import 'extention2.dart';print(StringToNumber('18').parseInt());print(StringToNumber2('18').parseInt());通过extention的名字来进行辨别。 如果两个extention的名字也雷同的话,那么能够通过prefix来进行辨别: import 'extention1.dart';import 'extention2.dart' as ext2;print(StringToNumber('18').parseInt());print(ext2.StringToNumber('18').parseInt());extention的实现实现扩大很简略,实现语法如下: extension <extension name> on <type> { (<member definition>)*}上面是一个扩大String的例子: extension NumberParsing on String { int parseInt() { return int.parse(this); } double parseDouble() { return double.parse(this); }}extension还能够扩大泛型参数: ...

December 31, 2021 · 1 min · jiezi

关于dart:dart系列之dart优秀的秘诀隔离机制

简介之前介绍了很多dart中的异步编程技巧,不晓得大家有没有发现一个问题,如果是在java的异步编程中,必定会提到锁和并发机制,然而对于dart来说,如同素来没有听到多线程和并发的问题,这是为什么呢? 明天,给大家解说一下dart中的隔离机制,大家就明确了。 dart中的隔离机制dart是一个单线程的语言,然而作为一个单线程的语言,dart却反对Future,Stream等异步个性。这一切都是隔离机制和事件循环带来的后果。 首先看一下dart中的隔离机制。 所谓隔离指的是dart运行的一个特定的空间,这个空间领有独自的内存和单线程的事件循环。 如下图所示: 在java或者c++等其余语言中,多个线程是共享内存空间的,尽管带来了并发和数据沟通的不便路径,然而同时也造成了并发编程的艰难。 因为咱们须要思考多线程之间数据的同步,于是额定多出了很多锁的机制,具体理解或者用过的人应该都会很懊恼。 多线程最大的缺点就是要求程序员的罗辑思维和编程技巧足够优良,这样才可能设计出完满运行的多线程程序。 然而在dart中,这些都不是什么问题。dart中所有的线程都领有本人的运行空间,这个线程的工作就是运行事件循环。 那么问题来了,主线程在处理事件循环,然而如果遇到了一个十分耗时的操作,该怎么办呢? 如果间接在主线程中运行,则可能会导致主线程的阻塞。 dart也充分考虑到了这个问题,所以dart提供了一个Isolate的类来对隔离进行治理。 因为dart程序自身就在一个Isolate中运行,所以如果在dart中定义一个Isolate,那么这个Isolate通常示意的是另外一个,须要和以后Isolate进行通信的Isolate。 生成一个Isolate那么如何在以后的dart程序中生成一个Isolate呢? Isolate提供了三种生成办法。 一个十分罕用的是Isolate的工厂办法spawn: external static Future<Isolate> spawn<T>( void entryPoint(T message), T message, {bool paused = false, bool errorsAreFatal = true, SendPort? onExit, SendPort? onError, @Since("2.3") String? debugName});spawn会创立一个新的Isolate,调用它须要传入几个参数: entryPoint示意的是生成新Isolate的时候须要调用的函数。entryPoint承受一个message参数。通常来说message是一个SendPort对象,用于两个Isolate之间的沟通。 paused示意新生成的Isolate是否处于暂停状态,他相当于: isolate.pause(isolate.pauseCapability)如果后续须要勾销暂停状态,则能够调用: isolate.resume(isolate.pauseCapability)errorsAreFatal 对应的是setErrorsFatal办法。 onExit对应的是addOnExitListener, onError对应的是addErrorListener。 debugName示意的是Isolate在调试的时候展现的名字。 如果spawn出错,则会抛出IsolateSpawnException异样: class IsolateSpawnException implements Exception { /// Error message reported by the spawn operation. final String message; @pragma("vm:entry-point") IsolateSpawnException(this.message); String toString() => "IsolateSpawnException: $message";}spawn办法生成的是和以后代码一样的Isolate。如果想要应用不同的代码来生成,则能够应用spawnUri,通过传入对应的Uri地址,从而生成不一样的code。 ...

December 27, 2021 · 1 min · jiezi

关于dart:dart系列之安全看我dart中的安全特性null-safety

简介在Dart 2.12中引入了null safety的新个性,也就是说dart程序中默认类型都是非空的,除非你显示通知编译器,这个类型能够为空。 看起来是一个小小的改变,然而这个小小的改变导致了很多Dart包的大版本升级,从而导致应用Dart2.12之前的版本跟应用dart2.12之后的版本齐全就是两个不同的世界。 真的这么微妙吗?一起来看看Dart 2.12 null safety的个性吧。 Non-nullable类型在感触Non-nullable类型之前,咱们先看一段代码: void main(){ String name; print('name is $name.');}代码很简略,咱们定义了一个String类型的name字符串,而后在print语句中打印它。 如果你是在dart 2.12版本之前,那么是没有问题的。 然而到了2.12,则会报错: The non-nullable local variable 'name' must be assigned before it can be used.Try giving it an initializer expression, or ensure that it's assigned on every execution path.意思就是说,name是非空的,你必须要给他赋个值。 通过强制不为空,保障了代码的安全性,十分好用。 那么如果name就能够为空怎么解决呢? 别急,咱们能够给能够为空的类型前面加上?即可: void main(){ String? name; print('name is $name.');}Nullable List Of Strings 和 List Of Nullable Strings如果咱们要创立一个List,list外面蕴含的是String,则能够这样创立: List<String> aListOfStrings = ['one', 'two', 'three'];在dart 2.12中,非空查看也被用到了泛型中,所以,默认状况下List中的String也不能为空,如果非要为空,则须要这样写: ...

December 22, 2021 · 1 min · jiezi

关于dart:dart系列之如丝滑般柔顺操作文件和目录

简介文件操作是IO中十分常见的一种操作,那么对应dart语言来说,操作文件是不是很简略呢?实际上dart提供了两种读取文件的形式,一种是一次性全副读取,一种是将文件读取为流。 一次性读取的毛病是须要将文件内容一次性全副载入到内存中,如果遇到文件比拟大的状况,就会比拟难堪。所以还须要流式读取文件的形式。一起来看看dart中这两种文件的读取形式吧。 File事实上dart中有很多中央都有File这个类,这里咱们要解说的File类是dart:io包中的。 读取整个文件File代表一个整体的文件,他有三个构造函数,别离是: factory File(String path) factory File.fromUri(Uri uri)factory File.fromRawPath(Uint8List rawPath)其中最罕用的就是第一个构造函数。 咱们能够这样来结构一个文件: var file = File('file.txt');有了文件之后,就能够调用File中的各种读取办法。 文件读取自身有两种模式,一种是文本,一种是二进制。 如果是文本文件,File提供了readAsString的办法,将整个文件读取为字符串。 Future<String> readAsString({Encoding encoding: utf8});咱们能够这样应用: var stringContents = await file.readAsString();另外,咱们还能够一行一行的对文件进行读取: Future<List<String>> readAsLines({Encoding encoding: utf8});后果返回的是一个List,list中示意文件每行的内容。 var lines = await file.readAsLines();下面两个办法是异步的办法,File还提供了两个同步的办法: String readAsStringSync({Encoding encoding: utf8});List<String> readAsLinesSync({Encoding encoding: utf8});如果文件是二进制,那么能够应用readAsBytes或者同步的办法readAsBytesSync: Future<Uint8List> readAsBytes();Uint8List readAsBytesSync();dart中示意二进制有一个专门的类型叫做Uint8List,他实际上示意的是一个int的List。 还是刚刚的文件,咱们看下怎么以二进制的模式进行读取: var file = File('file.txt');var contents = await file.readAsBytes();以流的模式读取文件下面咱们讲到的读取形式,都是一次性读取整个文件,毛病就是如果文件太大的话,可能造成内存空间的压力。 所以File为咱们提供了另外一种读取文件的办法,流的模式来读取文件. 相应的定义方法如下: Stream<List<int>> openRead([int? start, int? end]);咱们看一个根本的应用: import 'dart:io';import 'dart:convert';Future<void> main() async { var file = File('file.txt'); Stream<List<int>> inputStream = file.openRead(); var lines = utf8.decoder .bind(inputStream) .transform(const LineSplitter()); try { await for (final line in lines) { print('Got ${line.length} characters from stream'); } print('file is now closed'); } catch (e) { print(e); }}随机拜访个别状况下文件是程序拜访的,然而有时候咱们须要跳过某些后面的数据,间接跳转到指标地址,则须要对文件进行随机拜访。 ...

December 20, 2021 · 1 min · jiezi

关于dart:dart系列之实时通讯在浏览器中使用WebSockets

简介web客户端和服务器端通信有两种形式,一种是应用HTTP申请,从服务器端申请数据。这种申请的毛病就是只能客户端拉取服务器端的数据,只能进行轮询。 另外一种形式是应用WebSocket,在客户端和服务器端之间建设通道,这样服务器就能够间接向客户端推送音讯,防止了客户端频繁的拉取服务器端的数据,造成服务器端的压力。 dart:html包中就蕴含了WebSockets的相干操作,一起来看看吧。 dart:html中的WebSocketsWebSocket应用的是ws和wss作为URI的标记符。其中ws示意的是websocket,而wss示意的是WebSocket Secure。 WebSocket能够分为客户端和服务器端两局部。dart:html中提供的WebSocket对象中蕴含的是客户端的逻辑。 咱们先看下WebSocket类的定义: @SupportedBrowser(SupportedBrowser.CHROME)@SupportedBrowser(SupportedBrowser.FIREFOX)@SupportedBrowser(SupportedBrowser.IE, '10')@SupportedBrowser(SupportedBrowser.SAFARI)@Unstable()@Native("WebSocket")class WebSocket extends EventTarget能够看到它继承自EventTarget,并且反对chrome、firfox、IE10和Safari这几种浏览器。 创立一个WebSocketWebSocket有两种创立形式,第一种是带protocal,一种是不带protocal: factory WebSocket(String url, [Object? protocols]) { if (protocols != null) { return WebSocket._create_1(url, protocols); } return WebSocket._create_2(url); }这里的protocols指的是在webSocket协定框架之下的子协定,它示意的是音讯的格局,比方应用soap或者wamp。 子协定是在WebSocket协定根底上倒退进去的协定,次要用于具体的场景的解决,它是是在WebSocket协定之上,建设的更加严格的标准。 咱们看一个最简略的创立WebSocket的代码: var webSocket = new WebSocket('ws://127.0.0.1:1337/ws');以上如果服务器存在的话,就会胜利建设一个WebSocket的连贯。 WebSocket的状态WebSocket有四个状态,别离是closed, closing, connecting和open,都是以static来定义的,能够间接援用: static const int CLOSED = 3; static const int CLOSING = 2; static const int CONNECTING = 0; static const int OPEN = 1;发送音讯dart中的WebSocket定义了5中发送音讯的办法: void send(data) native; void sendBlob(Blob data) native; void sendByteBuffer(ByteBuffer data) native; void sendString(String data) native; void sendTypedData(TypedData data) native;WebSocket反对发送[Blob], [ByteBuffer], [String] 或者 [TypedData] 这四种数据类型。 ...

December 17, 2021 · 1 min · jiezi

关于dart:dart系列之浏览器中的舞者用dart发送HTTP请求

简介dart:html包为dart提供了构建浏览器客户端的一些必须的组件,之前咱们提到了HTML和DOM的操作,除了这些之外,咱们在浏览器端另一个罕用的操作就是应用XMLHttpRequest去做异步HTTP资源的申请,也就是AJAX申请。 dart同样提供了相似JS中XMLHttpRequest的封装,其对应的类叫做HttpRequest,一起来看看在dart中怎么应用HttpRequest吧。 发送GET申请尽管古代的web APP被各种框架所封装,然而归根结底他还是一个AJAX的富客户端利用。咱们通过各种异步的HTTP申请向服务器端申请数据,而后展现在页面上。一般来说数据的交互格局是JSON,当然也能够有其余的数据交互格局。 AJAX中最罕用的形式就是向服务器端发送get申请,对应的HttpRequest有一个getString办法: static Future<String> getString(String url, {bool? withCredentials, void onProgress(ProgressEvent e)?}) { return request(url, withCredentials: withCredentials, onProgress: onProgress) .then((HttpRequest xhr) => xhr.responseText!); }留神,getString办法是一个类办法,所以间接应用HttpRequest类来调用: var name = Uri.encodeQueryComponent('John'); var id = Uri.encodeQueryComponent('42'); HttpRequest.getString('users.json?name=$name&id=$id') .then((String resp) { // Do something with the response. });因为getString返回的是一个Future,所以能够间接在getString前面接then语句,来获取返回的值。 当然,你也能够在async办法中应用await来获取返回值。 Future<void> main() async { String pageHtml = await HttpRequest.getString(url); // Do something with pageHtml...}或者应用try catch来捕捉异样: try { var data = await HttpRequest.getString(jsonUri); // Process data...} catch (e) { // Handle exception...}发送post申请GET是从服务器拉取数据,相应的POST就是通用的向服务器中提交数据的办法。在HttpRequest中,对应的办法是postFormData: ...

December 15, 2021 · 2 min · jiezi

关于dart:netty系列之性能为王创建多路复用http2服务器

简介在之前的文章中,咱们提到了在netty的客户端通过应用Http2FrameCodec和Http2MultiplexHandler能够反对多路复用,也就是说在一个连贯的channel根底上创立多个子channel,通过子channel来解决不同的stream,从而达到多路复用的目标。 既然客户端能够做到多路复用,同样的服务器端也能够,明天给大家介绍一下如何在netty的服务器端打造一个反对http2协定的多路复用服务器。 多路复用的根底netty中对于http2多路复用的根底类是Http2FrameCodec、Http2MultiplexHandler和Http2MultiplexCodec。 Http2FrameCodec是将底层的HTTP/2 frames音讯映射成为netty中的Http2Frame对象。 有了Http2Frame对象就能够通过Http2MultiplexHandler对新创建的stream开启不同的channel。 Http2MultiplexCodec是Http2FrameCodec和Http2MultiplexHandler的结合体,然而曾经不再被举荐应用了。 因为Http2FrameCodec继承自Http2ConnectionHandler,而Http2MultiplexHandler继承自Http2ChannelDuplexHandler,所以这两个类能够同时在客户端和服务器端应用。 客户端应用Http2FrameCodecBuilder.forClient().build()来取得Http2FrameCodec,而服务器端通过Http2FrameCodecBuilder.forServer().build()来取得Http2FrameCodec。 多路复用在server端的应用配置TLS处理器对于服务器端,同样须要解决TLS和一般clear text两种状况。对于TLS来说,咱们须要自建ProtocolNegotiationHandler继承自ApplicationProtocolNegotiationHandler,而后实现configurePipeline办法,在其中别离解决http2和http1.1的连贯: protected void configurePipeline(ChannelHandlerContext ctx, String protocol) { if (ApplicationProtocolNames.HTTP_2.equals(protocol)) { //增加多路复用反对 ctx.pipeline().addLast(Http2FrameCodecBuilder.forServer().build()); ctx.pipeline().addLast(new Http2MultiplexHandler(new CustMultiplexHttp2Handler())); return; } if (ApplicationProtocolNames.HTTP_1_1.equals(protocol)) { ctx.pipeline().addLast(new HttpServerCodec(), new HttpObjectAggregator(MAX_CONTENT_LENGTH), new CustHttp1Handler("ALPN Negotiation")); return; } throw new IllegalStateException("未知协定: " + protocol); }首先增加Http2FrameCodec,而后增加Http2MultiplexHandler。因为Http2MultiplexHandler曾经封装了多路复用的细节,所以自定义的handler只须要实现失常的音讯解决逻辑即可。 因为Http2FrameCodec曾经对音讯进行了转换成为HTTP2Frame对象,所以只须要解决具体的Frame对象: public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof Http2HeadersFrame) { onHeadersRead(ctx, (Http2HeadersFrame) msg); } else if (msg instanceof Http2DataFrame) { onDataRead(ctx, (Http2DataFrame) msg); } else { super.channelRead(ctx, msg); } }配置clear text upgrade对于h2c的降级来说,须要向pipline中传入sourceCodec和upgradeHandler两个处理器。 ...

December 14, 2021 · 1 min · jiezi

关于dart:dart系列之HTML的专属领域除了javascript之外dart也可以

简介尽管dart能够同时用作客户端和服务器端,然而基本上dart还是用做flutter开发的根本语言而应用的。除了andorid和ios之外,web就是最常见和通用的平台了,dart也提供了对HTML的原生反对,这个反对就是dart:html包。 dart:html提供了对DOM对象的各种有用的操作和对HTML5 API的反对。这样咱们能够间接应用dart来操作HTML。 除了DOM之外,dart:html还能够对css进行操作,应用dart:html也非常简单: import 'dart:html';DOM操作对于DOM操作来说,首先是须要找到这个元素。 dart提供了querySelector() 和 querySelectorAll()办法,能够依据ID, class, tag, name或者这些元素的汇合来进行查找。 同样都是query办法,两者的不同在于,querySelector只返回找到的第一个元素,而querySelectorAll返回找到的所有元素。 所以querySelector返回的是一个Element,而querySelectorAll返回的是一个汇合List<Element>。 Element idElement = querySelector('#someId')!;Element classElement = querySelector('.some-class')!;List<Element> divElements = querySelectorAll('div');List<Element> textInputElements = querySelectorAll( 'input[type="text"]',);List<Element> specialElement = querySelectorAll('#someId div.class');下面就是咱们查找DOM中元素的操作。找到之后,就能够对这些元素进行操作了。 dart应用Element来示意DOM中的元素。对于每个Element来说,都领有classes, hidden, id, style, 和 title 这些属性。 如果Element中并没有要设置的属性,则能够应用attributes,如下: elem.attributes['someAttribute'] = 'someValue';当然对应某些非凡的Element,会有Element对应的子类与之绑定。 比方对于一个a标签来说,如下所示: <a id="name" href="/name/detail">详情</a>a标签对应的是dart中的AnchorElement元素。 如果要扭转a标签的href值,能够这样: var anchor = querySelector('#name') as AnchorElement;anchor.href = 'http://www.flydean.com';还能够增加、替换或者删除对应的节点: querySelector('#id')!.nodes.add(elem);querySelector('#id')!.replaceWith(elem);querySelector('#id')?.remove();下面咱们应用了一个非凡的运算符,感叹号,示意的是将一个可为空的类型转换成为不为空的类型。CSS操作CSS实际上就是element中的class,当咱们获取到element之后,就能够调用他的classes字段,而后对CSS进行解决。 elem.classes返回的是一个list,咱们能够向其增加或者删除对应的class。 var name = querySelector('#id')!;name.classes.add('redline');有class当然是最好了,class也是咱们举荐的写法。然而有时候还是须要间接在element中增加style,如下所示: name.style ..fontWeight = 'bold' ..fontSize = '3em';处理事件和DOM的交互就是各种事件,向element中增加event,能够应用element.onEvent.listen(function). 比方咱们能够增加click事件: querySelector('#id')!.onClick.listen((e) { // do something});上面是罕用的一些event: ...

December 7, 2021 · 1 min · jiezi

关于dart:dart系列之数学什么的就是小意思看我dart如何玩转它

简介dart也能够进行数学运算,dart为数学爱好者专门创立了一个dart:math包来解决数学方面的各种操作。dart:math包提供了正弦,余弦,最大值,最小值和随机数等操作。 一起来看看dart:math包都能做什么吧。 dart:math包的形成如果你去查看dart:math的源代码,你会发现,dart:math包其实很简略,它外面只有4个文件。别离是: math.dart,random.dart,point.dart和rectangle.dart。 前面两个文件,次要跟二维坐标无关,这里不具体阐明。 咱们罕用到的就是后面两个文件,math和random。 mathmath中定义了咱们在数学运算中罕用到的一些常量,如: const double e = 2.718281828459045;const double ln10 = 2.302585092994046;const double ln2 = 0.6931471805599453;const double log2e = 1.4426950408889634;const double log10e = 0.4342944819032518;const double pi = 3.1415926535897932;const double sqrt1_2 = 0.7071067811865476;const double sqrt2 = 1.4142135623730951;计算最大值和最小值: assert(max(18, 20) == 20);assert(min(18, 20) == 18);应用三角函数: assert(cos(pi) == -1.0);var degrees = 30;var radians = degrees * (pi / 180);var sinOf30degrees = sin(radians);assert((sinOf30degrees - 0.5).abs() < 0.01);Randomdart中的random包提供了一些比拟有用的生成随机数的办法,先看下Random类的定义: abstract class Random { external factory Random([int? seed]); external factory Random.secure(); int nextInt(int max); double nextDouble(); bool nextBool();}咱们能够应用Random中提供的nextInt,nextDouble和nextBool来生成对应的随机数: ...

December 3, 2021 · 1 min · jiezi

关于dart:dart系列之时间你慢点走我要在dart中抓住你

简介工夫和日期是咱们常常会在程序中应用到的对象。然而对工夫和日期的解决因为有不同时区的起因,所以始终以来都不是很好用。就像在java中,为工夫和日期批改和新增了屡次API,那么作为新生的语言dart而言,会有什么不一样的中央吗? dart中对于日期和工夫的两个十分重要的类是DateTime和Duration. 其中DateTime示意的是工夫,而Duration示意的是时间差。 DateTime先看一下DateTime的应用。 DateTime示意的是一个工夫点。因为世界时钟有UTC和本地工夫两种。所以,在应用DataTime的时候,也能够应用这两种时钟。 最简略的就是获取以后的工夫: var now = DateTime.now();如果要创立指定日期的工夫,则能够将年月日传入DateTime的构造函数: var now = DateTime(2021, 11, 20); 留神,下面创立的日期是本地日期。 如果要创立UTC time,则能够应用DateTime.utc办法: var utc = DateTime.utc(2021, 11, 20);还有一种示意工夫的办法是unix time, Unix time指的是从1970年1月1日开始所通过的秒数. DateTime有两种示意Unix time工夫的办法,别离是: DateTime.fromMicrosecondsSinceEpoch(10000); DateTime.fromMillisecondsSinceEpoch(10000);他们的区别在于,一个示意的是微秒,一个示意的是毫秒。 DateTime还能够将字符串转换成为DateTime对象: var time= DateTime.parse('2002-02-27T14:00:00-0500');事实上,DateTime.parse能够承受多种字符类型,如下所示: `"2012-02-27"``"2012-02-27 13:27:00"` `"2012-02-27 13:27:00.123456789z"``"2012-02-27 13:27:00,123456789z"``"20120227 13:27:00"``"20120227T132700"``"20120227"``"+20120227"` `"2012-02-27T14Z"``"2012-02-27T14+00:00"`DurationDuration示意的是两个工夫之间的差值。 来看下Duration的构造函数: const Duration( {int days = 0, int hours = 0, int minutes = 0, int seconds = 0, int milliseconds = 0, int microseconds = 0}) : this._microseconds(microsecondsPerDay * days + microsecondsPerHour * hours + microsecondsPerMinute * minutes + microsecondsPerSecond * seconds + microsecondsPerMillisecond * milliseconds + microseconds);能够看到Duration能够示意从天到microseconds的距离,曾经足够用了. 应该怎么应用呢? ...

December 2, 2021 · 1 min · jiezi

关于dart:URL-URI傻傻分不清楚dart告诉你该怎么用

简介如果咱们要拜访一个网站,须要晓得这个网站的地址,网站的地址个别被称为URL,他的全称是Uniform Resource Locator。那么什么是URI呢? URI的全程是Uniform Resource Identifier,也叫做对立资源标志符。 URI用来对资源进行标记,而URL是对网络上的资源进行标记,所以URL是URI的子集。 理解了URI和URL之间的关系之后,咱们来看看dart语言对URI的反对。 dart中的URIdart中为URI创立了一个专门的类叫做Uri: abstract class Uri Uri是一个抽象类,他定义了一些对URI的基本操作。它有三个实现类,别离是_Uri,_DataUri和_SimpleUri。 接下来,咱们一起来看看,dart中的Uri都能够做什么吧。 encode和decode为什么要对encode URI? 一般来说URI中能够蕴含一些特殊字符,像是空格或者中文等等。这些字符在传输中可能不被对方所意识。所以咱们须要对Uri进行编码。 然而对于URI中的一些非凡然而有意义的字符,比方: /, :, &, #, 这些是不必被本义的。 所以咱们须要一种可能对立编码和解码的办法。 在dart中,这种办法叫做encodeFull() 和 decodeFull(): var uri = 'http://www.flydean.com/doc?title=dart uri';var encoded = Uri.encodeFull(uri);assert(encoded == 'http://www.flydean.com/doc?title=dart%20uri');var decoded = Uri.decodeFull(encoded);assert(uri == decoded);如果要编码所有的字符,包含那些有意义的字符:/, :, &, #, 那么能够应用encodeComponent() 和 decodeComponent(): var uri = 'http://www.flydean.com/doc?title=dart uri';var encoded = Uri.encodeComponent(uri);assert(encoded == 'http%3A%2F%2www.flydean.com%2Fdoc%3Ftitle%3Ddart%20uri');var decoded = Uri.decodeComponent(encoded);assert(uri == decoded);解析URIURI是由scheme,host,path,fragment这些局部组成的。咱们能够通过Uri中的这些属性来对Uri进行合成: var uri = Uri.parse('http://www.flydean.com/doc#dart');assert(uri.scheme == 'http');assert(uri.host == 'www.flydean.com');assert(uri.path == '/doc');assert(uri.fragment == 'dart');assert(uri.origin == 'http://www.flydean.com');那么怎么结构Uri呢?咱们能够应用Uri的构造函数: ...

December 1, 2021 · 1 min · jiezi

关于dart:没有人比我更会使用集合对-是dart中的集合

简介dart中的汇合有三个,别离是list,set和map。dart在dart:core包中提供了对于这三种汇合十分有用的办法,一起来看看吧。 List的应用首先是list的创立,能够创立空的list或者带值的list: var emptyList =[];var nameList = ['jack','mac'];应用List的构造函数来创立: var nameList = List.filled(2, 'max');向list中增加元素或者list: nameList.add('tony');nameList.addAll(['lili', 'bruce']);删除元素: nameList.removeAt(0);nameList.clear();dart提供了list的排序办法sort(),sort能够接一个比拟的函数,用来示意谁在前谁在后: var names = ['jack', 'tony', 'max'];fruits.sort((a, b) => a.compareTo(b));list中还能够应用泛型,示意list中固定的类型: var names = <String>[];names.add('jack');Set的应用Set示意的是不反复的元素的汇合。然而set和list不同的是set是无序的,所以你不能用index来定位set中的元素。 来看下set的根本用法: //创立一个空的setvar names = <String>{};// 增加新的元素names.addAll(['jack', 'tony', 'max']);//删除元素names.remove('jack');或者应用Set的构造函数来结构Set: var names = Set.from(['jack', 'tony', 'max']);判断汇合中元素是否存在: assert(names.contains('jack'));assert(names.containsAll(['jack', 'tony']));set还有一个intersection的操作,用来求两个set的交加: var name1 = Set<String>();name1.addAll(['jack', 'tony', 'max']);var name2 = Set.from(['tony', 'bily']);var intersection = name1.intersection(name2);Map的应用Map是一种key,value的数据类型,也是一种在程序中十分常见的数据类型。 先看下怎么创立Map: // 创立mapvar studentMap = { 'name': 'jack', 'age': '18', 'class': 'class one'};var teacherMap = Map();var teacherMap2 = Map<String, String>();增加和删除: ...

November 26, 2021 · 1 min · jiezi

关于dart:dart系列之在dart中使用数字和字符串

简介要想相熟一种语言,最简略的做法就是相熟dart提供的各种外围库。dart为咱们提供了包含dart:core,dart:async,dart:math,dart:convert,dart:html和dart:io这几种罕用的库。 明天给大家介绍一下dart:core中的数字和字符串的应用。 # 数字 dart:core中定义了三种类型的数字,别离是num,int和double。 num是所有数字的总称。int和double都是继承自num,是num的子类。 事实上,dart:core中还有以一种数据类型叫做BigInt,BigInt是一种独立的数据类型,并不是num的子类: abstract class BigInt implements Comparable<BigInt>数字中最常见的操作就是将字符串转换为数字,转换能够调用parse办法,先看下num中parse办法的定义: static num parse(String input, [@deprecated num onError(String input)?]) { num? result = tryParse(input); if (result != null) return result; if (onError == null) throw FormatException(input); return onError(input); }传入的input能够是十进制、也能够是十六进制,如下所示: assert(int.parse('18') == 18);assert(int.parse('0x05') == 5);assert(double.parse('0.50') == 0.5);num.parse会将对应的字符转换成为int或者double类型: assert(num.parse('18') is int);assert(num.parse('0.50') is double);parse办法还能够传入字符串对应的基数,比方是十进制还是十六进制: assert(int.parse('11', radix: 16) == 17);下面咱们讲到了如何将字符串转换成为数字,上面是如何将数字转换成为字符串,num提供了toString()办法,能够不便的将int和double转换成为string。 assert(18.toString() == '18');assert(3.1415.toString() == '3.1415');对于小数来说,能够应用toStringAsFixed来指定小数的位数: assert(3.1415.toStringAsFixed(2) == '3.14');如果要应用迷信记数法的话,能够应用toStringAsPrecision: assert(314.15.toStringAsPrecision(2) == '3.1e+2');字符串所有的字符串在dart中都是以UTF-16进行编码的,dart中的string定义了很多罕用的并且十分有用的办法。 ...

November 24, 2021 · 1 min · jiezi

关于dart:dart系列之在dart中使用生成器

简介ES6中在引入异步编程的同时,也引入了Generators,通过yield关键词来生成对应的数据。同样的dart也有yield关键词和生成器的概念。 什么时候生成器呢?所谓生成器就是一个可能继续产生某些数据的安装,也叫做generator。 两种返回类型的generator依据是同步生成还是异步生成,dart返回的后果也是不同的。 如果是同步返回,那么返回的是一个Iterable对象. 如果是异步返回,那么返回的是一个Stream对象。 同步的generator应用sync*关键词如下: Iterable<int> naturalsTo(int n) sync* { int k = 0; while (k < n) yield k++;}异步的generator应用的是async* 关键词如下: Stream<int> asynchronousNaturalsTo(int n) async* { int k = 0; while (k < n) yield k++;}生成关键词应用的是yield。 如果yield前面跟着的自身就是一个generator,那么须要应用yield*。 Iterable<int> naturalsDownFrom(int n) sync* { if (n > 0) { yield n; yield* naturalsDownFrom(n - 1); }}Stream的操作stream示意的是流,失去这个流之后,咱们须要从流中取出对应的数据。 从Stream中取出数据有两种形式,第一种就是应用Stream自身的API来获取Stream中的数据。 最简略的就是调用stream的listen办法: StreamSubscription<T> listen(void onData(T event)?, {Function? onError, void onDone()?, bool? cancelOnError});listen能够接数据的解决办法,具体应用如下: final startingDir = Directory(searchPath); startingDir.list().listen((entity) { if (entity is File) { searchFile(entity, searchTerms); } });默认的办法是onData办法。 ...

November 23, 2021 · 1 min · jiezi

关于dart:dart系列之dart中的异步编程

简介相熟javascript的敌人应该晓得,在ES6中引入了await和async的语法,能够不便的进行异步编程,从而解脱了回调天堂。dart作为一种新生的语言,没有理由不继承这种优良的品质。很天然的,dart中也有await和async语言,一起来看看吧。 为什么要用异步编程那么为什么要用异步编程呢? 只用同步不可能解决吗? 其实大多状况下同步曾经够用了,然而在上面的几种状况下,同步的场景还是有缺点的。 须要花很长时间从网络上下载数据的状况。读取数据库的耗时状况。从文件读取数据的状况。总结而言,如果某些操作须要破费大量的工夫,那么就能够用到异步编程了。 怎么应用async是办法的描述符,如果要应用await,则必须配合async一起应用: Future<void> checkVersion() async { var version = await lookUpVersion(); // Do something with version}留神,await前面个别接着的是Future对象。先看一个谬误应用异步编程的例子: String createOrderMessage() { var order = fetchUserOrder(); return 'Your order is: $order';}Future<String> fetchUserOrder() => Future.delayed( const Duration(seconds: 2), () => 'Order one!', );void main() { print(createOrderMessage());}下面的代码本意是打印出从数据库耗时取出的数据,然而后果并不是设想的那样,其起因就是fetchUserOrder办法是一个异步办法,所以不会立刻返回,从而导致后果打印失败。 将下面的代码用async改写: Future<String> createOrderMessage() async { var order = await fetchUserOrder(); return 'Your order is: $order';}Future<String> fetchUserOrder() => Future.delayed( const Duration(seconds: 2), () => 'Large Latte', );Future<void> main() async { print('Fetching user order...'); print(await createOrderMessage());}Future下面咱们在应用async和await的过程中应用到了Future。在java中Future示意的是线程的执行后果。在dart中Future示意的是一个异步执行的后果。 ...

November 21, 2021 · 1 min · jiezi

关于dart:dart系列之创建Library-package

简介在dart零碎中,有pubspec.yaml文件的利用就能够被成为一个package。而Libray package是一类非凡的package,这种包能够被其余的我的项目所依赖. 也就是通常所说的库。 如果你也想你写的dart程序能够上传到pub.dev上,或者提供给他人应用,则来看看这篇文章吧。 Library package的构造先看下library package的构造: app3├── lib│   └── main.dart└── pubspce.yaml这是一个最简略的Library package的构造,在root目录上面,咱们有一个pubspce.yaml文件。而后还有一个lib目录寄存的是library的代码。 一般来说lib上面的库是能够供内部进行援用的。如果是library外部的文件,则能够放到lib/src目录上面,这外面的文件示意是private的,是不应该被别的程序引入的。 如果想要将src中的包导出供内部应用,则能够在lib上面的dart文件中应用export,将须要用到的lib导出。这样其余用户只须要import这个一个文件即可。 export的例子如下: library animation;export 'src/animation/animation.dart';export 'src/animation/animation_controller.dart';export 'src/animation/animations.dart';export 'src/animation/curves.dart';export 'src/animation/listener_helpers.dart';export 'src/animation/tween.dart';export 'src/animation/tween_sequence.dart';下面的代码是flutter的animation库。 导入library怎么应用呢?咱们能够应用import语句来导入对应的lib: import 'package:flutter/animation.dart';如果是外部文件的导入,则能够应用相对路径。只有在导入内部package的时候才须要加上package:前缀。 条件导入和导出library因为dart是设计在能够在不同的平台上进行工作,所以一个library在不同的平台可能须要导入或者导出不同的library文件, 这就叫做条件导入和导出。 比方能够通过判断dart库是io库还是html库来抉择导出不同的文件: export 'src/hw_none.dart' // Stub implementation if (dart.library.io) 'src/hw_io.dart' // dart:io implementation if (dart.library.html) 'src/hw_html.dart'; // dart:html implementation下面的意思是,如果在app中可能应用dart:io,那么就导出src/hw_io.dart. 如果可能应用dart:html,那么就导出src/hw_html.dart,否则就导出src/hw_none.dart。 如果是条件导入的话,将export改成import即可。 增加其余无效的文件因为不同的library有不同的作用,所以通常须要增加一些额定的文件来保障library的有效性和完整性。 为了保障library的有效性,须要增加测试代码,测试代码通常放在test目录中。 如果是创立命令行工具,则须要将对应的工具放到tools目录中。 另外还有 README.md 和 CHANGELOG.md等文件。 library的文档dart文档能够应用 dartdoc这个工具来生成。dart中的文档格局是以///结尾的,如下: /// The event handler responsible for updating the badge in the UI.void updateBadge() { ...}公布到pub.dev一个最好共享library的形式就是将其发送到pub.dev上。具体的命令是:pub publish。 ...

November 20, 2021 · 1 min · jiezi

关于dart:dart系列之元世界pubspecyaml文件详解

简介pubspec.yaml是所有dart我的项目的灵魂,它蕴含了所有dart我的项目的依赖信息和其余元信息,所以pubspec.yaml就是dart我的项目的meta! pubspec.yaml反对的字段依据dart的定义,pubspec.yaml中能够蕴含上面的字段: 字段名是否必须字段形容name是package的名字version如果公布到pub.dev,则须要package的版本号description如果公布到pub.dev,则须要package的形容信息homepage否package的主页repository否package的源代码地址issue_tracker否package问题跟踪地址documentation否package的文档信息dependencies否package的依赖信息dev_dependencies否pacakge的dev依赖信息dependency_overrides否想要笼罩的packageenvironmentdart2须要 executables否package的可执行文件门路publish_to否package将如何公布留神,以上是dart中pubspec.yaml反对的字段,如果是在flutter环境中,则会有些额定反对的字段。# 一个例子 咱们看一个具体的例子: name: my_appversion: 11.15description: >- this is a new apphomepage: http://www.flydean.comdocumentation: http://www.flydean.comenvironment: sdk: '>=2.10.0 <3.0.0'dependencies: efts: ^2.0.4 transmogrify: ^0.4.0dev_dependencies: test: '>=1.15.0 <2.0.0'字段详情上面来看下各个字段的详情和限度状况: Namename示意的是包的名字,name必须是全小写,如果有多个词的话,能够用下划线来辨别,如:my_app. 并且只能应用小写字母和数字的组合,同时不能以数字结尾,并且不要应用dart中的保留字。 VersionVersion示意的是版本号,版本号是由点宰割的三个数字,如:11.15.0. 前面还能够跟上build版本号:+1, +2, +hotfix.oopsie, 或者预公布版本等:-dev.4, -alpha.12, -beta.7, -rc.5. Descriptionpackage的形容信息最好应用英文来刻画,长度是60 到180个字符,示意这个包的作用。 Dependencies有两种依赖信息,一种是所有应用到这个packages的人都须要用到的依赖,这种依赖放在dependencies中。 还有一种是只用在以后pacakge开发中的包,这种依赖放在dev_dependencies中。 在某些状况下,咱们有可能须要笼罩某些依赖包,则能够放在:dependency_overrides中。 Executables有些pacakges提供的是工具供大家应用,这些工具有可能是命令行工具,所以须要在executables中指定能够执行的命令的门路。 比方上面的配置: executables: slidy: main fvm:那么在执行pub global activate之后,就能够在全局执行slidy来执行bin/main.dart, 和fvm来执行binfvm.dart. environment因为Dart是一门新的语言,所以目前来说其变动还是挺大的。所以有些利用能够依赖于不同的dart版本,这时候就须要用到environment: environment: sdk: '>=2.10.0 <3.0.0'下面的代码中,咱们指定了dart sdk的版本范畴。 从dart1.19之后,environment:中还反对指定flutter的版本: environment: sdk: '>=1.19.0 <3.0.0' flutter: ^0.1.2总结以上就是dart的元世界pubspec.yaml详解。 本文已收录于 http://www.flydean.com/10-dart-pubspec/ 最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现! 欢送关注我的公众号:「程序那些事」,懂技术,更懂你! ...

November 19, 2021 · 1 min · jiezi

关于dart:dart系列之在dart中使用packages

简介java中应用jar包来封装有用的性能,而后将其散发到maven仓库中,供其他人应用。同样的在dart中也有相似的概念叫做packages。packages就是能够用来共享的软件包,能够蕴含libraries和tools。 你能够在pub.dev网站中查到dart中所有的共享packages的信息。 那么怎么在一个dart我的项目中应用这些packages呢? pubspec.yaml简略点讲,一个dart的package就是蕴含pubspec.yaml的目录。pubspec.yaml是一个形容文件,用来表明该package的元信息,包含以后package的名字,版本号和依赖信息等。 要想应用pub.dev上的packages,只须要在pubspec.yaml引入对应的依赖即可。 咱们举个例子: name: app2description: a demo appversion: 1.0.0+1environment: sdk: ">=2.7.0 <3.0.0"dependencies: image_picker: ^0.6.7+22 video_player: ^0.10.12+5这里咱们的引入了两个依赖包,别离是image_picker和video_player。 get packages当咱们批改了pubspec.yaml之后,其实对应的package并没有下载到本地来,还须要通过上面的命令来下载对应的packages: cd <path-to-my_app> dart pub getdart pub get会依据pubspec.yaml中配置的内容下载对应的包,并搁置在零碎缓存中。 在Mac或者Linux零碎中,这个缓存目录的地址是:~/.pub-cache,在windows中这个目录地址是:%LOCALAPPDATA%\Pub\Cache。 当然,你也能够通过设置PUB_CACHE来更换这个地址。如果你依赖的包又依赖其余的包的话,其余依赖包也会被下载下来。 当下载完依赖包之后,dart会在 .dart_tool/目录中创立一个 package_config.json文件,用来示意以后我的项目和零碎缓存包的映射关系。 # 应用packages 万事俱备,只欠东风。当初包也有了,剩下就是应用了。 应用libary能够用关键字import。如果是dart SDK中的包,则以dart:结尾: import 'dart:html';如果是第三方包,则以package: 结尾: import 'package:test/test.dart';引入的libary还能够被重命名: import 'package:lib1/lib1.dart';import 'package:lib2/lib2.dart' as lib2;// Uses Element from lib1.Element element1 = Element();// Uses Element from lib2.lib2.Element element2 = lib2.Element();还能够应用show和hide引入局部library: // Import only foo.import 'package:lib1/lib1.dart' show foo;// Import all names EXCEPT foo.import 'package:lib2/lib2.dart' hide foo;默认状况下,引入的包是初始加载的,如果某些包特地大,或者你想要在应用的时候再进行加载,则能够应用deferred关键字进行延时加载: ...

November 18, 2021 · 1 min · jiezi

关于dart:dart系列之dart类中的泛型

简介相熟JAVA的敌人可能晓得,JAVA在8中引入了泛型的概念。什么是泛型呢?泛型就是一种通用的类型格局,个别用在汇合中,用来指定该汇合中应该存储的对象格局。 有了泛型能够简化咱们的编程,并且能够缩小谬误的产生,十分的不便。 dart语言中也有泛型。一起来看看吧。 为什么要用泛型应用泛型的次要目标是保障类型平安,比方咱们有一个List,而后只心愿List中保留String类型,那么在dart中能够这样指定: var stringList = <String>[];stringList.addAll(['jack ma', 'tony ma']);stringList.add(18); // 报错那么在应用的过程中,只能向stringList中增加字符串,如果向其增加数字,则会报错,从而保障List中类型的一致性。 奇妙的应用泛型还可能缩小咱们的代码量,因为泛型能够代表一类通用的类型。 比方,在学校中,咱们有寝室,寝室是有男女之分的,那么对应男生来说有这样的定义: abstract class BoyRoom { Boy getByName(String name);}对于女生来说有这样的定义: abstract class GirlRoom{ Girl getByname(String name);}事实上,两者实质上没太大区别,只是参数或者返回值的类型产生了变动,那么咱们能够这样写: abstract class Room<T>{ T getByname(String name);}从而简化了代码的应用。 怎么应用泛型泛型个别应用大写的单个字符来示意,通常来说是E, T, S, K 和 V等。 泛型最常见的应用中央是汇合中,比方List, set 和 map中: var listExample = <String>['jack ma', 'tony ma'];var setExamples = <String>{'jack ma', 'tony ma'};var mapExamples = <String, String>{ 'name1': 'jack ma', 'name2': 'tony ma',};泛型还能够用在这些汇合类的构造函数中,如下: var stringMap = Map<String, String>();示意结构进去的汇合中,应该蕴含对应的类型。 ...

November 17, 2021 · 1 min · jiezi

关于dart:dart系列之dart类的扩展

简介尽管dart中的类只能有一个父类,也就是单继承的,然而dart提供了mixin语法来绕过这样限度。 明天,和大家一起来探讨一下dart类中的继承。 应用extends和JAVA一样,dart中能够定义一个父类,而后应用extends来继承他,失去一个子类,如下所示: class Student{}class Boy extends Student{}在子类中,能够应用super关键词来调用父类的办法。 抽象类和接口dart中除了继承一般类之外,还能够继承抽象类和实现接口。 抽象类是以abstract关键词润饰的class,如下所示: abstract class Student{ String getName();}抽象类中通常会有形象办法,形象办法须要在子类中进行实现。 当然抽象类中也能够有具体实现的办法,然而抽象类不能够被实例化,如果你想在抽象类中实例化对象,这能够应用之前咱们提到的工厂构造函数。 和java不同的是,dart中并没有interface,他引入的是一个Implicit interfaces的概念。 对应每个对象来说,都隐式定义了一个蕴含类中所有办法和属性的接口。 一般来说,如果一个对象蕴含另外一个对象的构造和办法,然而他们之间的内容又是不一样的,则能够应用implements来隐式实现接口,如下所示: class Student{ String name; String get _name => name;}class Girl implements Student{ @override String name; @override String get _name => "girls";}在dart中一个类能够implements多个接口。 下面的例子中,咱们用到了@override注解,他示意子类对父类办法或者属性的重写。 在应用@override中,咱们须要留神的是,子类对父类的实现会有上面几个限度: 子类的实现办法的返回值,必须和父类返回值雷同,或者是父类返回值的子类。子类的实现办法的参数,必须和父类办法参数雷同,或者是父类参数的父类。子类办法的参数必须和父类的参数个数雷同。mixins尽管dart不反对多重继承,然而能够应用mixin来实现相似多重继承的性能。 要应用mixins,能够应用关键字with,如下所示: class Boy extends Student with Person { // ··· name='boy'; myName();}在dart中mixin是一个非凡的类,应用关键词mixin来形容,mixin的类中,没有构造函数,如下所示: mixin Person { String name=''; void myName() { print('my name is:'+name); }}在mixin中能够定义有用的办法和属性,继承mixin的类能够重写对应的属性和办法,从而达到自定义的性能。 在mixin中咱们也能够指定特定的类,也就是说只有特定的类才可能应用mixin,则能够应用关键词on,如下所示: mixin Person on Boy{ String name=''; void myName() { print('my name is:'+name); }}总结以上就是dart中继承的应用,dart中还能够继承办法,这是dart的高级利用,咱们会在后续的文章中进行介绍,敬请期待。 ...

November 16, 2021 · 1 min · jiezi

关于dart:dart系列之dart类中的构造函数

简介dart作为一种面向对象的语言,class是必不可少的。dart中所有的class,除了Null都继承自Object class。 要想应用dart中的类就要结构类的实例,在dart中,一个类的构造函数有两种形式,一起来看看吧。 传统的构造函数和JAVA一样,dart中能够应用和class名称雷同的函数作为其构造函数,这也是很多编程语言中首先的构造函数的创立形式,咱们以Student类为例,来看看dart中的构造函数是怎么样的: class Student { int age = 0; int id = 0; Point(int age, int id) { this.age = age; this.id = id; }}下面的this示意的是以后类的实例,对dart来说,this是能够疏忽的,然而在下面的例子中,因为类变量的名字和构造函数传入参数的名字是一样的,所以须要加上this来进行辨别。 下面的代码尽管很简略,然而写起来还是有太多的内容,上面是dart中的一种简写形式: class Student { int age = 0; int id = 0; Student(this.age, this.id);}当然,你也能够不指定构造函数,这样的话dart会为你创立一个默认的无参的构造函数。 命名构造函数dart和其余语言不同的中央是,还能够应用命名构造函数。命名构造函数的格局是ClassName.identifier,如下所示: class Student { int age = 0; int id = 0; Student(this.age, this.id); Student.fromJson(Map data) { print('in Student'); }}下面的Student.fromJson就是一个命名构造函数。能够应用该构造函数从Map中生成一个Student对象,有点像是java中的工厂办法。 构造函数的执行程序咱们晓得,dart中的类是能够继承的,那么对于dart中的子类来说,其构造函数的执行程序是怎么样的呢? 如果不给dart类指定构造函数,那么dart会为类主动生成一个无参的构造函数,如果这个类是子类的话,则会主动调用父类的无参构造函数。 那么对应子类的构造函数来说,初始化的时候有三步: 调用初始化列表调用父类的构造函数调用本人的构造函数在步骤2中,如果父类没有默认的无参构造函数,则须要手动指定具体父类的构造函数。怎么调用呢?能够间接在子类的构造函数前面应用:操作符接父类的构造函数,如下所示: class Student { String? firstName; Student.fromJson(Map data) { print('in Student'); }}class Jone extends Student { Jone.fromJson(Map data) : super.fromJson(data) { print('in Jone'); }}了解了父类的构造函数之后,咱们再看一下什么是初始化列表呢? ...

November 14, 2021 · 1 min · jiezi

关于dart:dart系列之dart语言中的异常

简介Exception是程序中的异常情况,在JAVA中exception有checked Exception和unchecked Exception。那么在dart中的状况是不是一样的呢?一起来看看吧。 Exception和ErrorDart中示意异样的类有两个,别离是Exception和Error。他们两个有什么区别呢? Exception是由VM或者dart code中抛出的。 Exception次要用来示意用户程序编写过程中产生的异样,是能够定位到的能够解决的异样。通常来说Exception中蕴含了足够的信息来不便用户来定位异样点。 所以Exception通常是须要被catch的。然而和java不同的是,dart中所有的异样都是unchecked 异样,也就是说dart中的异样并不强制要求被捕捉,是否捕捉异样是由程序员自行决定的。 结构一个异样很简略,如下所示: Exception("message")然而dart并不举荐这样应用,因为这样结构的异样太过通用了,即便捕捉到这样的异样,能够取得信息也比拟少。所以dart举荐抛出自定义异样,也就是说依据业务须要去创立Exception对应的类,而后依据业务须要进行抛出。 dart中也有很多Exception的子类,比方FormatException来示意各种不同的异样情景。 同样的,在JAVA中也是这样举荐的,不要间接抛出Exception,而是依据业务须要抛出自定义的异样。 和JAVA一样,dart中的Error示意的是一个重大的谬误,Error是应该在程序编写过程中须要防止的。 dart中的Error并不需要被捕捉,因为产生了Error就示意程序呈现了十分重大的谬误,曾经无奈运行上来了。 所以Error是咱们在程序编写过程中须要防止的。 Throw和catch如果程序产生了异样,则能够应用Throw语句将其抛出,而后在适合的中央应用catch进行捕捉。 比方咱们throw一个格局异样: throw FormatException('这是一个格局异样');然而在dart中,不仅仅能够throw Exception或者Error,任何一个Object都能够throw进来,如下所示: throw "这是一个异样!";抛出的异样能够应用catch来捕捉: try{ do something}catch(e){}dart也能够捕捉特定的异样,这种状况用on语句来示意,如下: try { someException();} on OutOfIndexException { // 捕捉特定的异样 doSomething();} on Exception catch (e) { // 捕捉其余的Exception print('其余的异样: $e');} catch (e) { // 解决剩下的异样 print('剩下的异样: $e');}dart中的catch能够指定两个参数,第一个参数就是throw的异样,第二个参数是StackTrace对象: try {} catch (e, s) { print('异样信息: $e'); print('堆栈信息: $s');}在解决完异样之后,如果想要再将其抛出,能够应用rethrow: void doSomething(){ try{ }catch (e) { print('get exception'); rethrow; // rethrow这个异样 }}Finally和JAVA一样,dart中也有Finally,用来进行最终的解决。Finally会在所有的catch语句执行结束之后执行: ...

November 13, 2021 · 1 min · jiezi

关于dart:dart系列之dart语言中的特殊操作符

简介有运算就有操作符,dart中除了一般的算术运算的操作符之外,还有自定义的十分非凡的操作符,明天带大家一起来摸索一下dart中的非凡操作符。 一般操作符一般操作符就很好解释了,就是加减乘除,逻辑运算符,比拟运算符和位运算符等。 这些操作符和其余语言的操作符没什么差异,这里就不具体介绍了。大家看几个一般操作符的例子: a++a + ba = ba == bc ? a : bassert(2 == 2);assert(2 != 3);assert(3 > 2);assert(2 < 3);类型测试操作符dart中的类型测试符相似JAVA中的instance of操作,次要有三个,别离是as,is和is! 其中is是类型判断操作符,而as是类型转换操作符,也就是常说的强制转换。 对上面的语句来说,如果obj是T的子类或者实现了T的接口,那么就会返回true。 obj is T 而上面的语句则会始终返回true: obj is Object?dart中的as操作符示意的是类型转换,转换类型之后就能够应用对应类型中的办法了。如下所示: (student as Student).firstName = 'Bob';那么问题来了,下面的写法和上面的写法有什么区别吗? if (student is Person) { // Type check student.firstName = 'Bob';}第一种写法中,如果student是空,或者不是Student的实例,则会报错,而第二种并不会。 条件运算符dart中也反对条件运算符,最常见的就是三元运算符: condition ? expr1 : expr2示意如果condition是true,则返回expr1, 否则返回expr2。 咱们在日常的工作中,常常会有一些判空操作,dart为咱们提供了十分简便的判空操作符: expr1 ?? expr2上式示意如果expr1为空,则抉择expr2。举个例子: String playerName(String? name) => name ?? 'Guest';级联符号级联符号是 .. 或者?.. , 用来在同一对象上进行序列操作,级联操作能够让咱们少写很多代码,能够在创立一个对象的同时,给对象赋值: ...

November 12, 2021 · 1 min · jiezi

关于dart:dart系列之dart语言中的变量

简介flutter是google在2015年dart开发者峰会上推出的一种开源的挪动UI构建框架,应用flutter能够十分不便的编译成运行在原始android,ios,web等挪动平台上的挪动利用。 flutter是应用dart来编写的,最新的flutter版本是2.5.3,而最新的Dart语言版本是2.14。 本系列将会深刻谈谈dart语言的用法和最佳实际,心愿大家可能喜爱。 dart中的变量Dart语言汲取了java和javascript的精髓,如果你是上述语言的开发者,那么会很容易迁徙到dart语言上。咱们先从一个语言最根本的变量开始,探讨dart语言的神秘。 定义变量Dart中定义变量和java,javascript中定义变量是统一的,如下所示: var name = 'jack';下面咱们应用var示意name的类型是能够通过推断失去。在程序编写过程中,如果咱们遇到某些变量并不知道其类型的时候,能够尝试应用var,让dart自行推断。 当然,咱们也能够指定变量的类型,如上所示,能够指定name为String类型: String name = 'jack';在dart中,所有的变量都是Object,而每个对象都是一个Class的实例。包含数字、函数、null都是Object。所有的对象都继承自Object类。 所以下面的赋值也能够这样写: Object name = 'jack';变量的默认值在dart中,未初始化的变量都有一个nullable类型的值,这个值的初始值是null。 和java中不一样的是,dart中所有的number的初始值也是null。这是因为dart中的number也是一个对象。 如果一个变量能够为null,那么在赋值的时候能够在变量类型前面加上?, 如下所示: int? age;对于类变量来说,只会在应用的时候进行初始化,这种初始化策略叫做延时初始化。 Late变量Late修饰符是在Dart 2.12引入的新个性。他能够示意变量须要被延时加载,或者示意一个不为空的变量会在后续被初始化。 咱们能够这样应用: late int age;void main() { age = 18; print(age);}为什么用late呢?因为有时候Dart无奈查看某些变量在应用之前是否被初始化了,然而如果你十分确定的话,应用late来润饰它即可。 另外,late润饰的变量只有在应用的时候才会被初始化,所以咱们能够应用late来定义一些耗时、耗资源的操作。 常量如果变量是不会变动的,那么这就不是变量了,而是常量。 常量能够用final或者const来润饰,final变量示意变量只会被赋值一次。 而const变量示意变量会在编译的时候被赋值,默认const也是final的。 如下所示: final age = 18; final int age = 18;const age = 20; 如果const变量是class变量,那么将其设置为static。 constant还能够用来赋值,如下所示: var age = const [];final bar = const [];const baz = []; // Equivalent to `const []`下面的代码中,尽管age的值是const的,然而age自身并不是const,所以age是能够从新被赋值的: ...

November 8, 2021 · 1 min · jiezi

关于dart:一个-JSer-的-Dart-学习日志三类

本文是“一个 JSer 的 Dart 学习日志”系列的第三篇,本系列文章次要以开掘 JS 与 Dart 异同点的形式,在温习和坚固 JS 的同时安稳地过渡到 Dart 语言。鉴于作者尚属 Dart 初学者,所以意识可能会比拟浮浅和全面,如您慧眼识虫,心愿不吝指正。如无非凡阐明,本文中 JS 蕴含了自 ES5 至 ES2021 的全副个性, Dart 版本则为 2.0 以上版本。 在 ES6 问世之前,宽泛风行的 JS 面向对象编程是应用原型链而非应用类,开发者须要对相干个性有足够的理解,并遵循一些默认的规定,能力勉强模拟出一个大抵可用的“类”。即使是 ES6 引入了 class 关键字来补救,作为新一代 JS 基础设施的类还是有待欠缺。相比之下,Dart 对类的反对就要欠缺和弱小得多。 一. 类似的整体构造两种语言中,用于定义类的语法结构高度类似,次要包含class关键字、类名、包裹在花括号{}外部的成员。 > /* Both JS and Dart */> class ClassName {> attrA;> attrB = 1;>> methodA(a, b){> // do something> this.attrA = a;> this.attrB = b;> }> }二. 构造函数相同之处构造函数在实例化类的时候调用,用于解决实例化参数、初始化实例属性等;应用 super 拜访超类的构造函数;没有超类,或超类的构造函数没有参数的时候,构造函数能够省略,省略构造函数的子类实例化的时候会隐式地调用超类的构造函数。不同之处1. constructor vs SameNameJS 中的构造函数为 constructor;Dart 中的构造函数为与类名统一的函数。 ...

September 28, 2021 · 4 min · jiezi

关于flutter:Flutter中关于使用异步时获得FutureT中数据的问题

应用异步取得Future<T>在flutter我的项目中应用async await异步获取数据时,会返回一个Future<T>类型的数据,然而将其应用在widget中,会有一个问题:在statefulWidget中应用变量接管值,会呈现无奈赋值的状况 ///index.dart class Index extends StatefulWidget { Index({Key key}) : super(key: key); @override _IndexState createState() => _IndexState();} class _IndexState extends State<Index> { List<Widget> _temps; String _studentId = "abcd"; String _token = "lkjncasfmalknfadwSadwawf1dawd"; @override void initState() { super.initState(); _temps = _getClassItems(getOneDaylessons(_dates, _studentId, _token)); } var _dates = initDate(); void _getDates(value) { _dates = DateFormat('EEE', "en_US").format(value).toString(); setState(() { _temps = _getClassItems(getOneDaylessons(_dates, _studentId, _token)); }); } List<Widget> _getClassItems(List<Widget> classItems) { if (classItems.isEmpty) { return [ Container( height: 60, child: Center( child: Text("今日暂无课程"), ), ) ]; } else { return classItems; } } @override Widget build(BuildContext context) { return Scaffold( body: Container( child: Column( children: _temps,//报错处 ), ) ) } ///getOneDaylessons.dart List<Widget> getOneDaylessons(String date, String studentId, String token) { ClassResponseData _data; getTimeTableFromStudentID(studentId, token) .then((v) => {_data=v}); List<ClassItemViewModel> datas = getADayClasses(data); List temp = datas .map((e) { if (e.date == date) { return ClassItem(data: e); } }) .toList() .where((element) => element != null) .toList(); return temp;}//运行我的项目报错_temps是null解决方案将getOneDaylessons同样应用async包装,返回Future<T>到index.dart.在index.dart中,应用FutureBuilder,取值 ...

April 8, 2021 · 2 min · jiezi

关于dart:Dart-212-现已发布

作者 / Michael Thomsen Dart 2.12 现已公布,其中蕴含 健全的空平安 和 Dart FFI 的稳定版。空平安是咱们最新主打的一项生产力强化性能,意在帮忙您躲避空值谬误,以前这种谬误通常很难被发现,您能够观看上面这支视频理解详情。FFI 则是一种互操作机制,反对调用以 C 语言编写的既有代码,例如调用 Windows Win32 API。欢送大家即刻开始应用 Dart 2.12。 https://www.bilibili.com/vide... Dart 平台的独特性能在具体理解健全空平安和 FFI 之前,咱们先来讨论一下它们在哪些方面符合了咱们对 Dart 平台的冀望。编程语言往往有很多相似的性能,例如,很多语言都反对面向对象的编程或在 web 上运行。真正将各个语言辨别开来的,是其独特的性能组合。 Dart 具备横跨三个维度的独特性能组合: 可移植性: 高效的编译器可针对设施生成 x86 和 ARM 机器代码,并针对 web 生成优化的 JavaScript。同时兼容挪动设施、桌面 PC、利用后端等多种 指标平台。大量的开发库和 package 提供了可在所有平台上应用的统一的 API,进一步升高了开发者创立真正多平台利用的老本。高生产力: Dart 平台反对热重载,因而可在原生设施和 web 上实现疾速迭代开发。此外,Dart 还提供了丰盛的构造,如 isolates 和 async/await 等,用以解决和实现常见的并发和事件驱动的利用模式。持重: Dart 的健全空平安类型零碎能够在开发过程中就捕捉到谬误。整个平台领有极好的可扩展性和可靠性,曾经被大量且多样的利用在累计超过十年的生产环境中实战测验过,其中包含 Google 的一些要害业务利用,如 Google Ads 和 Google Assistant 等。健全空平安加强了类型零碎的稳健性,同时进步了性能。借助 Dart FFI,您能够取得更强的可移植性,同时沿用由 C 语言编写的既有代码,在解决对性能要求极为严苛的工作时,能够纵情应用通过精心优化的 C 语言代码。 ...

March 12, 2021 · 3 min · jiezi

关于dart:Flutter-24FlutterUI布局和WidgetStatelesswidget与Statefulwidget

Statelesswidget如果一个Widget从初始化到应用再到销毁,整个过程中都不须要批改其UI的款式,例如纯展现页面,咱们就用Statelesswidget。常见的Statelesswidget有:Text、Icon、ImageIcon、Dialog等。能够看到这些往往都是一些展现类的,不须要扭转其状态的控件。应用Statelesswidget更轻量,更节俭内存资源。初始化Statelesswidget的时候不会附带一些动静更新UI的办法,这样也会晋升咱们软件的性能。 须要留神的是:在iOS开发中,初始化一个Label并命名为la,扭转它的文字内容,会调用la.text = @"new text",咱们能够了解为Label不是Statelesswidget的,因为它的text属性被扭转了。那Flutter的Text为什么又是Statelesswidget的呢?因为Flutter中所有Widget都是 “配置文件”,当咱们批改文本之后,Flutter会帮忙咱们从新初始化一个Text,而不是批改以后的Text对象,这是与原生开发不一样的中央。StatefulwidgetStatefulwidget是可变的Widget,在咱们的开发中会大量应用Statefulwidget。它实现了一个setState办法,当咱们调用这个办法的时候,该Statefulwidget会被从新渲染,留神是从新被渲染,而不是部分更新。当咱们调用setState时,Flutter在收到该音讯后,会从新调用其build办法从新构建这个widget,从而达到更新UI的目标。 来看如下代码: class StatefulWidgetDemoPage extends StatefulWidget { @override _StatefulWidgetDemoPageState createState() => _StatefulWidgetDemoPageState();}class _StatefulWidgetDemoPageState extends State<StatefulWidgetDemoPage> { @override Widget build(BuildContext context) { return Scaffold( floatingActionButton: FloatingActionButton( onPressed: () { setState(() {}); }, child: Icon(Icons.add), ), appBar: AppBar( title: Text("StatefuleWidget Demo"), centerTitle: true, backgroundColor: Colors.blue, ), body: Column( children: [ Container( width: 100, height: 100, margin: EdgeInsets.all(10), /// 色彩一个随机值 color: _randomColor(), ), ], ), ); } /// 获取一个随机的色彩值 _randomColor() { return Color.fromARGB(255, Random().nextInt(255), Random().nextInt(255), Random().nextInt(255)); }}咱们定义了一个生成随机色彩的办法_randomColor(),它会返回一个Color对象,而后咱们又定义了一个Container,Container的初始化参数color的值是_randomColor()的返回值。而后咱们在FloatingActionButton的onPressed的办法中调用一下setState办法,这个时候Flutter会从新绘制StatefulWidgetDemoPage,所以每次点击按钮,咱们能够看到Container的色彩都是不一样的。 ...

January 23, 2021 · 1 min · jiezi

关于dart:Flutter-117Flutter手把手教程UI控件多图预警按钮详解

作者 | 弗拉德起源 | 弗拉德(公众号:fulade_me) Material 格调中罕用的按钮有三种RaiseButton、FlatButton、OutlineButton。这三种按钮都是继承了MaterialButton,而MaterialButton又继承自StatelessWidget。 RaiseButton:带有暗影成果的按钮,默认带有灰色背景,点击上来会有点击成果和暗影。FlatButton: 扁平格调按钮,点击上来会有背景色彩。OutlineButton: 带有边框的按钮,且边框会在点击时扭转色彩。 1. RaisedButton咱们先来看RaisedButton的构造方法 const RaisedButton({ Key key, /// 点击后的回调办法 @required VoidCallback onPressed, /// 长按后的回调办法 VoidCallback onLongPress, /// 高亮时候的回调办法 ValueChanged<bool> onHighlightChanged, /// 鼠标指针的光标进入或悬停在此按钮(这个用于Web端或PC端) MouseCursor mouseCursor, /// 文本的主题,这个跟MaterialApp的属性theme无关 ButtonTextTheme textTheme, /// 文本色彩 Color textColor, /// 不可点击时的文本色彩 Color disabledTextColor, /// 背景色彩 Color color, /// 可点击时的背景色彩 Color disabledColor, /// 获取焦点时的色彩(用于Web端或PC端) Color focusColor, /// 指鼠标悬停时的色彩(用于Web端或PC端) Color hoverColor, /// 高亮时的色彩 Color highlightColor, /// 水波纹色彩,按下松开会有水波纹成果 Color splashColor, /// 按钮主题色彩,默认浅色 Brightness colorBrightness, /// 默认时的 暗影大小 double elevation, /// 选中时的 暗影大小 double focusElevation, /// 指鼠标悬停时的暗影大小 double hoverElevation, /// 高亮时的暗影大小 double highlightElevation, /// 不可选中时的暗影大小 double disabledElevation, /// 内边距 跟布局无关 EdgeInsetsGeometry padding, VisualDensity visualDensity, /// 设置按钮的形态 ShapeBorder shape, /// 切边的款式 Clip clipBehavior = Clip.none, FocusNode focusNode, bool autofocus = false, MaterialTapTargetSize materialTapTargetSize, /// 动画的工夫 Duration animationDuration, /// 子控件 Widget child, }) 1.1 一个最简略的RaisedButton ...

December 20, 2020 · 3 min · jiezi

关于dart:Flutter-115Flutter手把手教程Dart语言包管理工具Pub详解pub-getpub-cache使用

作者 | 弗拉德起源 | 弗拉德(公众号:fulade_me) 什么是Pub工具Dart 生态系统应用包来治理共享软件,比方:库和工具。咱们应用Pub包管理工具 来获取Dart包。在Pub上,能够找到公开可用的包。或者从本地文件系统或其余的地位,比方Git仓库,加载可用的包。无论包是从什么路径加载的, Pub 都会进行版本依赖治理,从而帮忙咱们取得版本兼容的软件包以及SDK。pub工具蕴含治理 Package 、部署 Package 和部署命令行利用的命令。Dart 包目录中至多蕴含一个pubspec文件。 pubspec 文件记录一些对于我的项目的依赖数据。此外还有一些其余数据比方:Dart 库,利用,资源,测试,图片,以及示例。 上面是一个 pubspec 的示例,示例中申明依赖了在 Pub 站点上托管的两个包( js 和 intl ): name: my_appdependencies: js: ^0.6.0 intl: ^0.15.8pub get在我的项目中配置了pubspec文件后,就能够在我的项目根目录中执行pub get命令: cd <path-to-my_app> pub getpub get命令确定以后利用所依赖的包,并将它们保留到地方零碎缓存(central system cache)中。如果以后利用依赖了一个公开包,Pub会从Pub站点 该包。对于一个Git依赖,Pub会Clone该Git仓库。同样包含包的相干依赖也会被下载。例如,如果 js 包依赖 test 包, pub 会同时获取js包和test包。 Pub 会创立一个.packages 文件(位于应用程序的根路目录下),该文件将应用程序所依赖的每个包名相应的映射到零碎缓存中的包。 pub upgrade第一次获取依赖时,Pub 会下载依赖及其兼容的最新版本。而后通过创立lockfile 锁定依赖,以始终应用这个版本。 Pub会在pubspec旁创立并存储一个名为pubspec.lock文件。它列出了应用的每个依赖包的指定版本(以后包或传递包的版本)。在开发我的项目中的每个人都可能应用所有雷同版本的包。同样退出到 lockfile 能够保障部署的利用应用的是同一版本的代码。 如果曾经筹备更新依赖到最新版本,应用命令 pub upgrade : pub upgrade下面的命令用于从新生成 lockfile 文件,并应用最新可用版本的依赖包。如果仅降级某个依赖,能够在命令中指定须要降级的包: ...

December 15, 2020 · 2 min · jiezi

关于dart:Flutter-114Flutter手把手教程Dart语言Dart语言引用importpackage使用

作者 | 弗拉德起源 | 弗拉德(公众号:fulade_me) 库import 关键字能够帮忙你创立一个模块化和可共享的代码库,代码库不仅只是提供 API 而且还起到了封装的作用:以下划线(_)结尾的成员仅在代码库中可见。 应用库应用import来指定命名空间以便其它库能够拜访。比方你能够导入代码库 dart:html来应用Dart Web中相干 API: import 'dart:html';import的惟一参数是用于指定代码库的URI,对于Dart内置的库,应用 dart:xxxxxx的模式。而对于其它的库,你能够应用一个文件系统门路或者以 package:xxxxxx 的模式。package:xxxxxx 指定的库通过包管理器(比方 pub 工具)来提供: import 'package:test/test.dart';指定库前缀如果你导入的两个代码库有抵触的标识符,你能够为其中一个指定前缀。比方如果 library1和library2 都有Element 类,那么能够这么解决: import 'package:lib1/lib1.dart';import 'package:lib2/lib2.dart' as lib2;// 应用 lib1 的 Element 类。Element element1 = Element();// 应用 lib2 的 Element 类。lib2.Element element2 = lib2.Element();导入库的一部分如果你只想应用代码库中的一部分,你能够有选择地导入代码库。例如: // 只导入 lib1 中的 foo。(Import only foo).import 'package:lib1/lib1.dart' show foo;// 导入 lib2 中除了 foo 外的所有。import 'package:lib2/lib2.dart' hide foo;提早加载库提早加载(也常称为懒加载)容许利用在须要时再去加载代码库,上面是可能应用到提早加载的场景: 为了缩小利用的初始化工夫。解决 A/B 测试,比方测试各种算法的不同实现。加载很少会应用到的性能,比方可选的屏幕和对话框。应用deferred as关键字来标识须要延时加载的代码库: ...

December 12, 2020 · 1 min · jiezi

关于dart:Flutter-113Flutter手把手教程Dart语言异步FutureStreamasyncawait详解

作者 | 弗拉德起源 | 弗拉德(公众号:fulade_me) 异步Dart 代码库中有大量返回Future或Stream对象的函数,这些函数都是异步的,它们会在耗时操作执行结束前间接返回而不会期待耗时操作执行结束。async和await关键字用于实现异步编程,并且让你的代码看起来就像是同步的一样。 Future能够通过上面两种形式,取得Future执行实现的后果: 应用async和await;应用Future API;应用async和await的代码是异步的,然而看起来有点像同步代码。例如,上面的代码应用await期待异步函数的执行后果。 await lookUpVersion();必须在带有async关键字的异步函数中应用 await: Future checkVersion() async { var version = await lookUpVersion(); // 应用 version 持续解决逻辑}只管异步函数能够解决耗时操作,然而它并不会期待这些耗时操作实现,异步函数执行时会在其遇到第一个 await表达式的时候返回一个Future对象,而后期待await表达式执行结束后继续执行。 应用try、catch以及finally来解决应用await导致的异样: try { version = await lookUpVersion();} catch (e) { // 无奈找到版本时做出的反馈}你能够在异步函数中屡次应用await关键字。例如,上面代码中期待了三次函数后果: var entrypoint = await findEntrypoint();var exitCode = await runExecutable(entrypoint, args);await flushThenExit(exitCode);await表达式的返回值通常是一个Future对象;如果不是的话也会主动将其包裹在一个Future对象里。Future对象代表一个"承诺",await表达式会阻塞直到须要的对象返回。 如果在应用await时导致编译谬误,请确保await在一个异步函数中应用。例如,如果想在main()函数中应用await,那么main()函数就必须应用async关键字标识。 Future main() async { checkVersion(); print('在 Main 函数中执行:版本是 ${await lookUpVersion()}');}申明异步函数定义异步函数只需在一般办法上加上async关键字即可。将关键字async增加到函数并让其返回一个Future 对象。假如有如下返回String对象的办法: String lookUpVersion() => '1.0.0';将其改为异步函数,返回值是Future: ...

December 12, 2020 · 1 min · jiezi

关于dart:Flutter-112Flutter手把手教程Dart语言什么是泛型和泛型的使用场景

作者 | 弗拉德 起源 | 弗拉德(公众号:fulade_me) 泛型如果你查看数组的API文档,你会发现数组List的理论类型为List<E>。<> 符号示意数组是一个泛型(或参数化类型)通常应用一个字母来代表类型参数,比方E、T、S、K 和 V 等等。 为什么应用泛型?泛型罕用于须要要求类型平安的状况,然而它对代码运行也有益处: 适当地指定泛型能够更好地帮忙代码生成。应用泛型能够缩小代码反复。比方你想申明一个只能蕴含String类型的数组,你能够将该数组申明为List<String>,这示意只能蕴含字符串类型的数组。这样的话就能够很容易防止因为在该数组放入非String类变量而导致的诸多问题,同时编译器以及其余浏览代码的人都能够很容易地发现并定位问题: var names = List<String>();names.addAll(['Seth', 'Kathy', 'Lars']);names.add(42); // 这样写就会报错另一个应用泛型的起因是能够缩小反复代码。泛型能够让你在多个不同类型实现之间共享同一个接口申明,比方上面的例子中申明了一个类用于缓存对象的接口: /// 定义一个 抽象类abstract class ObjectCache { Object getByKey(String key); void setByKey(String key, Object value);}不久后你可能又会想专门为String类对象做一个缓存,于是又有了专门为String做缓存的类: /// 另外一个抽象类abstract class StringCache { String getByKey(String key); void setByKey(String key, String value);}如果过段时间你又想为数字类型也创立一个类,那么就会有很多诸如此类的代码。这时候能够思考应用泛型来申明一个类,让不同类型的缓存实现该类做出不同的具体实现即可: abstract class Cache<T> { T getByKey(String key); void setByKey(String key, T value);}在上述代码中,T是一个代替类型。其相当于类型占位符,在开发者调用该接口的时候会指定具体类型。 应用汇合字面量List、Set以及Map字面量也能够是参数化的。定义参数化的List只需在中括号前增加<type>;定义参数化的Map只须要在大括号前增加 <keyType, valueType>: var names = <String>['小芸', '小芳', '小民'];var uniqueNames = <String>{'小芸', '小芳', '小民'};var pages = <String, String>{ 'index.html': '主页', 'robots.txt': '网页机器人提醒', 'humans.txt': '咱们是人类,不是机器'};应用类型参数化的构造函数在调用构造方法时也能够应用泛型,只需在类名后用尖括号<...>将一个或多个类型包裹即可: ...

December 11, 2020 · 1 min · jiezi

关于dart:flutter异步编程事件循环IsolateStream流

事件循环、Isolate开始前咱们须要明确 Dart 是单线程的并且 Flutter 依赖于 Dart 如果你晓得js 中的event loop 将很好了解dart的整个异步过程 先看一段代码 import 'dart:async';Future eventLoop() async{print('A');Future((){print('F');scheduleMicrotask((){print('H');});Future((){print('M');}).then((_){print('N');});}).then((_){print('G');});Future((){print('I');}).then((_){print('J');});scheduleMicrotask(text1);scheduleMicrotask((){print('D');});print('B');}void text1() {print('C');scheduleMicrotask((){print('E');});Future((){print('K');}).then((_){print('L');});}你只到输入后果吗 正确的输入程序是: A B C D E F G H I J K L M NeventLoop1、MicroTask 队列微工作队列,个别应用scheduleMicroTask办法向队列中增加 这是大多数时候你不用应用的货色。比方,在整个 Flutter 源代码中 scheduleMicroTask() 办法仅被援用了 7 次, 所以最好优先思考应用 Event 队列 2、Event 队列I/O、手势、绘图、计时器、流、futures等等异步操作都将进入event队列 尽量应用事件队列能够使微工作队列更短,升高事件队列卡死的可能性 代码执行程序首先咱们晓得dart是单线程的,所以dart的代码执行程序是: 同步代码顺次执行碰到异步代码先进对应的队列中,而后继续执行上面的代码当同步代码执行结束,先去看MicroTask 队列中的工作,将MicroTask队列中的工作顺次执行结束MicroTask中的工作执行结束后,再去看Event 队列中的工作,event队列出一个工作 而后执行 , 而后回到第三步 循环 直到所有队列都清空IsolateIsolate 是 Dart 中的 线程, Flutter的代码都是默认跑在root isolate上的 「Isolate」在 Flutter 中并不共享内存。不同「Isolate」之间通过「音讯」进行通信。import 'dart:async';import 'dart:io';import 'dart:isolate';import 'package:flutter/foundation.dart';import 'package:flutter/material.dart';//一个普普通通的Flutter利用的入口//main函数这里有async关键字,是因为创立的isolate是异步的void main() async{runApp(MyApp());//asyncFibonacci函数里会创立一个isolate,并返回运行后果print(await asyncFibonacci(20));}//这里以计算斐波那契数列为例,返回的值是Future,因为是异步的Future<dynamic> asyncFibonacci(int n) async{//首先创立一个ReceivePort,为什么要创立这个?//因为创立isolate所需的参数,必须要有SendPort,SendPort须要ReceivePort来创立final response = new ReceivePort();//开始创立isolate,Isolate.spawn函数是isolate.dart里的代码,_isolate是咱们本人实现的函数//_isolate是创立isolate必须要的参数。await Isolate.spawn(_isolate,response.sendPort);//获取sendPort来发送数据final sendPort = await response.first as SendPort;//接管音讯的ReceivePortfinal answer = new ReceivePort();//发送数据sendPort.send([n,answer.sendPort]);//取得数据并返回return answer.first;}//创立isolate必须要的参数void _isolate(SendPort initialReplyTo){final port = new ReceivePort();//绑定initialReplyTo.send(port.sendPort);//监听port.listen((message){//获取数据并解析final data = message[0] as int;final send = message[1] as SendPort;//返回后果send.send(syncFibonacci(data));});}int syncFibonacci(int n){return n < 2 ? n : syncFibonacci(n-2) + syncFibonacci(n-1);}因为Root isolate会负责渲染,还有UI交互,如果咱们有一个很耗时的操作呢?后面晓得isolate里是一个event loop(事件循环),如果一个很耗时的task始终在运行,那么前面的UI操作都被阻塞了,所以如果咱们有耗时的操作,就应该放在isolate里! ...

September 18, 2020 · 1 min · jiezi

dart字符串基本属性及方法

代码示例// 单行字符串String str = 'abc';//多行字符串String multiLine = '''这是多行文本 能够回车的''';// 字符串连贯形式'Dart ' 'is ' 'fun!'; // 'Dart is fun!''Dart ' + 'is ' + 'fun!'; // 'Dart is fun!''Dart' * 2; // 'DartDart'String属性属性形容List<int> codeUnits获取字符串utf-16编码值的列表int hashCode获取字符派生的哈希代码bool isEmpty字符串是否为空bool isNotEmpty字符串是否不为空int length获取字符串长度Runes runes获取字符串utf-16编码值的可迭代列表Type runtimeType获取运行时的数据类型String办法属性形容int codeUnitAt(int index)返回给定索引值的对应utf-16编码int compareTo(String other)与传入字符串进行比拟,有雷同返回1,否则返回-1bool contains(Pattern other, [int index])查找返回字符串是否有符号要求的,传入index规定从index位开始查找bool endsWith(String other)字符串的结尾是否为传入的值int indexOf(Pattern other, [int start])从字符串后面开始查找返回合乎规定的第一个的索引地位,传入start规定从哪里开始查找int lastIndexOf(Pattern other, [int start])与indexOf雷同,不同的是这个办法是从前面开始查找String padLeft(int width, [String padding])如果字符串没有width的长度,则在后面加上padding字符串并返回,不会扭转原字符串String padRight(int width, [String padding])同padLeft办法雷同,不同的是从padding加在前面String replaceAll(Pattern from, String to)替换所有匹配的子字符串String replaceAllMapped(Pattern from, String replace(match))将匹配到的字符串用函数解决后返回字符串替换String replaceFirst(Pattern from, String to, [int index])替换第一个匹配的子字符串,能够规定从index出开始匹配String replaceFirstMapped(Pattern from, String replace(match), [int index])同replaceAllMapped,此办法只替换第一个匹配的值,能够规定从index处开始匹配String replaceRange(int start, int end, String to)替换范畴类的字符串List<String> split(Pattern pattern)拆分字符串为数组String splitMapJoin(Pattern pattern, { String onMatch(match), String onNonMatch(match) })拆分替换字符串,匹配和不匹配的执行对应函数替换成返回值bool startsWith(Pattern pattern, [int index])是否是匹配的正则或字符串开始,能够规定从index开始查找String substring(int startIndex, [int endIndex])提取字符串中startIndex(蕴含)到endIndex(不蕴含)两个指定的索引号之间的字符。String toLowerCase()把字符串转换为小写String toUpperCase()把字符串转换为大写String trim()去除字符串两边的空白String trimLeft()去除字符串右边的空白String trimRight()去除字符串左边的空白

July 15, 2020 · 1 min · jiezi

Dart面向对象编程一基础篇

6-2类与对象主文件// 引入库(dart文件)import 'calss_and_obj2.dart';void main() {  // 创建一个对象  var getp = new p();// 赋值 写入类中的属性的值  getp.name = 'tom';  getp.age = 20;// 获取值 读类中的属性  print(getp.name);// 读类中的方法  getp.work();  print(getp.address);}引入文件// 声明一个类class p {  // 加下划线代表私有的 只在当前dart文件中可以调用 外链的dart文件不可见  // 属性和方法也可加下划线表示私有// class _p{  String name;  int age;// final定义的 只能读不能写  final String address = 'aaaa';// 声明方法  void work() {    print('name is $name,age=$age,he is working');  }}6-3计算属性// void main(){//   var rect=new Rctangle();//   rect.height=20;//   rect.width=10;//   print(rect.area());// }// class Rctangle{//   num width,height;//   num area(){//     return width * height;//   }// }void main() {  var rect = new Rctangle();  rect.height = 20;  rect.width = 10;  print(rect.area);  rect.area = 200;  print(rect.width);}class Rctangle {  num width, height;  // 计算属性get获取值 也可以set  num get area {    return width * height;  }  set area(value) {    width = value / 20;  }}6-4构造方法void main() {  // var person=new Person('Tom',30,'male');  var person = new Person('Tom', 30);  var person1 = new Person.getn('Tom1');  person.name = 'topm';  person.age = 20;  print(person.name);  print(person.age);  print(person1.name);  // print(person.gender);}class Person {  String name;  int age;  // 构造方法 如果有自定义的构造方法 那么默认的是不要的  Person(String name, int age) {    this.name = name;    this.age = age;  }// final String gender;// 语法糖 这种方法可以 给final变量赋值// Person(this.name,this.age,this.gender);// 有名字的构造方法  Person.getn(this.name);  void work() {    print('working');  }}6-5常量构造方法// 常量构造方法void main() {  const person = const Person('Tom', 30);  print(person.name);}class Person {  final String name;  final int age;  // 构造方法 如果有自定义的构造方法 那么默认的是不要的  const Person(this.name, this.age);// final String gender;// 语法糖 这种方法可以 给final变量赋值// Person(this.name,this.age,this.gender);// 有名字的构造方法  // Person.getn(this.name);  void work() {    print('working');  }}6-6工厂构造方法class Logger {  final String name;  // Map<String, Logger>泛型 来限制key value的类型  static final Map<String, Logger> _cache = <String, Logger>{};  // 工厂构造方法 可以返回对象  factory Logger(String name) {    if (_cache.containsKey(name)) {      return _cache[name];    } else {      final logger = Logger._internal(name);      _cache[name] = logger;      return logger;    }  }  // 构造方法是不能有返回值的  Logger._internal(this.name);  void log(String msg) {    print(msg);  }}6-7初始化列表// 常量构造方法void main() {  var a = {'name': '1', 'age': 2, 'gender': '3'};  var person = new Person.withmap(a);  print(person.name);}class Person {  String name;  int age;  final String gender;  Person(this.name, this.age, this.gender);// 列表构造方法 执行时间 在构造方法前面 可以对 final属性赋值  Person.withmap(Map map) : gender = map['gender'] {    this.name = map["name"];    this.age = map['age'];  }  void work() {    print('working');  }}6-8静态成员1非静态的方法可以访问静态属性2静态方法不能使用实例化对象来访问 只能通过类名加方法名访问3在类中声明常量 static const int age=10; 6-9对象操作符import 'constructors.dart';void main() {// Person person=new Person();// 条件运算符 解决空指针问题// 对象不为空 执行// person?.work();// var person;// person='';// person=new Person();// person.work();// 把对象转换成xx类型 强转// (person as Person).work();// 判断对象是否为Person对象类型// if(person is Person){//   person.work();// }// 判断对象不是Person对象类型// else if(person is! Person){// print('11111');// }  var person = new Person();// person.name='aa';// person.age=30;// 级联操作  person    ..name = 'aa'    ..age = 30;  print(person.name);}class Person {  String name;  int age;  void work() {    print('working');  }}6-10对象call方法void main() {  var person = new Person();// person.name='aa';// person.age=30;//   print(person.name);// name is null// 执行类中的call方法  person('gggggg');}class Person {  String name;  int age;  void work() {    print('working');  }  // 也可以写成有返回值的 名称必须为call  void call(String name) {    print('name is $name');  }}

July 7, 2020 · 1 min · jiezi

dart控制语句和方法

控制语句4-1if语句void main() {  int score = 100;  if (score >= 90) {    if (score == 100) {      print('完美');    } else {      print('优秀');    }  } else if (score > 60) {    print('良好');  } else if (score == 60) {    print('及格');  } else {    print('不及格');  }}4-2for语句void main() {  var list = [1, 2, 3, 4, 5];  // for循环  for (var index = 0; index < list.length; index++) {    print(list[index]);  }  // 不需要使用下标时 可以使用这种方法遍历列表的元素  for (var item in list) {    print(item);  }}4-3while语句void main() {  int c = 0;  // 当c<5时就循环打印c 打完加1  while (c < 5) {    print(c++);  }// 先执行do再进行while循环  do {    print(c--);  } while (c > 0 && c < 5);}4-4break和continuevoid main() {  var list = [1, 2, 3];  for (var i in list) {    // if (i != 2) {    //   print(i);    // }    if (i == 2) {      //跳出当前循环// break;// 打印1,3会跳过当前这种情况继续执行      continue;    }    print(i);  }  print('----------');  var list2 = [4, 5, 6];  for (var a in list2) {    if (a == 5) {      //只会终止自己所在的for循环 外边还有嵌套的for循环 不会终止      break;    }    print(a);  }}4-5switch...case语句void main() {  String lan = 'java';  // switch case 每个case后面要跟一个break;默认是default  switch (lan) {    case 'dart':      print('dart is my fav');      break;    case 'java':      print('java is my fav');      break;    default:      print('none');  }  switch (lan) {    D:    case 'dart':      print('dart is my fav');      break;    case 'java':      print('java is my fav');      // 先执行当前case中的 然后跳转到D中的case继续执行      continue D;    // break;    default:      print('none');  }}方法5-1方法的定义// void是没有返回值的 返回值类型:方法名(参数){return:返回值}//"f:\vscodexm\dartlearn\chapter5\function_declaration.dart" 1 'test' true// 方法也是对象 并且有具体类型的function// 返回值类型  参数类型 都可以省略// 箭头语法简化代码 只适用于一个表达式// 方法都有返回值 没指定 return nullvoid main(List args) {  print(args);  print(geta('张三', 18));  printp('李四', 20);}// String geta(String name,int age){// return 'name=$name,age=$age';// }// =>箭头可以表示返回值 箭头后面可以跟表达式int gender = 2;geta(name, age) => gender == 1 ? 'name=$name,age=$age' : 'test';// 返回值类型 和参数类型可以省略 默认为void// printp(name,age){//   print('name=$name,age=$age');// }void printp(String name, int age) {  print('name=$name,age=$age');}5-2可选参数// void是没有返回值的 返回值类型:方法名(参数){return:返回值}//"f:\vscodexm\dartlearn\chapter5\function_declaration.dart" 1 'test' true// 方法也是对象 并且有具体类型的function// 返回值类型  参数类型 都可以省略// 箭头语法简化代码 只适用于一个表达式// 方法都有返回值 没指定 return nullvoid main(List args) {  print(args);  print(geta('张三', 18));  printp('李四', 20);}// String geta(String name,int age){// return 'name=$name,age=$age';// }// =>箭头可以表示返回值 箭头后面可以跟表达式int gender = 2;geta(name, age) => gender == 1 ? 'name=$name,age=$age' : 'test';// 返回值类型 和参数类型可以省略 默认为void// printp(name,age){//   print('name=$name,age=$age');// }void printp(String name, int age) {  print('name=$name,age=$age');}5-3默认参数值void main() {  // name=xxx,gender=null,age=null调用这个方法后两个参数可不传  printp('xxx');// name=xxx,gender=male,age=20{}根据命名来  printp('xxx', gender: 'male');  printp('xxx', age: 20);}// {int age=30,String gender='female'}设置默认参数printp(String name, {int age = 30, String gender = 'female'}) {  print('name=$name,gender=$gender,age=$age');}### 5-4方法对象void main() {  var func = printhello;  Function func1 = printhello;  func();  func1();// 方法作为一个参数进行传递  var list = [1, 2, 3, 4];  list.forEach(print);  var list2 = ['a', 'b', 'c'];// [aaa, bbb, ccc一个方法 作为其他方法参数进行传递  print(listtimes(list2, times));}// dart中方法也都是对象 可以赋值给其他对象或变量void printhello() {  print('hello');}List listtimes(List list, String times(str)) {  for (var i = 0; i < list.length; i++) {    list[i] = times(list[i]);  }  return list;}String times(str) {  return str * 3;}5-5匿名方法void main() {  // 匿名方法 可以通过赋值给对象或者方法来调用  // (){  //   print('hello');  // };  // 匿名方法也可以传参  var func = (str) {    print('hello----$str');  };  func(30);  // 直接调用匿名方法 不推荐使用  (() {    print('test不推荐');  })();  var list2 = ['a', 'b', 'c'];  var result = listtimes(list2, (str) => str * 3);  print(result);  // listtimes(list2, (str){return str*3;});}List listtimes(List list, String times(str)) {  for (var i = 0; i < list.length; i++) {    list[i] = times(list[i]);  }  return list;}5-6闭包// 闭包是一个方法(对象)// 闭包定义在其他方法内部// 闭包能够访问外部方法中的局部变量,并持有其状态void main() {  var func = a();  func();  func();  func();  func();}a() {  int count = 0;  //printCount是一个闭包 可以持有a中count的状态 也可以使用匿名方法  // printCount(){  //   print(count++);  // }  // return printCount;  // 匿名方法  return () {    print(count++);  };}

July 5, 2020 · 1 min · jiezi

dart数据类型和运算符

数据类型2-1变量与常量使用var生命变量 未初始化默认为nullvoid main() {  // 既可以赋值数字也可以字符串  var a;  // 打印出null 由于声明未赋值  print(a);  a = 10;  // 打印出10  print(a);  // 打印出字符串hello dart  a = 'hello dart';  print(a);  // 既可以声明的时候赋值 也可以声明后赋值 打出20  var b = 20;  print(b);  //  final c = 30;  // final只能赋值一次的变量 不能继续赋值了  // c=50;  print(c);  // const声明常量 必须是编译器常亮  const d = 20;  // 常亮也是不能修改的  // d=50;  print(d);}2-2数值型void main() {  // num是数值型的总称 包括浮点型(带小数点)和整形  num a = 10;  a = 12.5;  print(a);  int b = 20;  // double的值不能赋给int  // b=20.5  print(b);  double c = 10.5;  print(b + c);  print(b - c);  print(b * c);  print(b / c);  // 取整 1 20除以10.5取了整就是1  print(b ~/ c);  // 取余 9.5  print(b % c);  // 非数字 定义在double方法中 0.0/0.0=NAN  print(0.0 / 0.0);  // 打印b是否为偶数true  print(b.isEven);  //  打印b是否为奇数false  print(b.isOdd);  int e = -100;  //  abs()方法取绝对值  print(e.abs());  double f = 10.5;  //  四舍五入11  print(f.round());  //  向下取整10  print(f.floor());  //  向上取整11  print(f.ceil());  //  转化为整形10  print(f.toInt());  //  转化为浮点型10.5  print(f.toDouble());}2-3字符串void main() {  //  String str1 = 'hello';  // 三个引号代表打印多行字符串 或者三个双引号  String str2 = '''hello  dart''';  print(str2);  // \n换行  String str3 = 'hello \n dart';  print(str3);  // 字符串前面加个r可以避免字符被转义 打出hello \n dart  String str4 = r'hello \n dart';  print(str4);  String a1 = 'this is my fav lan';  // + this is my fav lannew  print(a1 + 'new');  // *代表打印5次  print(a1 * 5);  // 比较两字符串是否相同  print(str3 == a1);// 取字符串第几位  print(a1[0]);  int a = 1;  int b = 2;// 插值表达式 ${}可以转义为计算a+b的值 a+b=3  print('a+b=${a + b}');// 如果插值表达式直接取变量值 就可以把大括号省略掉  print('a=$a');  // 取字符串长度  print(a1.length);  // 判断字符串是否为空  print(a1.isEmpty);  // 是否包含某个字符串  print(a1.contains('this'));  // 从0开始截取3位  print(a1.substring(0, 3));  // 是否是以a开头的 false  print(a1.startsWith('a'));  //  是否已a结尾  print(a1.endsWith('a'));  //  第一个i对应的下标  print(a1.indexOf('i'));  // 最后一个i对应的下标  print(a1.lastIndexOf('i'));  // 去前后的空格 left right可以单独去  print(a1.trim());  // 大写  print(a1.toUpperCase());  // 以空格进行分隔 返回数组  var a2 = a1.split(' ');  print(a2);  // 替换  print(a1.replaceAll('this', 'that'));}2-4布尔型void main() {  // 声明方法 只有true或者false  bool a = true;  bool b = false;  print('hello'.isEmpty);}2-5列表void main() {  // list元素可以是不同类型的  var list1 = [1, 2, 3, 'dart', true];  print(list1);  // 取第0个元素  print(list1[0]);  // 更改第1个元素  list1[1] = 'hello';  print(list1);  // 内容不可变的list  var list2 = const [1, 2, 3];  // 报错 不能修改常量数组  // list2[0]=5;  // list的创建  var list3 = new List();  // 打印[]  print(list3);  var a = ['heloo', 'dart'];//  长度  print(a.length);//  最后一位插入元素  a.add('new');  print(a);// 在第二个元素插入字符串  a.insert(1, 'java');  print(a);//  在数组中移除元素  a.remove('java');  print(a);//  清空数组//  a.clear();  print(a);//  是否包含某个元素 包含的话会打出元素下标 不包含打出-1  print(a.indexOf('dart'));  print(a.indexOf('dart1'));//  按字母或者数值进行排序 [dart, heloo, new]  a.sort();  print(a);// 从第二个元素开始截取[heloo, new]  print(a.sublist(1));// 把元素逐个打印 传入的是一个方法  a.forEach(print);}2-6Mapvoid main() {  // 每一组元素都有键和值true:'2'不建议这样做  var map1 = {"first": "dart", 1: true, true: '2'};  print(map1);  // 打印key=first的value值   dart  print(map1['first']);  print(map1[true]);  // 修改map值  map1[1] = false;  print(map1);  var map2 = const {1: 'dart', 2: 'java'};  // 不能给不可变得map修改值  // map2[1]='1';  // 初始化  var map3 = new Map();  var a = {'first': 'dart', 'second': 'java', 'third': 'ph'};  // 长度  print(a.length);  print(a.isEmpty);  print(a.isNotEmpty);  //(first, second, third)  print(a.keys);  // (dart, java, ph)  print(a.values);  // 是否包含某个key  print(a.containsKey('first'));// 是否包含某个value  print(a.containsValue('a'));// 移除key=third的那一项  a.remove('third');  print(a);// 传入一个方法 方法用插值表达式 取$key $value 结果:key=first,value=dart key=second,value=java  a.forEach(f);// list转成map 下标作为key 元素作为值  var list = ['1', '2', '3'];  print(list.asMap());}void f(key, value) {  print('key=$key,value=$value');}2-7dynamicvoid main() {  // a是动态类型 所以可以赋予不同的值  var a;  a = 10;  a = 'dart';  // 声明动态类型 new List<dynamic>();创建一个泛型 list中的类型随意  dynamic b = 20;  b = 'java';  var list = new List<dynamic>();  list.add(1);  list.add('hello');  list.add(true);  print(list);}运算符3-1算数运算符void main() {  int a = 10;  int b = 20;  print(a + b);  print(a - b);  print(a * b);  print(a / b);  print(a ~/ b);  print(a % b);  // 先使用a的值进行打印方法 再去给a加1 10  print(a++);  // 先进行+1 再把a的值传入print方法打印 12  print(++a);  // 12 先操作 再减1  print(a--);  // 10  print(--a);}3-2关系运算符void main() {  int a = 5;  int b = 3;  // 判断内容是否相等 不判断类型  print(a == b);  print(a != b);  print(a > b);  print(a < b);  print(a >= b);  print(a <= b);  String a1 = '111';  String b1 = '321';  print(a1 == b1);}3-3逻辑运算符void main() {  bool ist = true;  bool isf = false;  print(!ist);  // &&都为true才为true  print(ist && isf);  // ||一个为真就真  print(ist || isf);  // String a;  // 声明后不赋值不能判断 为null  // print(a.isEmpty);  String a = '';  // true  print(a.isEmpty);  // false  print(!a.isEmpty);}3-4赋值运算符void main() {  int a = 10;  int b = 5;  // b??=10; b没有值会赋值 有值则无效  b ??= 10;  // 5  print(b);  // 12  a += 2;  print(a);  // 7  a -= 5;  print(a);// 相当于a*b=? 35  print(a *= b);// 7  print(a ~/= b);// 2  print(a %= b);// print(a/=b);}3-5条件表达式void main() {  int gender = 0;  // 三目运算符  // String a=gender==0?'male':'female';  String a = gender == 0 ? 'male=$gender' : 'female=$gender';  print(a);  String b;  String c = 'java';// b如果为空把c给b  String d = b ?? c;  print(d);}

July 3, 2020 · 1 min · jiezi