Learning Dart - 类型

Learning Dart - 类型

基本类型

Numbers (int, double)

  • int
    整数值不大于 64 位,值的范围可以是 -2^63到 2^63 - 1,具体取决于平台
var x = 1;
var hex = 0xDEADBEEF;
  • double
    64 位(双精度)浮点数
# 可以将变量声明为 num。如果这样做,变量可以同时具有整数和双精度值。
num x = 1; // x can have both int and double values
x += 2.5;

# 必要时,整数字面量会自动转换为双精度数:
double z = 1; // Equivalent to double z = 1.0.

字符串与数字转换

// 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');

Strings (String)

可以使用单引号或双引号来创建字符串

var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";

可以使用 ${expression} 将表达式的值放入字符串中。如果表达式是一个标识符,则可以跳过 {}。要获取对象对应的字符串,Dart 会调用对象的 toString() 方法。

var s = 'string interpolation';

assert('Dart has $s, which is very handy.' ==
    'Dart has string interpolation, '
        'which is very handy.');
assert('That deserves all caps. '
        '${s.toUpperCase()} is very handy!' ==
    'That deserves all caps. '
        'STRING INTERPOLATION is very handy!');

备注: == 运算符测试两个对象是否等价。如果两个字符串包含相同的代码单元序列,它们就是等价的。

连接字符串:可以使用相邻字符串字面量或 + 运算符来连接字符串

var s1 = 'String '
    'concatenation'
    " works even over line breaks.";
assert(s1 ==
    'String concatenation works even over '
        'line breaks.');

var s2 = 'The + operator ' + 'works, as well.';
assert(s2 == 'The + operator works, as well.');

创建多行字符串使用三单引号或三双引号

var s1 = '''
You can create
multi-line strings like this one.
''';

var s2 = """This is also a
multi-line string.""";

用 r 作为前缀来创建 "原始 "字符串

# 反斜杠 “\” 不会被当作转义字符,而是被当作普通的字符处理
var s = r'In a raw string, not even \n gets special treatment.';

原始字符串文字,是指没有转义字符的字符串,它可以让我们在字符串中不需要对一些特殊字符进行转义,直接使用原始的字符即可

字面字符串是编译时常量,只要任何插值表达式是求值为空或数值、字符串或布尔值的编译时常量即可。

// These work in a const string.
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';

// These do NOT work in a const string.
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];

// 有效
const validConstString = '$aConstNum $aConstBool $aConstString';
// 无效
// const invalidConstString = '$aNum $aBool $aString $aConstList';

Booleans (bool)

只有两个对象具有 bool 类型:布尔字面量 true 和 false,它们都是编译时常量

Dart 的类型安全意味着您不能使用 if (nonbooleanValue) 或 assert (nonbooleanValue) 这样的代码。取而代之的是明确检查值,就像下面这样:

// Check for an empty string.
var fullName = '';
assert(fullName.isEmpty);

// Check for zero.
var hitPoints = 0;
assert(hitPoints <= 0);

// Check for null.
var unicorn = null;
assert(unicorn == null);

// Check for NaN.
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);

Runes (Runes; 经常被 characters API 取代)

如果需要读取或写入单个 Unicode 字符,请使用字符包为 String 定义的字符获取器。返回的 Characters 对象是字符串的字符串簇序列。下面是一个使用字符 API 的示例:

import 'package:characters/characters.dart';

void main() {
  var hi = 'Hi 🇩🇰';
  print(hi);
  print('The end of the string: ${hi.substring(hi.length - 1)}');
  print('The last character: ${hi.characters.last}');
}

输出结果如下:
企业微信20231229-181431@2x.png

Symbols (Symbol)

符号对象代表 Dart 程序中声明的运算符或标识符。您可能永远都不需要使用符号,但对于通过名称来引用标识符的 API 来说,符号是非常宝贵的,因为最小化会改变标识符名称,但不会改变标识符符号。

#radix
#bar

Foo.dart

library foo_lib;   
// libarary name can be a symbol   

class Foo {         
   // class name can be a symbol  
   m1() {        
      // method name can be a symbol 
      print("Inside m1"); 
   } 
   m2() { 
      print("Inside m2"); 
   } 
   m3() { 
      print("Inside m3"); 
   } 
}

以下代码在Symbol类型的帮助下加载Foo.dart库并搜索Foo类。由于需要反射上述库中的元数据,因此这里需要代码导入dart:mirrors库。

import 'dart:core'; 
import 'dart:mirrors'; 
import 'Foo.dart';  

main() { 
   Symbol lib = new Symbol("foo_lib");   
   //library name stored as Symbol 

   Symbol clsToSearch = new Symbol("Foo");  
   // class name stored as Symbol  

   if(checkIf_classAvailableInlibrary(lib, clsToSearch))  
   // searches Foo class in foo_lib library 
      print("class found.."); 
}  

bool checkIf_classAvailableInlibrary(Symbol libraryName, Symbol className) { 
   MirrorSystem mirrorSystem = currentMirrorSystem(); 
   LibraryMirror libMirror = mirrorSystem.findLibrary(libraryName); 

   if (libMirror != null) { 
      print("Found Library"); 
      print("checkng...class details.."); 
      print("No of classes found is : ${libMirror.declarations.length}"); 
      libMirror.declarations.forEach((s, d) => print(s));  

      if (libMirror.declarations.containsKey(className)) return true; 
      return false; 
   } 
}

注意:代码行 - libMirror.declarations.forEach((s, d) => print(s));将在运行时迭代库中的每个声明,并将声明打印为Symbol的类型。

Found Library 
checkng...class details.. 
No of classes found is : 1 
Symbol("Foo") // class name displayed as symbol  
class found.

引用:更多请阅读 https://www.yiibai.com/dart/dart_programming_symbol.html#article-start

Records ((value1, value2))

Record syntax

record 表达式是以逗号分隔的命名或位置字段列表,用括号括起来:

var record = ('first', a: 2, b: true, 'last');

record 类型注释是以逗号分隔的类型列表,用括号括起来。您可以使用记录类型注解来定义返回类型和参数类型。例如,以下 (int, int) 语句就是记录类型注解:

(int, int) swap((int, int) record) {
  var (a, b) = record;
  return (b, a);
}

// Record type annotation in a variable declaration:
(String, int) record;

// Initialize it with a record expression:
record = ('A string', 123);

// Record type annotation in a variable declaration:
({int a, bool b}) record;

// Initialize it with a record expression:
record = (a: 123, b: true);

// 字段名不同类型也不同
({int a, int b}) recordAB = (a: 1, b: 2);
({int x, int y}) recordXY = (x: 3, y: 4);

// Compile error! These records don't have the same type.
// recordAB = recordXY; // no


(int a, int b) recordAB = (1, 2);
(int x, int y) recordXY = (3, 4);

recordAB = recordXY; // OK.

Record fields

record 是不可变的只有 getter

var record = ('first', a: 2, b: true, 'last');

print(record.$1); // Prints 'first'
print(record.a); // Prints 2
print(record.b); // Prints true
print(record.$2); // Prints 'last'

Record types

单个记录类型没有类型声明。记录是根据其字段类型进行结构类型化的。记录的形状(字段集、字段类型及其名称(如有))唯一地决定了记录的类型。

(num, Object) pair = (42, 'a');

var first = pair.$1; // Static type `num`, runtime type `int`.
var second = pair.$2; // Static type `Object`, runtime type `String`.

Record equality

如果两条记录具有相同的形状(字段集),且相应字段的值相同,则这两条记录是相等的。由于已命名字段的顺序不是记录形状的一部分,因此已命名字段的顺序不会影响相等性。

(int x, int y, int z) point = (1, 2, 3);
(int r, int g, int b) color = (1, 2, 3);

print(point == color); // Prints 'true'.
({int x, int y, int z}) point = (x: 1, y: 2, z: 3);
({int r, int g, int b}) color = (r: 1, g: 2, b: 3);

print(point == color); // Prints 'false'. Lint: Equals on unrelated types.

Multiple returns

记录允许函数返回捆绑在一起的多个值。要从返回中检索记录值,请使用模式匹配将值解构为局部变量。

Explain
// Returns multiple values in a record:
(String, int) userInfo(Map<String, dynamic> json) {
  return (json['name'] as String, json['age'] as int);
}

final json = <String, dynamic>{
  'name': 'Dash',
  'age': 10,
  'color': 'blue',
};

// Destructures using a record pattern:
var (name, age) = userInfo(json);

/* Equivalent to:
  var info = userInfo(json);
  var name = info.$1;
  var age  = info.$2;
*/

Collections

Dart 内置支持 list、set 和 map 集合

Lists (List, also known as arrays)

var list = [1, 2, 3];

var list = [
  'Car',
  'Boat',
  'Plane',
];

To create a list that’s a compile-time constant, add const before the list literal:

var constantList = const [1, 2, 3];
// constantList[1] = 1; // This line will cause an error.

Sets (Set)

Dart 中的集合是由唯一项组成的无序集合。Dart 通过集合文字和集合类型提供对集合的支持。

var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};

要创建空集,可在类型参数前使用 {},或将 {} 赋值给 Set 类型的变量:

var names = <String>{};
// Set<String> names = {}; // This works, too.
// var names = {}; // Creates a map, not a set.

使用 add() 或 addAll() 方法将项目添加到现有集合中:

var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);

要创建一个编译时常量的集合,请在集合字面之前添加 const:

final constantSet = const {
  'fluorine',
  'chlorine',
  'bromine',
  'iodine',
  'astatine',
};
// constantSet.add('helium'); // This line will cause an error.

Maps (Map)

Dart 对映射的支持由映射字面意义和映射类型提供。

var gifts = {
  // Key:    Value
  'first': 'partridge',
  'second': 'turtledoves',
  'fifth': 'golden rings'
};

var nobleGases = {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};

// 使用下标赋值操作符([]=)向现有映射添加新的键值对:
var gifts = Map<String, String>();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';

var nobleGases = Map<int, String>();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';

var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // Add a key-value pair

// 下标取值
var gifts = {'first': 'partridge'};
assert(gifts['first'] == 'partridge'); // true

// 不存在返回 null
var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null); // true

// length
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);

// 要创建一个编译时常量的映射,请在映射字面之前添加 const:
final constantMap = const {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};

// constantMap[2] = 'Helium'; // This line will cause an error.

扩展运算符

Dart 支持 list、map 和 set 字面中的展开操作符(...)和空感知展开操作符(...?)展开操作符为在集合中插入多个值提供了一种简洁的方法。

var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);

如果扩展运算符右侧的表达式可能为空,则可以使用空感知扩展运算符(...?)

var list2 = [0, ...?list];
assert(list2.length == 1);

Dart 提供了用于 list、map 和 set 字面的集合 if 和集合 for。您可以使用这些操作符通过条件(if)和重复(for)来构建集合。

var nav = ['Home', 'Furniture', 'Plants', if (promoActive) 'Outlet'];
var nav = ['Home', 'Furniture', 'Plants', if (login case 'Manager') 'Inventory'];

var listOfInts = [1, 2, 3];
var listOfStrings = ['#0', for (var i in listOfInts) '#$i']; // ['#0','#1','#2','#3']
assert(listOfStrings[1] == '#1'); 

泛型

// Object
abstract class ObjectCache {
  Object getByKey(String key);
  void setByKey(String key, Object value);
}
// String
abstract class StringCache {
  String getByKey(String key);
  void setByKey(String key, String value);
}
// T
abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}

// 方法和函数也允许使用类型参数:
T first<T>(List<T> ts) {
  // Do some initial work or error checking, then...
  T tmp = ts[0];
  // Do some additional checking or processing...
  return tmp;
}

类型定义

typedef IntList = List<int>;
IntList il = [1, 2, 3];

// 类型别名可以有类型参数:
typedef ListMapper<X> = Map<X, List<X>>;
Map<String, List<String>> m1 = {}; // Verbose.
ListMapper<String> m2 = {}; // Same thing but shorter and clearer.


typedef Compare<T> = int Function(T a, T b);
int sort(int a, int b) => a - b;
void main() {
  assert(sort is Compare<int>); // True!
}

类型系统

https://dart.cn/language/type-system

Read more

Flutter入门指南

Flutter入门指南

Flutter 是一个由 Google 开发的开源移动应用开发框架。它允许开发者使用一套代码同时构建 iOS 和 Android 应用,并且提供了丰富的 UI 组件和高效的开发工具,使得开发者能够快速构建出高性能的跨平台应用。 一、Flutter 的实现原理 Flutter 的核心在于其自带的高性能渲染引擎 Skia。不同于其他框架依赖于原生的 UI 组件,Flutter 直接通过 Skia 渲染引擎将所有组件绘制到屏幕上。这种方式保证了跨平台应用在 iOS 和 Android 上的表现完全一致。 1.1 结构概览 Flutter 的架构分为三层: 1. Framework(框架层): 这部分主要由 Dart 编写,提供了 Flutter 的各种 UI 组件(Widget)、手势检测、渲染层以及动画等。

By Lewis