本文首發於個人部落格
函式
函式的基本定義
- Dart是一種真正的面嚮物件語言,所以即使函式也是物件,所有也有型別, 型別就是Function。
- 這也就意味著函式可以作為變數定義或者作為其他函式的引數或者返回值.
函式的定義方式:
返回值 函式的名稱(引數列表) {
函式體
return 返回值
}
複製程式碼
按照上面的定義方式, 我們定義一個完整的函式:
int sum(num num1, num num2) {
return num1 + num2;
}
複製程式碼
Effective Dart建議對公共的API, 使用型別註解, 但是如果我們省略掉了型別, 依然是可以正常工作的
sum(num1, num2) {
return num1 + num2;
}
複製程式碼
另外, 如果函式中只有一個表示式, 那麼可以使用箭頭語法(arrow syntax)
- 注意, 這裡面只能是一個表示式, 不能是一個語句
sum(num1, num2) => num1 + num2;
複製程式碼
函式的引數問題
函式的引數可以分成兩類: 必須引數和可選引數 前面使用的引數都是必須引數.
可選引數
可選引數可以分為 命名可選引數 和 位置可選引數 定義方式:
命名可選引數: {param1, param2, ...}
位置可選引數: [param1, param2, ...]
複製程式碼
命名可選引數的演示:
// 命名可選引數
printInfo1(String name, {int age, double height}) {
print('name=$name age=$age height=$height');
}
// 呼叫printInfo1函式
printInfo1('eagle'); // name=eagle age=null height=null
printInfo1('eagle', age: 18); // name=eagle age=18 height=null
printInfo1('eagle', age: 18, height: 1.88); // name=eagle age=18 height=1.88
printInfo1('eagle', height: 1.88); // name=eagle age=null height=1.88
複製程式碼
位置可選引數的演示:
// 定義位置可選引數
printInfo2(String name, [int age, double height]) {
print('name=$name age=$age height=$height');
}
// 呼叫printInfo2函式
printInfo2('eagle'); // name=eagle age=null height=null
printInfo2('eagle', 18); // name=eagle age=18 height=null
printInfo2('eagle', 18, 1.88); // name=eagle age=18 height=1.88
複製程式碼
命名可選引數, 可以指定某個引數是必傳的(使用@required, 有問題)
// 命名可選引數的必須
printInfo3(String name, {int age, double height, @required String address}) {
print('name=$name age=$age height=$height address=$address');
}
複製程式碼
引數預設值
引數可以有預設值, 在不傳入的情況下, 使用預設值
注意, 只有可選引數才可以有預設值, 必須引數不能有預設值
// 引數的預設值
printInfo4(String name, {int age = 18, double height=1.88}) {
print('name=$name age=$age height=$height');
}
複製程式碼
Dart中的main函式就是一個接受可選的列表引數作為引數的, 所以在使用main函式時, 我們可以傳入引數, 也可以不傳入
函式是一等公民
在很多語言中, 函式並不能作為一等公民來使用, 比如Java/OC. 這種限制讓程式設計不夠靈活, 所以現代的程式語言基本都支援函式作為一等公民來使用, Dart也支援. 這就意味著你可以將函式賦值給一個變數, 也可以將函式作為另外一個函式的引數或者返回值來使用.
main(List<String> args) {
// 1.將函式賦值給一個變數
var bar = foo;
print(bar);
// 2.將函式作為另一個函式的引數
test(foo);
// 3.將函式作為另一個函式的返回值
var func =getFunc();
func('kobe');
}
// 1.定義一個函式
foo(String name) {
print('傳入的name:$name');
}
// 2.將函式作為另外一個函式的引數
test(Function func) {
func('eagle');
}
// 3.將函式作為另一個函式的返回值
getFunc() {
return foo;
}
複製程式碼
匿名函式的使用
大部分我們定義的函式都會有自己的名字, 比如前面定義的foo、test函式等等。 但是某些情況下,給函式命名太麻煩了,我們可以使用沒有名字的函式,這種函式可以被稱之為匿名函式( anonymous function),也可以叫lambda或者closure。
main(List<String> args) {
// 1.定義陣列
var movies = ['盜夢空間', '星際穿越', '少年派', '大話西遊'];
// 2.使用forEach遍歷: 有名字的函式
printElement(item) {
print(item);
}
movies.forEach(printElement);
// 3.使用forEach遍歷: 匿名函式
movies.forEach((item) {
print(item);
});
movies.forEach((item) => print(item));
}
複製程式碼
詞法作用域
dart中的詞法有自己明確的作用域範圍,它是根據程式碼的結構({})來決定作用域範圍的 優先使用自己作用域中的變數,如果沒有找到,則一層層向外查詢。
var name = 'global';
main(List<String> args) {
// var name = 'main';
void foo() {
// var name = 'foo';
print(name);
}
foo();
}
複製程式碼
詞法閉包
閉包可以訪問其詞法範圍內的變數,即使函式在其他地方被使用,也可以正常的訪問。
main(List<String> args) {
makeAdder(num addBy) {
return (num i) {
return i + addBy;
};
}
var adder2 = makeAdder(2);
print(adder2(10)); // 12
print(adder2(6)); // 8
var adder5 = makeAdder(5);
print(adder5(10)); // 15
print(adder5(6)); // 11
}
複製程式碼
返回值問題
所有函式都返回一個值。如果沒有指定返回值,則語句返回null;隱式附加到函式體。
main(List<String> args) {
print(foo()); // null
}
foo() {
print('foo function');
}
複製程式碼
運算子
除法、整除、取模運算
我們來看一下除法、整除、取模運算
var num = 7;
print(num / 3); // 除法操作, 結果2.3333..
print(num ~/ 3); // 整除操作, 結果2;
print(num % 3); // 取模操作, 結果1;
複製程式碼
??=賦值操作
dart有一個很多語言都不具備的賦值運算子:
- 當變數為null時,使用後面的內容進行賦值。
- 當變數有值時,使用自己原來的值。
main(List<String> args) {
var name1 = 'eagle';
print(name1);
// var name2 = 'kobe';
var name2 = null;
name2 ??= 'james';
print(name2); // 當name2初始化為kobe時,結果為kobe,當初始化為null時,賦值了james
}
複製程式碼
條件運算子:
Dart中包含一直比較特殊的條件運算子:expr1 ?? expr2
- 如果expr1是null,則返回expr2的結果;
- 如果expr1不是null,直接使用expr1的結果。
var temp = 'eagle';
var temp = null;
var name = temp ?? 'kobe';
print(name);
複製程式碼
級聯語法:..
- 某些時候,我們希望對一個物件進行連續的操作,這個時候可以使用級聯語法
class Person {
String name;
void run() {
print("${name} is running");
}
void eat() {
print("${name} is eating");
}
void swim() {
print("${name} is swimming");
}
}
main(List<String> args) {
final p1 = Person();
p1.name = 'eagle';
p1.run();
p1.eat();
p1.swim();
final p2 = Person()
..name = "eagle"
..run()
..eat()
..swim();
}
複製程式碼
流程控制
和大部分語言的特性比較相似,這裡就不再詳細贅述,看一下即可。
if和else
和其他語言用法一樣 這裡有一個注意點:不支援非空即真或者非0即真,必須有明確的bool型別
- 我們來看下面name為null的判斷
var age = null;
if(age){ //錯誤的用法
print(age);
}
複製程式碼
迴圈操作
基本的for迴圈
for (var i = 0; i < 5; i++) {
print(i);
}
複製程式碼
for in遍歷List和Set型別
var names = ['eagle', 'kobe', 'curry'];
for (var name in names) {
print(name);
}
複製程式碼
while和do-while和其他語言一致 break和continue用法也是一致
switch-case
普通的switch使用
注意:每一個case語句,預設情況下必須以一個break結尾
main(List<String> args) {
var direction = 'east';
switch (direction) {
case 'east':
print('東面');
break;
case 'south':
print('南面');
break;
case 'west':
print('西面');
break;
case 'north':
print('北面');
break;
default:
print('其他方向');
}
}
複製程式碼
個人微信: