前言一:接下來一段時間我會陸續更新一些列Flutter文字教程vue
更新進度: 每週至少兩篇;算法
更新地點: 首發於公衆號,次日更新於掘金、思否等地方;express
更多交流: 能夠添加個人微信 372623326,關注個人微博:coderwhy編程
但願你們能夠 幫忙轉發,點擊在看,給我更多的創做動力。數組
前言二:若干年後,你會發現,選錯了公司和行業的損失遠比選錯了語言來的大。安全
並且計算機這個行業,只會一種編程語言顯然是不現實的,接收一門新的語言,並無你想象中的難!微信
Google爲Flutter選擇了Dart就已是既定的事實,不管你多麼想用你熟悉的語言,好比JavaScript、Java、Swift、C++等來開發Flutter,至少目前都是不能夠的。數據結構
在講解Dart的過程當中,我會假定你已經有必定的編程語言基礎
,好比JavaScript、Java、Python、C++等。閉包
其實若是你對編程語言足夠的自信
,Dart的學習過程甚至能夠直接忽略:app
差別是並不大
;語法上的差別
+某些語言有某些特性
,而某些語言沒有某些特性而已;因此,若是你對編程語言已經足夠了解,能夠跳過咱們接下來的Dart學習:
下面,咱們就從安裝Dart開始吧!
爲何還須要安裝Dart呢?
事實上在安裝Flutter SDK的時候,它已經內置了Dart了,咱們徹底能夠直接使用Flutter去進行Dart的編寫而且運行。
可是,若是你想單獨學習Dart,而且運行本身的Dart代碼,最好去安裝一個Dart SDK。
下載Dart SDK
到Dart的官方,根據不一樣的操做系統下載對應的Dart
不管是什麼操做系統,安裝方式都是有兩種:經過工具安裝
和直接下載SDK,配置環境變量
1.經過工具安裝
2.直接下載SDK,配置環境變量
學習Dart過程當中,我使用VSCode
做爲編輯器
使用VSCode編寫Dart須要安裝Dart插件:我目前給這個VSCode裝了四個插件
接下來,就能夠步入正題了。學習編程語言,從祖傳的Hello World開始。
在VSCode中新建一個helloWorld.dart文件,添加下面的內容:
main(List<String> args) {
print('Hello World');
}
複製代碼
而後在終端執行dart helloWorld.dart
,就能看到Hello World的結果了。
完成了這個執行過程以後,以你以前學習的編程語言來看,你能獲得多少信息呢?
接下來,就是我本身的總結:
main
是沒有返回值的;main
的命令行參數,是經過List<String>
完成的。
List
是Dart中的集合類型。String
都表示傳遞給main
的一個參數;明確聲明變量的方式, 格式以下:
變量類型 變量名稱 = 賦值;
複製代碼
示例代碼:
String name = 'coderwhy';
int age = 18;
double height = 1.88;
print('${name}, ${age}, ${height}'); // 拼接方式後續會講解
複製代碼
注意事項: 定義的變量能夠修改值, 可是不能賦值其餘類型
String content = 'Hello Dart';
content = 'Hello World'; // 正確的
content = 111; // 錯誤的, 將一個int值賦值給一個String變量
複製代碼
類型推導聲明變量的方式, 格式以下:
var/dynamic/const/final 變量名稱 = 賦值;
複製代碼
var的使用示例:
var name = 'coderwhy';
name = 'kobe';
print(name.runtimeType); // String
複製代碼
var的錯誤用法:
var age = 18;
age = 'why'; // 不能夠將String賦值給一個int類型
複製代碼
若是確實但願這樣作,可使用dynamic來聲明變量:
dynamic name = 'coderwhy';
print(name.runtimeType); // String
name = 18;
print(name.runtimeType); // int
複製代碼
final和const都是用於定義常量的, 也就是定義以後值都不能夠修改
final name = 'coderwhy';
name = 'kobe'; // 錯誤作法
const age = 18;
age = 20; // 錯誤作法
複製代碼
final和const有什麼區別呢?
String getName() {
return 'coderwhy';
}
main(List<String> args) {
const name = getName(); // 錯誤的作法, 由於要執行函數才能獲取到值
final name = getName(); // 正確的作法
}
複製代碼
final和const小案例:
// const time = DateTime.now(); // 錯誤的賦值方式
final time = DateTime.now();
print(time); // 2019-04-05 09:02:54.052626
sleep(Duration(seconds: 2));
print(time); // 2019-04-05 09:02:54.052626
複製代碼
const放在賦值語句的右邊,能夠共享對象,提升性能:
class Person {
const Person();
}
main(List<String> args) {
final a = const Person();
final b = const Person();
print(identical(a, b)); // true
final m = Person();
final n = Person();
print(identical(m, n)); // false
}
複製代碼
對於數值來講,咱們也不用關心它是否有符號,以及數據的寬度和精度等問題。只要記着整數用int
,浮點數用double
就好了。
不過,要說明一下的是Dart中的int
和double
可表示的範圍並非固定的,它取決於運行Dart的平臺。
// 1.整數類型int
int age = 18;
int hexAge = 0x12;
print(age);
print(hexAge);
// 2.浮點類型double
double height = 1.88;
print(height);
複製代碼
字符串和數字之間的轉化:
// 字符串和數字轉化
// 1.字符串轉數字
var one = int.parse('111');
var two = double.parse('12.22');
print('${one} ${one.runtimeType}'); // 111 int
print('${two} ${two.runtimeType}'); // 12.22 double
// 2.數字轉字符串
var num1 = 123;
var num2 = 123.456;
var num1Str = num1.toString();
var num2Str = num2.toString();
var num2StrD = num2.toStringAsFixed(2); // 保留兩位小數
print('${num1Str} ${num1Str.runtimeType}'); // 123 String
print('${num2Str} ${num2Str.runtimeType}'); // 123.456 String
print('${num2StrD} ${num2StrD.runtimeType}'); // 123.46 String
複製代碼
布爾類型中,Dart提供了一個bool的類型, 取值爲true和false
// 布爾類型
var isFlag = true;
print('$isFlag ${isFlag.runtimeType}');
複製代碼
注意: Dart中不能判斷非0即真, 或者非空即真
Dart的類型安全性意味着您不能使用if(非booleanvalue)或assert(非booleanvalue)之類的代碼。
var message = 'Hello Dart';
// 錯誤的寫法
if (message) {
print(message)
}
複製代碼
Dart字符串是UTF-16編碼單元的序列。您可使用單引號或雙引號建立一個字符串:
// 1.定義字符串的方式
var s1 = 'Hello World';
var s2 = "Hello Dart";
var s3 = 'Hello\'Fullter';
var s4 = "Hello'Fullter";
複製代碼
可使用三個單引號或者雙引號表示多行字符串:
// 2.表示多行字符串的方式
var message1 = ''' 哈哈哈 呵呵呵 嘿嘿嘿''';
複製代碼
字符串和其餘變量或表達式拼接: 使用${expression}, 若是表達式是一個標識符, 那麼{}能夠省略
// 3.拼接其餘變量
var name = 'coderwhy';
var age = 18;
var height = 1.88;
print('my name is ${name}, age is $age, height is $height');
複製代碼
對於集合類型,Dart則內置了最經常使用的三種:List / Set / Map
。
其中,List
能夠這樣來定義:
// List定義
// 1.使用類型推導定義
var letters = ['a', 'b', 'c', 'd'];
print('$letters ${letters.runtimeType}');
// 2.明確指定類型
List<int> numbers = [1, 2, 3, 4];
print('$numbers ${numbers.runtimeType}');
複製代碼
其中,set
能夠這樣來定義:
[]
換成{}
就行了。Set
和List
最大的兩個不一樣就是:Set
是無序的,而且元素是不重複的。// Set的定義
// 1.使用類型推導定義
var lettersSet = {'a', 'b', 'c', 'd'};
print('$lettersSet ${lettersSet.runtimeType}');
// 2.明確指定類型
Set<int> numbersSet = {1, 2, 3, 4};
print('$numbersSet ${numbersSet.runtimeType}');
複製代碼
最後,Map
是咱們常說的字典類型,它的定義是這樣的:
// Map的定義
// 1.使用類型推導定義
var infoMap1 = {'name': 'why', 'age': 18};
print('$infoMap1 ${infoMap1.runtimeType}');
// 2.明確指定類型
Map<String, Object> infoMap2 = {'height': 1.88, 'address': '北京市'};
print('$infoMap2 ${infoMap2.runtimeType}');
複製代碼
瞭解了這三個集合的定義方式以後,咱們來看一些最基礎的公共操做
第一類,是全部集合都支持的獲取長度的屬性length
:
// 獲取集合的長度
print(letters.length);
print(lettersSet.length);
print(infoMap1.length);
複製代碼
第二類, 是添加/刪除/包含操做
List
來講,因爲元素是有序的,它還提供了一個刪除指定索引位置上元素的方法// 添加/刪除/包含元素
numbers.add(5);
numbersSet.add(5);
print('$numbers $numbersSet');
numbers.remove(1);
numbersSet.remove(1);
print('$numbers $numbersSet');
print(numbers.contains(2));
print(numbersSet.contains(2));
// List根據index刪除元素
numbers.removeAt(3);
print('$numbers');
複製代碼
第三類,是Map
的操做
// Map的操做
// 1.根據key獲取value
print(infoMap1['name']); // why
// 2.獲取全部的entries
print('${infoMap1.entries} ${infoMap1.entries.runtimeType}'); // (MapEntry(name: why), MapEntry(age: 18)) MappedIterable<String, MapEntry<String, Object>>
// 3.獲取全部的keys
print('${infoMap1.keys} ${infoMap1.keys.runtimeType}'); // (name, age) _CompactIterable<String>
// 4.獲取全部的values
print('${infoMap1.values} ${infoMap1.values.runtimeType}'); // (why, 18) _CompactIterable<Object>
// 5.判斷是否包含某個key或者value
print('${infoMap1.containsKey('age')} ${infoMap1.containsValue(18)}'); // true true
// 6.根據key刪除元素
infoMap1.remove('age');
print('${infoMap1}'); // {name: why}
複製代碼
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('why'); // name=why age=null height=null
printInfo1('why', age: 18); // name=why age=18 height=null
printInfo1('why', age: 18, height: 1.88); // name=why age=18 height=1.88
printInfo1('why', height: 1.88); // name=why age=null height=1.88
複製代碼
位置可選參數的演示:
// 定義位置可選參數
printInfo2(String name, [int age, double height]) {
print('name=$name age=$age height=$height');
}
// 調用printInfo2函數
printInfo2('why'); // name=why age=null height=null
printInfo2('why', 18); // name=why age=18 height=null
printInfo2('why', 18, 1.88); // name=why 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('coderwhy');
}
// 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');
}
複製代碼
備註:全部內容首發於公衆號,以後除了Flutter也會更新其餘技術文章,TypeScript、React、Node、uniapp、mpvue、數據結構與算法等等,也會更新一些本身的學習心得等,歡迎你們關注