Dart语言学习总结

因要学习flutter平台,平台语言使用Dart,看了一下官方的demo:

https://github.com/flutter/flutter

看起来有点吃力,还是学习Dart语言也有利于以后开发,学习地址

https://www.dartlang.org/guides/language/language-tour

https://www.dartlang.org/guides/libraries/library-tour

总结如下:

1.Dart简介

强类型语言

一个单线程的语言

类型注释是可选的,Dart可以推断类型。

Dart支持泛型类型

程序都必须具有顶级main()功能,该功能用作应用程序的入口点

接口可以有函数

类和接口是统一的,都是接口

2.关键字

abstract 2

dynamic 2

implements 2

show 1

as 2

else

import 2

static 2

assert

enum

in

super

async 1

export 2

interface 2

switch

await 3

external 2

is

sync 1

break

extends

library 2

this

case

factory 2

mixin 2

throw

catch

false

new

true

class

final

null

try

const

finally

on 1

typedef 2

continue

for

operator 2

var

covariant 2

Function 2

part 2

void

default

get 2

rethrow

while

deferred 2

hide 1

return

with

do

if

set 2

yield 3

  • 带有上标1单词是上下文关键字,仅在特定位置具有含义。他们到处都是有效的标识符。
  • 带有上标2单词是内置标识符。为了简化将JavaScript代码移植到Dart的任务,这些关键字在大多数地方都是有效的标识符,但它们不能用作类或类型名称,也不能用作导入前缀。
  • 带有上标3的单词是与Dart 1.0发布后添加的异步支持相关的更新,有限的保留字。

3.变量与常量

3.1变量

var name = ‘Bob’ ; // 官方建议使用var

dynamic name = ‘Bob’ ;

String name = ‘Bob’ ;

未初始化的变量的初始值为null

不具备关键字publicprotectedprivate。如果标识符以下划线(_)开头,则表示是私有的。 

3.2常量

final name = ‘Bob’ ;//

const name = ‘Bob’ ;//

const在类级别,要加static const

const构造两个相同的编译时常量会产生同一个的实例

var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);

assert(identical(a, b)); // They are the same instance!

注:使用static关键字实现类范围的变量和方法( 对于常用或广泛使用的实用程序和功能,考虑使用顶级函数而不是静态方法)。

区别一:final 要求变量只能初始化一次,并不要求赋的值一定是编译时常量,可以是常量也可以不是。而 const 要求在声明时初始化,并且赋值必需为编译时常量。

编译时常量:字面量(如数字、bool、字符串、List的字面量形式)、其它常量 或者 常量的算术运算,也可以是这些的组合形式(递归要求),简单地说常量就是可以在编译时确定的值。

区别二:final 是惰性初始化,即在运行时第一次使用前才初始化。而 const 是在编译时就确定值了。

区别三:const 可以修饰变量,也可以修饰值(value)。而 final 只用来修饰变量。

4.内置类型

4.1 数字

int: 整数值不大于64位,具体取决于平台。在Dart VM上,值可以是-2 63到2 63 – 1.编译为JavaScript的Dart使用 从-2 53到2 53 – 1的值。

double :64位(双精度)浮点数,由IEEE 754标准规定。

// String -> int
var one = int.parse(‘1’);
assert(one == 1);

// String -> double
var onePointOne = double.parse(‘1.1’);
assert(onePointOne == 1.1);

// int -> String
String oneAsString = 1.toString();
assert(oneAsString == ‘1’);

// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == ‘3.14’);

4.2 Strings(字符串)

Dart字符串是一系列UTF-16代码单元。您可以使用单引号或双引号来创建字符串。

var s1 = ‘Single quotes work well for‘ + ” string literals.”;
var s2 = “$s1+case: ${s.toUpperCase()};

可以想到”转义”只有’和”,使用三重引号进行“转义”:

var s1 = ”’
You can create”’

“””multi-line strings like this one.
“””

4.3 Booleans

使用bool定义: bool b = true;

4.4数组

在Dart中的数组,其值可以是不同类型

var list = [“aa”,”dd”,3,newText(“test”)];

list.forEach((item) => print(‘I drink $item));

4.5 Maps

 key或values要同一个类型(key可以是对象)

    var gifts = {‘first’: ‘partridge’};

    gifts[‘fourth’] = ‘calling birds’; // Add a key-value pair

    gifts[“2”] = “222”;

    print(gifts[“2”]); //打印

   putIfAbsent()当且仅当键中的键尚不存在时,如果要为键指定值,请使用此方法

,您必须提供一个返回值的函数:

var teamAssignments = {};
teamAssignments.putIfAbsent(
   
‘Catcher’, () => pickToughestKid());
assert(teamAssignments[‘Catcher’] != null);

map循环:

gifts.forEach((k, v) {
  print(
‘I want to visit $k and swim at $v’);
 
// I want to visit first and swim at partridge
}); 

4.6 Runes

在Dart中,Runes是UTF-32位字符串。

Unicode为世界上所有书写系统中使用的每个字母,数字和符号定义唯一的数值。由于Dart字符串是一系列UTF-16位,因此在字符串中表示32位Unicode值需要特殊语法。

表达Unicode代码点的常用方法是 \uXXXX,其中XXXX是4位十六进制值。例如,心脏角色()是\u2665。要指定多于或少于4个十六进制数字,请将值放在大括号中。例如,笑表情符号(😆)是\u{1f600}

字符串 类有几个属性,你可以用它来提取符文信息。在codeUnitAtcodeUnit属性返回16位编码单元。

以下示例说明了符文,16位代码单元和32位代码点之间的关系。

    var clapping = ‘\u{1f44f}’;

    print(clapping);

    print(clapping.codeUnits);  // [55357, 56399]

    print(clapping.runes.toList());  //[128079]

    Runes input = new Runes(‘\u2665  \u{1f605}  \u{1f60e}  \u{1f47b}  \u{1f596}  \u{1f44d}’);

    print(new String.fromCharCodes(input)); // ♥  😅  😎  👻  🖖  👍

4.7 URL

1.进行编码和解码的字符除了那些在URI特殊含义(例如/:&#),使用encodeFull()decodeFull()方法:

var uri = http://example.org/api?foo=some message’;var encoded = Uri.encodeFull(uri);
assert(encoded ==
   
http://example.org/api?foo=some%20message);

2.编码和解码所有这一切都在一个URI特殊的含义,使用encodeComponent()decodeComponent()方法:

var uri = http://example.org/api?foo=some message’;

var encoded = Uri.encodeComponent(uri);
assert(encoded ==
   
‘http%3A%2F%2Fexample.org%2Fapi%3Ffoo%3Dsome%20message’);

3.组装与拆分:

var uri = Uri(
    scheme:
‘http’,
    host:
‘example.org’,
    path:
‘/foo/bar’,
    fragment:
‘frag’);

// var uri = Uri.parse(‘http://example.org:8080/foo/bar#frag’);

assert(uri.scheme == ‘http’);
assert(uri.host == ‘example.org’);
assert(uri.path == ‘/foo/bar’);
assert(uri.fragment == ‘frag’);
assert(uri.origin == http://example.org:8080);

4.8 日期和时间

// Get the current date and time.
var now = DateTime.now();

// Create a new DateTime with the local time zone.
var y2k = DateTime(2000); // January 1, 2000

// Specify the month and day.
y2k = DateTime(2000, 1, 2); // January 2, 2000

// Specify the date as a UTC time.
y2k = DateTime.utc(2000); // 1/1/2000, UTC

// Specify a date and time in ms since the Unix epoch.
y2k = DateTime.fromMillisecondsSinceEpoch(946684800000,
    isUtc:
true);

// millisecondsSinceEpoch日期的属性返回自“Unix epoch” – 1970年1月1日UTC以来的毫秒数:

// Parse an ISO 8601 date.
y2k = DateTime.parse(‘2000-01-01T00:00:00Z’);

 

使用Duration类计算两个日期之间的差异并向前或向后移动日期(要使用UTC日期):

var y2k = DateTime.utc(2000);

// Add one year.
var y2001 = y2k.add(Duration(days: 366));
assert(y2001.year == 2001);

// Subtract 30 days.
var december2000 = y2001.subtract(Duration(days: 30));
assert(december2000.year == 2000);
assert(december2000.month == 12);

// Calculate the difference between two dates.
// Returns a Duration object.
var duration = y2001.difference(y2k);
assert(duration.inDays == 366); // y2k was a leap year.

5.函数

所有函数都返回一个值。如果未指定返回值,则将语句return null;隐式附加到函数体。

实现函数的示例:

bool isNoble (int atomicNumber ){

return _nobleGases [ atomicNumber ] != null ; }

虽然Effective Dart建议 为公共API键入注释,但如果省略类型,该函数仍然有效:

isNoble (atomicNumber ){ return _nobleGases [

atomicNumber ] != null ; }

 

对于只包含一个表达式的函数,可以使用简写语法:

bool isNoble (int atomicNumber )=>

_nobleGases [ atomicNumber ] != null ;  

该语法是一个速记 。有时将表示法称为箭头语法。=> expr{ return expr; }=>

注意: 只有表达式 – 不是语句 – 可以出现在箭头(=>)和分号(;)之间。例如,您不能在其中放置if语句,但可以使用条件表达式

定义必传参<child>参数默认值<number>、选传参<device>

bool isNoble (@required Widget child, int number = 1, [String device]){

return _nobleGases [ atomicNumber ] != null ; }

 

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

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

var list = [1, 2, 3];

// Pass printElement as a parameter.
list.forEach(printElement); 

匿名函数

  var list = [‘apples’, ‘bananas’, ‘oranges’];

  list.forEach((item) {

    print(‘${list.indexOf(item)}: $item’);

  });

再如:

button.onClick.listen((e) => window.alert(‘Confirmed!’));

 

嵌套函数:

void myFunction() {
   
var insideFunction = true;

void nestedFunction() {
     
var insideNestedFunction = true;
     
assert(insideFunction);
     
assert(insideNestedFunction);
}

}

变量函数:

在Dart中,可以把一个函数当一个变量:

/// Returns a function that adds [addBy] to the
/// function’s argument.
Function makeAdder(num addBy) {
 
return (num i) => addBy + i; //返回一个匿名函数
}

void main() {
 
// Create a function that adds 2.
  var add2 = makeAdder(2);

// Create a function that adds 4.
  var add4 = makeAdder(4);

  var add5 = makeAdder(4);

    assert(add2(3) == 5);
 
assert(add4(3) == 7);

 

    // 函数变量一样可以比较

    print(add4 == add5); // false 匿名函数都是新的

    var adder = makeAdder;

    print(adder== makeAdder); // true 函数同一个

 

// 函数变量可以理解为函数别名

    print(adder(3)(7)); // 10

}

6.运算符

类型转换运算符:

操作者

含义

as

类型转换

is

如果对象具有指定的类型,则为True

is!

如果对象具有指定的类型,则返回false

()

表示函数调用

[]

引用列表中指定索引处的值

.

指表达式的属性; 示例:从表达式中foo.bar选择属性barfoo

?.

比如.最左边的操作数可以为null; 示例:从表达式中foo?.bar选择属性barfoo非null(值为foo.bar),为null(值为null)

.runtimeType

获取对象的类型,可以使用Object的runtimeType属性,该属性返回一个Type对象,比如.print (‘a的类型是$ {a.runtimeType}’ );

obj is T如果obj实现指定的接口,则结果为true T。例如,obj is Object总是如此。 

级联符号(..)

var sb = StringBuffer();
sb.write(
‘foo’)
  ..write(
‘bar’);

严格来说,级联的“双点”符号不是运算符。它只是Dart语法的一部分。

控制流程语句

您可以使用以下任一方法控制Dart代码的流程:

  • if 和 else
  • for 循环
  • whiledo– while循环
  • break 和 continue
  • switch 和 case
  • Assert(布尔条件为false,则使用语句来中断正常执行,注Flutter在调试模式下启用断言)

您也可以使用try-catch和影响控制流throw

try {
 
// ···
} on Exception catch (e) {
  print(
‘Exception details:\n $e’);
}
catch (e, s) { // 指定一个或两个参数catch()。第一个是抛出的异常,第二个是堆栈跟踪
  print(‘Exception details:\n $e’);
  print(
‘Stack trace:\n $s’);
}
finally {
  print(
finally);

}

其他运算符与java、C++、swift、OC语言一致,不一一列示了

7.类

class Musician extends Performer with Musical

with关键字后跟一个或多个mixin名称(类),声明没有构造函数,并且没有调用super

7.1构造函数

1.如果您未声明构造函数,则会为您提供默认构造函数。默认构造函数没有参数,并在超类中调用无参数构造函数。

2.子类不从其父类继承构造函数。声明没有构造函数的子类只有默认(无参数,无名称)构造函数。

3.超类没有未命名的无参数构造函数,则必须手动调用超类中的一个构造函数。在冒号(:)之后,在构造函数体(如果有)之前指定超类构造函数。

class Point {
 
num x, y;

Point(num x, num y) {
   
// There’s a better way to do this, stay tuned.
    this.x = x;
   
this.y = y;
  }
}

同样:

class Point {
 
num x, y;

// Syntactic sugar for setting x and y
  // before the constructor body runs.
  Point(this.x, this.y);

 

  // Named constructor
  Point.origin() { // 默认构制方法时调用
    x = 0;
    y =
0;
  }

7.2重定向构造函数

有时构造函数的唯一目的是重定向到同一个类中的另一个构造函数。重定向构造函数的主体是空的,构造函数调用出现在冒号(:)之后。

class Point {
 
num x, y;

// The main constructor for this class.
  Point(this.x, this.y);

// Delegates to the main constructor.
  Point.alongXAxis(num x) : this(x, 0);
}

7.3常量构造函数

如果您的类生成永远不会更改的对象,则可以使这些对象成为编译时常量。为此,请定义const构造函数并确保所有实例变量都是final。(应该是单例的意思)

class ImmutablePoint {
 
static final ImmutablePoint origin =
     
const ImmutablePoint(0, 0);

    final num x, y;

    const ImmutablePoint(this.x, this.y);
}

7.4 工厂构造函数

factory在实现不总是创建其类的新实例的构造函数时使用关键字。例如,工厂构造函数可能从缓存中返回实例,或者它可能返回子类型的实例。

class Logger {
 
final String name;
 
bool mute = false;

// _cache is library-private, thanks to
  // the _ in front of its name.
  static final Map<String, Logger> _cache =
      <
String, Logger>{};

factory Logger(String name) { // 工厂构造函数无权访问this
    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) {
   
if (!mute) print(msg);
  }
}

7.5重载运算符函数

您可以覆盖下表中显示的运算符。例如,如果定义Vector类,则可以定义+添加两个向量的方法。

<

+

|

[]

>

/

^

[]=

<=

~/

&

~

>=

*

<<

==

%

>>

 

注意:您可能已经注意到,这!=不是一个可覆盖的运算符。表达e1 != e2只是语法糖!(e1 == e2)

例:

class Vector {
 
final int x, y;

   Vector(this.x, this.y);

    Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
 
Vector operator -(Vector v) => Vector(x – v.x, y – v.y);

// Operator == and hashCode not shown. For details, see note below.
  // ···
}

void main() {
 
final v = Vector(2, 3);
 
final w = Vector(2, 2);

  assert(v + w == Vector(4, 5));
 
assert(v – w == Vector(0, 1));
}

7.6 哈希码 (hashCode)

class Person {
 
final String firstName, lastName;

Person(this.firstName, this.lastName);

// Override hashCode using strategy from Effective Java,
  // Chapter 11.
  @override
 
int get hashCode {
   
int result = 17;
    result =
37 * result + firstName.hashCode;
    result =
37 * result + lastName.hashCode;
   
return result;
  }

// You should generally implement operator == if you
  // override hashCode.
  @override
 
bool operator ==(dynamic other) {
   
if (other is! Person) return false;
   
Person person = other;
   
return (person.firstName == firstName &&
        person.lastName == lastName);
  }
}