Dart学习笔记
参考资料
Dart最大特点是核心模块内置了html/js解析器,无论是html5还是canvas都能应付自如,并且对js有很好的性能支持。
import 'dart:html';
变量和常量
可变变量var
尽管Dart是强类型的,但是类型注释是可选的,因为Dart可以推断类型。用var关键词搞定,当你不想显示地声明一个变量的类型,那么您可以使用特殊类型dynamic
当你使用 var定义 name变量时,这个类型便会约束在 String类型,如果赋值其他类型便会出错。
如果你不想约束一个变量的类型,那么可以使用 Object类型定义或者dynamic关键字定义。
不可变量final
用final修饰的变量,必须在定义时将其初始化,其值在初始化后不可改变,但是用final标记的变量可以在运行时确定。
不可变量const
用const也可以定义常量。
它们的区别在于,const比final更加严格。final只是要求变量在初始化后值不变,但通过final,我们无法在编译时(运行之前)知道这个变量的值;而const所修饰的是编译时常量,我们在编译时就已经知道了它的值,显然,它的值也是不可改变的。
在 Dart中这一点很叫人放心。
数据类型
Number 类型
Number 类型分为 int 和 double
int 的范围是 -2^53 ~ 2^53 double 是符合 IEEE 754标准的 64位双精度的浮点数。
除了常见的运算符外,你还能使用内置的 abs()、ceil()、floor()等方法。
如果还有其他运算方法的需求,你可以引入 dart:math库来尝试用一下。
一个例子
void main() { // 字符串转 int var one = int.parse('1'); // 字符串转浮点 var onePointOne = double.parse('1.1'); // int 转字符串 String oneAsString = 1.toString(); // double 转字符串,保留几位小数 String piAsString = 3.14159.toStringAsFixed(2); }
String 类型
可以使用单引号或双引号创建字符串,也可以用缓存区创建
var Res = StringBuffer(); Res..write();
字符串连接
字符串连接,使用 + 操作符
// 字符串连接可以使用 + 号 var str4 = str1 +'-'+ str2;
多行字符串
// 多行字符串,如""" 或 ''' var str5 = ''' 多行字符串的定义 简单吧 ''';
raw 字符串
使用 r 来定义
// 使用 r 修饰,表明是 raw 类型的字符串 var str6 = r"In a raw string, even \n s";
列表List
var list = [1, 2, 3];
和其他语言一样,数组索引也从 0开始。同样地,你还可以像 JavaScript那样迭代数组:
list.forEach((item) { print('index: ${list.indexOf(item)}, item:${item}'); });
字典Map
var gifts = { // Key: Value 'first': 'partridge', 'second': 'turtledoves', 'fifth': 'golden rings' }; var gifts = Map(); gifts['first'] = 'partridge'; gifts['second'] = 'turtledoves'; gifts['fifth'] = 'golden rings';
自定义下标字典
var nobleGases = { 2: 'helium', 10: 'neon', 18: 'argon', }; var nobleGases = Map(); nobleGases[2] = 'helium'; nobleGases[10] = 'neon'; nobleGases[18] = 'argon';
流程控制
if..else if..else
if (isRaining()) { you.bringRainCoat(); } else if (isSnowing()) { you.wearJacket(); } else { car.putTopDown(); }
for loops
var message = new 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)); } callbacks.forEach((c) => c());
// for - in var collection = [0, 1, 2]; for (var x in collection) { print(x); }
while & do-while loops
// while 循环在执行循环之前先判断条件是否满足 while (!isDone()) { doSomething(); }
// do-while 循环是先执行循环代码再判断条件 do { printLine(); } while (!atEndOfPage());
switch case
Dart 中的 Switch 语句使用 == 比较 integer、string、或者编译时常量。
var command = 'OPEN'; switch (command) { case 'CLOSED': executeClosed(); break; case 'PENDING': case 'APPROVED': case 'DENIED': executeDenied(); break; case 'OPEN': executeOpen(); break; default: executeUnknown(); }
break & continue
// 使用break来终止当前循环 while (true) { if (shutDownRequested()) break; processIncomingRequests(); }
使用 continue 来跳过当前,开始下一次循环: for (int i = 0; i < candidates.length; i++) { var candidate = candidates[i]; if (candidate.yearsExperience < 5) { continue; } candidate.interview(); }
assert
如果条件表达式结果不满足需要,则可以使用 assert 语句俩打断代码的执行。适用于单元测试。
// Make sure the variable has a non-null value. assert(text != null); // Make sure the value is less than 100. assert(number < 100); // Make sure this is an https URL. assert(urlString.startsWith('https'));
函数(过程)
可选命名参数
把一组函数的参数放在{}之内可以把它们标记为可选位置参数:
在调用函数的时候,你可以通过paraName: Value的形式使用有命名的参数。比如:
enableFlags(bold: true, hidden: false);
int add2(x,{y=2,z=3}){ print("x=$x y=$y z=$z"); return(x+y+z); } void main(){ print(add2(1,z:3,y:4)); }
可选位置参数
把一组函数的参数放在[]之内可以把它们标记为可选位置参数:
int add(x,[y=2,z=3]){ print("x=$x y=$y z=$z"); return(x+y+z); } void main(){ print(add(1)); print(add(1,3,4)); }
void main() { 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("geminis say: ", "hello world")); print(say("geminis say: ", "hello world", "iphone6")); }
作为对象的函数
你可以把一个函数当做参数传给另一个函数(函数代参,或称高阶递归)。比如:
printElement(element) { print(element); } var list = [1, 2, 3]; // 将 printElement 作为参数传递给其他函数 list.forEach(printElement);
语法作用域
Dart 是语法作用域型的语言,这意味着变量的范围是静态确定的。你可以“层层跟踪大括号”来看一下变量是否存在于这个区域中。
下面是一份关于嵌套的带参函数在不同的作用域等级上的示例:
var topLevel = true; main() { var indideMain = true; myFunction() { var insideFunction = true; nestedFunction() { var insideNestedFunction = true; assert(topLevel); assert(insideMain); assert(insideFunction); assert(insideNestedFunction); } } }
请留意nestedFunction()是怎样使用不同作用域上的变量的,最好从最内层开始一直分析到最外层。
闭包函数
闭包指的是一个函数可以访问其语法作用域内的变量,即使这个函数是在变量本身的作用域之外被调用的。
函数内部会包含在临近作用域内所定义的变量。在下一个示例中,makeAdder()捕获了变量addBy。不管返回的函数在哪里被调用,它都可以使用addBy。
/// 返回一个把 addBy 作为参数的函数 Function makeAdder(num addBy) { return (num i) => addBy + 1; } main() { // 创建一个加2的函数 var add2 = makeAdder(2); // 创建一个加4的函数 var add4 = makeAdder(4); assert(add2(3) == 5); assert(add4(3) == 7); }
异常处理
你的Dart代码可以抛出异常和捕获异常。异常就是出现预期之外的结果的错误。如果没有捕获异常, isolate 将会使异常挂起,往往会导致 isolate 和程序终止。
Dart中所有异常都是不需检测的异常。方法并不会声明它将抛出哪些异常,而且你不需要去捕捉任何异常。
Dart 除了提供 异常、错误 类型以外还提供了众多预定义的子类型。当然,你可以定义你自己的异常类型。毕竟,Dart程序可以将任何非空对象作为异常抛出,不只局限与异常和错误对象。
throw抛出异常
catch捕获异常
finally安全运行
try { breedMoreLlamas(); } on OutOfLlamasException { // 一个具体异常 buyMoreLlamas(); } on Exception catch (e) { // 任意一个异常 print('Unknown exception: $e'); } catch (e) { // 非具体类型 print('Something really unknown: $e'); } finally { cleanLlamaStalls(); // 然后清理 }
类和泛型
简化构造
class Point { num x; num y; Point(this.x, this.y); } var p = new Point(1, 2); print([p.x, p.y]);
调用系统命令
多线程和线程池
库管理
创建自己的库
library loglib; debug(msg) => print("DEBUG: $msg"); warn(msg) => print("WARN: $msg"); info(msg) => print("INFO: $msg"); class Logger { bool _isEnabled; bool get isEnabled => _isEnabled; void set isEnabled(value) => _isEnabled = value; log(msg) => print("LOG: $msg");
引入自定义库
import 'dart:html'; import './mylog.dart'; //import './mylog.dart' as logger; // 类似C语言的风格的主函数和注释, /* 是不是 很亲切 的感觉 */ main() { querySelector('#status').text = 'Hello world, this is dart!'; var title = new Element.html("<h1>清单列表</h1>"); // 可以直接是 html原生语法 document.body.children.add(title); InputElement itemInput = new Element.tag( "input"); // 也可以引用dart的tag对象,如InputElement,ButtonElement,DivElement itemInput.id = "txt-item"; itemInput.placeholder = "Enter an item"; // 默认灰色提示 document.body.children.add(itemInput); ButtonElement addButton = new ButtonElement(); // 这也是一种初始方式 addButton.text = "提交"; document.body.children.add(addButton); DivElement itemContainer = new DivElement(); document.body.children.add(itemContainer); /* * 监听事件 */ var number = 0; // 初始化物品数量 add_items() { var itemValue = itemInput.value; // 获取input内容 info(itemValue + itemValue.toString().trim().length.toString()); // 打开浏览器开发者控制台查看 if (itemValue.toString().trim().length > 0) { var listElement = new Element.html("<div class='item'>${itemValue}<div>"); itemContainer.children.add(listElement); // 向itemContainer里填充数据 number++; querySelector('#status').text = number.toString(); } itemInput.value = ""; // 清空input输入框 } var evt_additems = (event) { add_items(); }; addButton.onClick.listen(evt_additems); // 添加监听一 itemInput.onKeyPress.listen((event) { // 添加监听二 if (event.keyCode == 13) { // 按Enter回车 add_items(); } }); }
打包分享库
通过pub这个内置工具来打包发布有用的库函数,先定义pubspec.yaml文件
name: loglib version: 1.2.3 description: > Provides a simple logging framework to log to the console author: You <you@your.email.com> homepage: http://your.website.com/loglib dependencies: args: '^0.13.2' environment: sdk: '>=1.19.0 <3.0.0' flutter: ^0.1.2 hosted_library: versioned_library: '1.2.3' unittest: any my_security_library: hosted: url: http://your.internal.server.com version: '>=1.0.0 <2.0.0' git: url: git://github.com/my/open_source_library.git
pub publish --dry-run
先来个直观的例子
创建只包含一个元素的html页面
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Dart:HTML == Future</title> </head> <body> <div id="status"></div> <!-- 只包含一个div元素 --> <script async type="text/javascript" src="packages/browser/dart.js"></script> <script async type="application/dart" src="demo.dart"></script> <!-- 这是一段类似js的dart程序 --> </body> </html>
新建一个demo.dart脚本
import 'dart:html'; // 类似C语言的风格的主函数和注释, /* 是不是 很亲切 的感觉 */ main(){ querySelector('#status').text = 'Hello world, this is dart!'; }
在dart中新增html元素很简单
import 'dart:html'; // 类似C语言的风格的主函数和注释, /* 是不是 很亲切 的感觉 */ main(){ querySelector('#status').text = 'Hello world, this is dart!'; var title = new Element.html("<h1>清单列表</h1>"); // 可以直接是 html原生语法 document.body.children.add(title); InputElement itemInput = new Element.tag("input"); // 也可以引用dart的tag对象,如InputElement,ButtonElement,DivElement itemInput.id = "txt-item"; itemInput.placeholder = "Enter an item"; // 默认灰色提示 document.body.children.add(itemInput); ButtonElement addButton = new Element.tag("button"); addButton.text = "提交"; document.body.children.add(addButton); DivElement itemContainer = new Element.tag("div"); document.body.children.add(itemContainer); }
增加事件监听的复杂例子
import 'dart:html'; // 类似C语言的风格的主函数和注释, /* 是不是 很亲切 的感觉 */ main() { querySelector('#status').text = 'Hello world, this is dart!'; var title = new Element.html("<h1>清单列表</h1>"); // 可以直接是 html原生语法 document.body.children.add(title); InputElement itemInput = new Element.tag("input"); // 也可以引用dart的tag对象,如InputElement,ButtonElement,DivElement itemInput.id = "txt-item"; itemInput.placeholder = "Enter an item"; // 默认灰色提示 document.body.children.add(itemInput); ButtonElement addButton = new ButtonElement(); // 这也是一种初始方式 addButton.text = "提交"; document.body.children.add(addButton); DivElement itemContainer = new DivElement(); document.body.children.add(itemContainer); var evt_additems = (event) { var itemValue = itemInput.value; // 获取input内容 var listElement = new Element.html("<div class='item'>${itemValue}<div>"); itemContainer.children.add(listElement); // 向itemContainer里填充数据 itemInput.value = ""; // 清空input输入框 }; addButton.onClick.listen(evt_additems); // 事件监听是重点:onClick,onDrag,onMouseUp/Over/Down/Out...,onKeyUp/Down/Press.. }
dart处理后修改html元素内容
import 'dart:html'; // 类似C语言的风格的主函数和注释, /* 是不是 很亲切 的感觉 */ main() { querySelector('#status').text = 'Hello world, this is dart!'; var title = new Element.html("<h1>清单列表</h1>"); // 可以直接是 html原生语法 document.body.children.add(title); InputElement itemInput = new Element.tag( "input"); // 也可以引用dart的tag对象,如InputElement,ButtonElement,DivElement itemInput.id = "txt-item"; itemInput.placeholder = "Enter an item"; // 默认灰色提示 document.body.children.add(itemInput); ButtonElement addButton = new ButtonElement(); // 这也是一种初始方式 addButton.text = "提交"; document.body.children.add(addButton); DivElement itemContainer = new DivElement(); document.body.children.add(itemContainer); /* * 监听事件 */ var number = 0; // 初始化物品数量 add_items() { var itemValue = itemInput.value; // 获取input内容 var listElement = new Element.html("<div class='item'>${itemValue}<div>"); itemContainer.children.add(listElement); // 向itemContainer里填充数据 itemInput.value = ""; // 清空input输入框 number++; querySelector('#status').text = number.toString(); } var evt_additems = (event) { add_items(); }; addButton.onClick.listen(evt_additems); // 添加监听一 itemInput.onKeyPress.listen((event) { // 添加监听二 if (event.keyCode == 13) { // 按Enter回车 add_items(); } }); }
一个简单的黄金爬虫脚本
这个脚本是用于获取黄金价格和涨幅比例
创建目录
mkdir getGold && cd getGold
使用 stagehand 来生成终端应用
pub global activate stagehand # If it's not installed
stagehand console-full
添加组件到 pubspec.yaml
dependencies:
html: ^0.13.3+3
http: ^0.12.0
运行安装相关依赖
pub get
编写代码 /lib/getGold.dart
import 'package:http/http.dart'; import 'package:html/parser.dart'; import 'package:html/dom.dart'; Future initiate(BaseClient client) async { // Make API call to Hackernews homepage Response response = await client.get('http://fund.eastmoney.com/000217.html'); if (response.statusCode != 200) return response.body; // Use html parser var document = parse(response.body); var time = document.querySelectorAll('#gz_gztime'); var jinzhi = document.querySelectorAll('#gz_gsz'); var zhangfu = document.querySelectorAll('#gz_gszzl'); var res = StringBuffer(); jinzhi.forEach((v) => res..write(v.text + " ")); zhangfu.forEach((v) => res..write(v.text + " ")); time.forEach((v) => res..write(v.text + " ")); return res; }
运行启动脚本 /bin/main.dart
mport 'package:getGold/getGold.dart' as getGold; import 'package:http/http.dart'; Future main() async { print(await getGold.initiate(Client())); }
