Stories

Detail Return Return

Flutter/Dart第08天:Dart類型(內置類型、記錄、集合、泛型和類型別名) - Stories Detail

Dart內置類型(共10類)

Dart官網文檔:https://dart.dev/language/built-in-types

Dart內置類型即Dart SDK自帶的類型,我們編程過程中可直接使用的類型,主要分為10類:

  1. 數值類型:包括int類、double類等。
  2. 字符串類型:即String類。
  3. 布爾類型:即bool類。
  4. 記錄類型:即Record類,Dart 3中開始支持(最新版本的Java 21也支持)。
  5. 列表類型:即List類,同時也是數組。
  6. Set類型:即Set類。
  7. 映射類型:即Map類。
  8. 字符類型:與字符相關處理。
  9. 符合類型:即Symbol類。
  10. 特殊值:null空值。

Dart中類型的其他一些規則:

  1. Object類是Dart中除Null之外的所有類的基類。擴展問題:Dart中頂層類是什麼呢?
  2. Enum類是Dart中所有枚舉類的基類。擴展問題:Enum類是Object的子類嗎?答案:是。
  3. dynamic類型Dart的靜態檢測會失效,容易引發空安全等其他運行時錯誤,建議使用Object或者Object?代替。
  4. FutureStream支持異步編程。
  5. Never一般用於總是拋出異常的函數,表明表達式用於無法成功執行。
  6. void表明值不會被再次使用,一般用户函數返回值。

數字類型(int和double)

Dart中數字類型類結構如下:

image

intdouble都是num類的子類。int不超過64位的整數,double為64位雙精度浮點數。

num類型支持操作:加+,減-,乘*,除/abs()絕對值,ceil()向上取整,floor()向下取整操作。特別注意:操作,如>>右移或者<<左移等位操作,僅int類型支持。

代碼樣例:如下代碼,數字類型定義。

// int類型
var x = 1;
var hex = 0xDEADBEEF;

// double類型
var y = 1.1;
var exponents = 1.42e5;
double z = 1; // 等同於:double z = 1.0;

// num類型:既可以是整數,又可以是浮點數
num x = 1;
x += 2.5;

代碼樣例:如下代碼,數字類型和字符串相互轉換。

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

代碼樣例:如下代碼,int類型操作。

assert((3 << 1) == 6); // 0011 << 1 == 0110
assert((3 | 4) == 7); // 0011 | 0100 == 0111
assert((3 & 4) == 0); // 0011 & 0100 == 0000

代碼樣例:如下代碼,字面量數字屬於編譯時常量,因此字面量數字表達式也可以作為常量。

const msPerSecond = 1000;
const secondsUntilRetry = 5;
const msUntilRetry = secondsUntilRetry * msPerSecond;

字符串類型(String)

Dart中字符串是一個UTF-16的序列碼,我們可以通過'單引號或者"雙引號定義一個字符串、通過${}進行字符串插值、通過相鄰字符串連接、使用+符號進行連接,通過3個單引號'''或者3個雙引號"""定義多行字符串,還可以通過增加前綴r定義原始字符串。

代碼樣例:如下代碼,字符串的各種定義方式。

// 引號:單引號或雙引號
var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
var s3 = 'It\'s easy to escape the string delimiter.';
var s4 = "It's even easier to use the other delimiter.";

// 插值
final name = 'Tom';
var s5 = 'My name is $name.';
assert(s5 == 'My name is Tome.');

// 相鄰字符串
var s6 = 'String '
    'concatenation'
    " works even over line breaks.";
assert(s6 ==
    'String concatenation works even over '
        'line breaks.');

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

// 多行字符串:3個單引號或3個雙引號
var s8 = '''
My name is Tom.
I am a boy.
''';

var s9 = """
My name is Tom.
I am a boy.
""";

// 原始字符串
var s10 = r'My name is Tome.\nI am a boy.';

特別注意:==雙等於號操作符在Dart中用於檢測2個對象是否相等,如果是字符串,則是校驗它們的序列碼是否相同(這與Java有很多的區別)。

代碼樣例:如下代碼,字面量字符串是編譯時常量,如果字符串插值表達式中的變量是常量,那麼插值字符串也是常量。

// 字面量字符串
const aConstString = 'a constant string';

// 插值字符串常量
const aConstNum = 0;
const aConstBool = true;
const validConstString = '$aConstNum $aConstBool $aConstString';

布爾類型(bool)

Dart中只有2個對象是bool類型:truefalse,且他們都是常量。

代碼樣例:如下代碼,在表達式中的布爾類型。

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

字符和符號(characters)

Dart中字符代表字符串中一個Unicode編碼單元。Unicode為世界上的每個字母、數字和符合定義了一個唯一數字值。

由於Dart的字符串是UTF-16編碼,因此Dart中表示Unicode有其對應的語法格式,常用的方式為\uXXXX代表一個字符,其中XXXX4位16進制的值。

舉例説明:心形字符♥的值為\u2665,如果少於或者超過4位16禁止值,則用{}包裹起來,如笑臉字符😁的值為\u{1f606}

代碼樣例:如下所示,一般我們用characters庫來操作字符。

import 'package:characters/characters.dart';

void main() {
  var hi = 'Hi 🇩🇰';
  print(hi);
  // 結果:Hi 🇩🇰
  
  print('The end of the string: ${hi.substring(hi.length - 1)}');
  // 結果:The end of the string: ???

  final charList = hi.characters;
  for (int i = 0; i < charList.length; i++) {
    print('The character $i = ${charList.elementAt(i)}');
  }
  // 結果:
  // The character 0 = H
  // The character 1 = i
  // The character 2 =  
  // The character 3 = 🇩🇰

  print('The last character: ${hi.characters.last}');
  // The last character: 🇩🇰
}

特別注意:如上代碼,因為使用了characters庫,因此需要在pubspec.yaml文件中增加依賴(如下完整配置)。

name: NTopicDart

environment:
  sdk: ^3.1.2

dependencies:
  characters: ^1.3.0

符號(Symbol)

有點類似於HTML中錨,#前綴,後面格式標識符。

記錄類型(Record)

Dart官網文檔:https://dart.dev/language/records

特別注意:記錄類型需要Dart 3.0才開始支持(Java從JDK 21開始支持)。

Record記錄類型是一個匿名的、不可變集合類型。有點兒像集合類型,它是多個對象元素的集合,不一樣的是,記錄大小固定、異構和類型固定的。記錄是一個具體的值,因此它可以作為變量、函數入參或結果、也可以嵌套(即記錄中的元素是一個記錄),也可以作為List/Set/Map等集合類的元素。

記錄語法:

  1. ()括號包裹的,,逗號分隔的命名字段或者位置字段列表。
  2. 記錄類型註解是用()括號包裹的,,號分隔的字段類型列表,它可以作為方法入參和結果的類型。
  3. 記錄如果使用的是命名字段,那麼字段名是記錄定義的一部分,即2個記錄,字段名不一樣則是2個不同的記錄。
  4. 記錄的字段內置getters取值方法,但是沒有setters設置方法,因為記錄是不可變的。其中命名字段的字段名即取值方法,而位置字段則使用$<position>字段位置取值,並且忽略所有的命名字段。
  5. 記錄比較:如果2個記錄相對,那麼他們必須有相同的字段、相同的字段類型,已經字段具有相同的值。
  6. 記錄可作為函數入參和返回值:當作為返回值,其實是一個函數可以返回多個值。
// 記錄定義:位置字段+命名字段
var record = ('first', a: 2, b: true, 'last');

// 記錄類型註解 
(int, int) swap((int, int) record) {
  var (a, b) = record;
  return (b, a);
}

// 記錄定義和初始化
(String, int) record;
record = ('A string', 123);

({int a, bool b}) record;
record = (a: 123, b: true);

// 命令字段:字段名不一樣,屬於不同的記錄(recordAB和recordXY是不同類型)
({int a, int b}) recordAB = (a: 1, b: 2);
({int x, int y}) recordXY = (x: 3, y: 4);


// 位置字段:類型一樣即可,參數名不是記錄定義的一部分
(int a, int b) recordAB = (1, 2);
(int x, int y) recordXY = (3, 4);
recordAB = recordXY;

// 取值方法:位置字段和命名字段的取值方法
var record = ('first', a: 2, b: true, 'last');
print(record.$1); // 結果:first
print(record.a);  // 結果:2
print(record.b);  // 結果:true
print(record.$2); // 結果:last

// 記錄比較:相同字段、字段類型和字段值
(int x, int y, int z) point = (1, 2, 3);
(int r, int g, int b) color = (1, 2, 3);

print(point == color); // 結果: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); // 結果:false

集合類型(list/set/map)

Dart官方文檔:https://dart.dev/language/collections

list、set、map的定義和用法:Flutter/Dart第03天:Dart可迭代集合

代碼樣例:如下代碼,通過...list的方式可以展開一個集合;定義集合時,可增加控制流

// 展開非null的集合
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);

// 展開為null的集合
var list3;
var list2 = [0, ...?list3];
assert(list2.length == 1);

// 條件判斷
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'];
assert(listOfStrings[1] == '#1');

泛型類型

Dart官網文檔:https://dart.dev/language/generics

泛型是編碼中最常見的編碼方式,本文不在贅述。

類型別名(typedef)

Dart官網文檔:https://dart.dev/language/typedefs

類型別名:通過typedef關鍵字,可以給一個類型增加一個別名類型(目前還沒有看到別名存在的必要🐶)。

// 類型別名
typedef IntList = List<int>;
IntList il = [1, 2, 3];

// 類型別名:感覺簡短
typedef ListMapper<X> = Map<X, List<X>>;
Map<String, List<String>> m1 = {};
ListMapper<String> m2 = {};

// 類型別名:`不建議`把內聯函數定義別名
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://ntopic.cn/p/2023100301


Add a new Comments

Some HTML is okay.