如何學一門新語言,以 Dart 爲例

世界上沒有一種能夠各個領域通吃的語言,爲了應對不一樣的場景和需求,咱們擺脫不了要學習一門新的語言。最近準備入坑 Flutter(技術儲備),學了點 Dart, 一點心得分享給你們。前端


大綱程序員


介紹

1. 假定前提

我想看這篇文章的應該都是程序員了吧?都有本身熟悉的語言,這就好辦了,咱們能夠複用已有的認知去快速學習一門新語言。若是你是小白,這篇文章可能不適合你編程


2. 基本原則

  • 肯定語言的定位和場景。別再說 PHP 是最好的語言了,你們都知道。每一門語言都有本身定位和適用場景,爲了解決不一樣的問題。因此學習一門語言的時候,首先要了解語言的定位和領域,這樣你才能明白爲何語言設計者設計某個特性的動機。例如:設計模式

    • JavaScript:瀏覽器腳本語言霸主, 寫前端確定繞不開 JavaScript 啦。一門十幾天搞出來的語言,就不要問 [] == ![] // true 是什麼動機了, 不要學這些糟粕。
    • Dart: 針對客戶端('Flutter')優化語言, 當初號稱要取代 JavaScript, 官方本身的定位就是客戶端
    • Go: 聽說是 C++ 編譯速度慢倒逼出來的語言。因此你能夠站在 C++ 的對立面去思考它的設計:例如 簡單的語法、高速編譯、垃圾回收、高性能、高併發。半數是爲了解決 C++ 的問題。適用於服務器編程、分佈式、網絡編程、雲平臺。
    • Rust: 系統編程語言,C/C++ 最有力的挑戰者

    固然,也有一些語言只有在特定平臺或場景才能使用,這種沒辦法,這屬於商業壁壘。例如數組

    • Swift/Objective-C 基本只能用於 Apple 平臺,儘管 Swift 開源,也能夠跑在 Linux 上,但除了 Apple 應用開發,不多看到 Swift 的身影
    • C# 和 Swift 相似

  • 不要陷入語言的語法細節,剝離掉語法糖。學習新語言,能夠暫時忽略掉語法的細節, 切換到上帝視角瀏覽器

  • 基於原有的認知,橫向進行比較。正常來講編程語言 80% 概念或範式是通用的,這就是爲何你熟悉一門語言,能夠快速入門其餘語言。服務器

  • 打破認知。另外 20% 包含該門語言獨有的特性和思想, 這纔是咱們須要關注的核心。網絡


3. 基本姿式

  • 肯定本身要解決的問題/場景。 咱們學一門語言通常不是爲了學習語言而學習。首先你應該有須要解決場景和問題,接着帶着這些問題對編程語言進行選型,肯定多個語言候選者。
  • 思考這些語言是怎麼解決你的問題的? 這就是'打破認知'的過程, 分析一下這些候選者優缺點
  • 肯定要學習這門語言了? 下文會按照這個步驟展開
    • 創建標籤雲。收集這門語言的 20% 獨有特性/思想, 例如 Killer Feature、槽點、吹點,針對性刻意進行學習。
    • 粗略過一下官方文檔。 也就是那80%,對基本語法有個基本的印象,類比本身熟悉的語言,能夠快速理解。
    • 開始實踐。如今你這門語言創建初步的印象了。趁熱開始實踐,好比能夠跟着官方入門教程。一邊實踐一邊查閱文檔,很快就能熟練起來
    • 深刻了解這門語言


已有的語言認知

下面是常見編程語言的構成圖譜,對照一下,這些概念是否都知道? 是否真的瞭解你用來吃飯的傢伙?併發



沒看懂?看來你沒學過一門真正(複雜)的語言,如 ScalaC嘎嘎Rust。😺 翻過這些大山,其餘的就是一覽衆山小了。太難了異步

小孩子才作選擇,牛逼(有精力)的人是全都要。你也能夠學幾門比較有表明性語言。參考《七天七語言》開始點技能樹:

  • 按市場劃分:

    • 通用類型語言(用來吃飯的)。 例如 Java、JavaScript、Python、C/C++、Go、PHP、Objective-C/Swift(iOS開發者, 嚴格說不算‘通用’)
    • 符合本身口味的小衆語言。Rust、Elixir、Ruby、Kotlin、Clojure、OCaml...
  • 按範式劃分:

    • 面向對象: 例如 Ruby、Java、Python...
    • 多範式: 例如 JavaScript、Scala、Rust...
    • 函數式: 例如 Lisp(例如Clojure)、Erlang、Haskell...
    • 過程式: 例如 C、Go(能夠算是面向對象、Whatever)
    • 原型語言: Io,好小衆
  • 其餘劃分方式:

    • 類型: 強類型、弱類型; 靜態類型、動態類型
    • 執行方式: 靜態語言、腳本語言
    • 系統層次: 系統編程語言、應用語言


創建標籤雲

上文說了,80% 的知識是能夠複用的,咱們要針對另外 20% 該語言獨有的特性和思想進行刻意學習。我這裏介紹一個方法是創建一個標籤雲。這個標籤雲是對這門語言的一些關鍵描述。 例如它的主要特性、優勢、吐槽點。

這些關鍵描述對咱們快速瞭解一門語言有很大的幫助, 這個標籤雲其實表明的就是你對這門語言的基本印象。 換句話說,你學了一門語言,但沒怎麼用,過一段時間就忘光了全部語法細節,可是這門語言的基本印象會長久停留在你腦海中。我想這些印象就是這門語言的精髓所在吧!

那麼怎麼收集這個標籤雲?

  • 打開官網。看官方怎麼描述本身的語言、有哪些主要特性、定位是什麼。
  • 也能夠經過 Wiki 看看這門語言的系統的描述和定義
  • 知乎。看別人怎麼吹或者吐槽這門語言的
  • 道聽途說
  • 快速預覽官方指南。找亮點

隨便舉幾個例子。 Dart 語言:

標籤雲使用 WordClouds 生成


Go 語言:


Javascript:


Elixir:



刻意學習,以 Dart 爲例

接着帶着這些問題針對性地去學習這門語言, 這裏以Dart 爲例,由於這兩天正好在學 Dart,準備入坑 Flutter,我本身對 Dart 沒什麼好感。

學習方法, 永遠是 What / Why / How: 是什麼,爲何這麼設計,具體怎麼作?

① 2018 最坑人語言?

沒有 Flutter 這門語言確實要掛了。編程語言也要看爹


② 針對客戶端優化

這是官方本身的定位。

針對客戶端優化主要體如今開發體驗運行性能上面

  • JIT(Just in Time) 快速編譯生效,這是 Hot reload 基礎。Hot reload 可讓 Flutter 接近 Web 的開發體驗
  • AOT(Ahead of Time) 生成高效原生代碼。能夠獲得更快的運行速度和啓動速度
  • 另一層意思是,Dart 這門語言和 JavaScript 很是類似。好比語法、單線程/事件循環、事件驅動、async/await、Isolate、Generator、Future/Stream、collection if/for 能夠媲美JSX
  • 支持編譯到JavaScript。瀏覽器是重要的客戶端,不支持 JavaScript 還敢說客戶端優化?

③ 面向對象

語法和 Java 很像,有一些語法糖挺甜的。

  • 沒有關鍵字區分 class 和 interface,能夠說 class 就是 interface

  • Mixins。前端對 Mixin 的概念應該都不陌生,畢竟這麼多人用 Vue?

  • 操做符重載。Javascript 不支持操做符重載。因此對前端來講算是一個新東西。 不過我的不推薦,JavaScript 沒有操做符重載不也用得挺爽? 並且操做符的語義不明確,會徒增心智負擔,這時候還不如使用定義良好的方法。有意義的名稱比符號要好記憶

  • new 可選。在某些場景讓代碼更簡潔,好比 Flutter 組件聲明。算是彌補沒有 JSX 之痛吧。

    void main() {
      runApp(
        Center(
          child: Text(
            'Hello, world!',
            textDirection: TextDirection.ltr,
          ),
        ),
      );
    }
    複製代碼
  • Callable Classes。語法糖,沒想到有什麼應用場景。

    class WannabeFunction {
      call(String a, String b, String c) => '$a $b $c!';
    }
    
    var wf = new WannabeFunction();
    var out = wf("Hi","there,","gang"); // 🍬
    複製代碼

    我直接 wf.call 也不麻煩吧? 靈感來自JavaScript? JavaScript 的函數也是一個對象,能夠有本身屬性


④ 操做符

Dart 也有一些有趣的操做符/表達式,來看看有多甜:

  • 級聯操做符(Cascade Notation)。級聯操做符是一個很甜的語法糖。不說廢話,看代碼:

    querySelector('#confirm') // Get an object.
    ..text = 'Confirm' // 🍬 甜點,這是類 jQuery 的串行調用的加強版
    ..classes.add('important')
    ..onClick.listen((e) => window.alert('Confirmed!'));
    複製代碼

    等價於:

    var button = querySelector('#confirm');
    button.text = 'Confirm';
    button.classes.add('important');
    button.onClick.listen((e) => window.alert('Confirmed!'));
    複製代碼

  • 容器操做符(Collection Operators)。這個語法糖也會比較甜,前期用 Dart 來描述 Flutter 的視圖是一件很痛苦的事情。Dart 陸續添加了一些甜點,如展開操做符Collection if/for, 再加上命名函數參數new可選,表達力已經很接近 JSX 了

    [0, ...list];
    [0, ...?list]; // 支持識別null的展開操做符
    
    // collection if
    var nav = [
      'Home',
      'Furniture',
      'Plants',
      if (promoActive) 'Outlet'
    ];
    
    // collection for
    var listOfStrings = [
      '#0',
      for (var i in listOfInts) '#$i'
    ];
    複製代碼


⑤ const/final 與靜態數據

在 dart 中 const/final 使用的地方很是多,能夠用於修飾變量、實例變量、對象建立。

注意:靜態數據和不可變數據是不一樣的概念

  • 變量修飾
final name = 'Bob';
const bar = 100000;
const foo = [];
const baz = [];

console.log(foo == baz); // true 編譯時常量
複製代碼

const 將被視爲'編譯時'常量。相對final 有所優化


  • 修飾對象建立
var foo = const [];
複製代碼

const 修飾變量建立,Dart 會默認以 const 的上下文來實例化對象:

const primaryColors = [
  Color("red", [255, 0, 0]),
  Color("green", [0, 255, 0]),
  Color("blue", [0, 0, 255]),
];
複製代碼

primaryColor被修飾 const 修飾,那麼其下的對象建立都隱式使用 const 修飾。上面的代碼等價於:

const primaryColors = const [
  const Color("red", const [255, 0, 0]),
  const Color("green", const [0, 255, 0]),
  const Color("blue", const [0, 0, 255]),
];
複製代碼

Dart 內置的容器對象默認支持const。 對於自定義類,須要類提供const構造方法, 並且全部實例都必須使用final修飾。

class ImmutablePoint {
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);
  // 全部實例變量都必須用final修飾
  final num x, y;
  // const 構造方法
  const ImmutablePoint(this.x, this.y);
}
複製代碼

⑥ 類型系統

  • 名義類型。沒有Duck Duck Duck 🦆🦆🦆

  • Sound Type System(soundness,嚴格類型系統)。即靜態類型+運行時檢查, 好比一個變量靜態類型爲 String,若是將int賦值給它,編譯器會報錯。可是經過某些手段,咱們能夠繞過編譯器檢查,例如強制類型轉換。Sound Type System 能夠在運行時進行類型檢查,不會放過這些錯誤。

    main(List<String> args) {
      int a;
      a = "1" as int; // 繞過了靜態類型檢查, 可是運行會報錯
    }
    複製代碼

    好處:

    • 代碼更健壯
    • 有利於AOT
    • 儘量消滅bug,編譯階段的漏網之魚,也會被檢測出來,不要抱着僥倖心理。
  • dynamic:能夠視做是any類型吧?儘可能避免使用


⑦ 異步異步

Future/Stream、async/await、Generator。沒必要多說,熟悉 JavaScript 一看就懂


⑧ 元編程

  • MetaData。和Java的註解差很少。顧名思義,MetaData就是給你的代碼提供更多的信息。能夠用於提示編譯器,在運行時經過反射庫也能夠獲取到MetaData信息。

    class SmartTelevision extends Television {
      @override
      void turnOn() {...}
      // ···
    }
    複製代碼
  • noSuchMethod()。相似於 Ruby 的 method_missing。 當未找到屬性或者方法時被調用,能夠實現一些動態屬性或方法。元編程神器。在 JavaScript 中能夠經過Proxy 實現相同的效果。



說實話,Dart 沒有什麼多少讓人眼前一亮的特性。在它身上你能夠看到許多其餘語言的影子、例如Java、JavaScript、Swift... 這也無可厚非,現代編程語言確實長得愈來愈像。

好處是它特別容易上手,壞處是除了 Flutter 綁定以外,我找不到其餘能夠用它的理由。



實踐

藉助已有的經驗,很快就能夠入門,這時候能立刻上手去寫是最好的。

能夠從Hello World 開始, 或者也能夠從官方的入門教程開始。Dart 的話。

hello world !

void main(List<String> args) {
  print('Hello, World!');
}
複製代碼

經過最簡單的 hello world 也能夠獲知一些關鍵信息:

  • 相似 C 的前綴式類型聲明。
  • main 程序入口
  • 分號不能省略
  • 標準庫。print 來源於 dart:core 這個包是全局的
  • List 數組
  • 泛型
  • ...

Flutter 搞起來!



深刻了解這門語言

若是你喜歡這門語言,想要讓大家的關係進一步發展,你就要深刻了解它:

  • 瞭解它的最佳實踐
  • 閱讀它的語言規範
  • 造輪子。好比寫個靜態網頁生成器; 若是是面嚮對象語言,能夠實現幾個常見的設計模式
  • 學習標準庫
  • 瞭解實現原理
  • 瞭解性能分析和優化


總結

編程語言也有三重境界:

看山是山,看山不是山,看山仍是山

  • ① 我用的語言就是最好的語言,如 PHP,很牛逼
  • ② 全部語言都差很少,本質都是同樣
  • ③ 迴歸到語言,語言不過是個工具。就像畫家的畫筆,不過是實現本身想法的一個工具。這個階段,咱們再也不爭執什麼是最好的語言,並且爲了避免同的繪製效果選擇不一樣的畫筆。

只要能解決咱們須要解決的問題,編程語言歷來不是門檻,或者說它是最容易被克服的問題。就像別人吐槽 Flutter 用 Dart 而不用JavaScript同樣。



擴展

相關文章
相關標籤/搜索