iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 24
1
Software Development

你會十五種程式語言?不,我會十五種HelloWorld.為了避免這種狀況,因此寫了這篇:淺入淺出十五種程式語言系列 第 24

Dart 食之無味,棄之可惜

寫在前面

Dart是由google開發的語言
目的是讓同一套程式碼可以跨平台編譯
注意,跟JAVA編譯一次後到處執行是不同的喔,Dart雖然也只需要寫一次程式碼,但是如果要跨平台需要分別編譯出不同平台的執行檔
Dart跨平台的方式是使用Flutter這個框架,讓同一套Dart程式碼可以分別編譯出在iOS跟在Andorid平台上執行的執行檔
原本半官方的Flutter Desktop Embedding整合進Flutter後甚至能夠交叉編譯成Windows,MacOS,linux的執行檔
如果你需要開發Web,Dart也能編譯成Javascript,讓你於瀏覽器上執行

Dart的推出讓google有了一套完整的生態,後端由golang吃下,而前端則使用可以跨平台的Dart
(甚至你希望的話,Dart也能拿來開發後端)

但是Dart也不是完全沒有缺點
比方說在Android或iOS上,如果你必須處理底層的事物,那還是必須要倚賴Java及Swift
(這點Dart就比不上kotlin了,畢竟kotlin可以直接拿Java的函式庫來用)
尤其在iOS由於為了安全性有很多系統層級的事情是沒有開放給外部使用,只能使用Swift的api做轉接,此時若是你不是使用Swift就頭大了
(比方說iOS的簡訊處理,設定上是隱藏的)

另外還有個可怕的大魔王,同樣由七巨頭的Facebook推出的React Native
使用工程師們已經很熟悉的Javascript,同時原本就是用來編寫網頁前端的框架延伸而出
變成可以開發用於iOS及Android上的程式
更何況還有比Dart更為豐富的套件庫(雖然Dart有急起直追的趨勢,不過現在還是RN比較多)
因此有人說Flutter唯一的缺點就是使用了Dart,沒辦法接納已經很完整的js生態
目前Flutter能夠跟RN一拼的大概就是效能,但是這個效能是有代價的

https://ithelp.ithome.com.tw/upload/images/20200924/201278369V7Q7BpiH4.png

兩個網頁並不是同一個網頁,單純想展示兩者在畫面的Render上的不同
react還可以分辨出每個元件的在做什麼,但是flutter完全不行(或者該說現在的人類還跟不上嗎?)

於是乎,Dart變成一種看上去很美但是實際上(目前)並沒有到他理想中的實用性
或許如果不需要寫太底層,比方說用於公司內部的系統控管之類的應用上,就可以使用Dart讓你跨平台
做一套可以在PC也能在手機上的程式

說了這麼多,我們來動手寫dart吧
我們今天先不教Flutter,這樣使用docker的同學才能跟上進度

程式碼上菜

在你的工作目錄下面建立一個附檔名為.dart的檔案
然後貼上下面的程式碼吧

import 'dart:io';
import 'dart:math' as math;

void main() {
    print("Tell me what you want to do:");
    print("(1)T to H (2)H to T");
    var input = stdin.readLineSync();
    switch(input){
      case "1":
        print("Please enter the number:");
        var number = stdin.readLineSync();
        print(t2h(number));
      break;

      case "2":
        print("Please enter the number:");
        var number = stdin.readLineSync();
        print(h2t(number));
      break;
    
      default :
        print("Wrong selection");
    }
}

String t2h(String number) {
  var num = int.parse(number);
  for (var i = 0; i < 16; i++){
    for (var j = 0;j < 16; j++){
      for (var k = 0; k < 16; k++){
        if (math.pow(16,2)*i+math.pow(16,1)*j+math.pow(16,0)*k == num)
          return returnAE(i)+returnAE(j)+returnAE(k);
      }
    }
  }
}

String returnAE(int number){
  switch (number){
    case 10: return "A";
    case 11: return "B";
    case 12: return "C";
    case 13: return "D";
    case 14: return "E";
    case 15: return "F";
    default : return number.toString();
  }
}

int h2t(String number){
  int output = 0;
  int i = 0;
  while (i<number.length){
    output += AEreturn(number.substring(i,i+1))*(math.pow(16,number.length-i-1));
    i++;
  }
  return output;
}

int AEreturn(String input){
  switch (input){
    case "A": return 10;
    case "B": return 11;
    case "C": return 12;
    case "D": return 13;
    case "E": return 14;
    case "F": return 15;
    default: return int.parse(input);
  }
}

之後docker的使用者進行掛載後切換到掛載的目錄下執行

docker container run -it -v ${PWD}:/home/Dart google/dart /bin/bash

或是直接執行

docker container run -it -v ${PWD}:/home/Dart google/dart dart /home/Dart/convert.dart

本地有安裝的人可以直接用

dart convert.dart

這樣就可以開始玩你的程式拉

結構

官方有推薦的程式碼風格
官方推薦的tab也不是往常的4個空格,而是跟RN相同的2個空格
但是為了確保我們的程式名稱跟以前寫過的一樣,並沒有完全按照官方的寫法

也能使用官方的工具

dartfmt 

來讓你的程式碼風格接近於官方風格(有沒有golang的感覺?)
也能把程式碼貼到這裡後按下上方的Format

程式開頭的import

import 'dart:io';
import 'dart:math' as math;

是為了要引入冪次計算跟輸入輸出

dart也是編譯式的語言,因此會需要main方法

void main() {}

注意dart的行尾是需要;的喔

輸入輸出

print("Tell me what you want to do:");
print("(1)T to H (2)H to T");
var input = stdin.readLineSync();

輸出使用print
輸入則使用stdin.readLineSync()

print是Dart提供的基本輸出
由於我們已經引入了dart:io這個用來做input跟output的library,我們也能這麼做

stdout.writeln("Tell me what you want to do:");
stdout.writeln("(1)T to H (2)H to T");
var input = stdin.readLineSync();

邏輯switch

Dart的switch結構跟常見的差不多

switch(input){
  case "1":
    print("Please enter the number:");
    var number = stdin.readLineSync();
    print(t2h(number));
  break;

  case "2":
    print("Please enter the number:");
    var number = stdin.readLineSync();
    print(h2t(number));
  break;

  default :
    print("Wrong selection");
}

注意每個case需要使用break隔開

方法的結構

Dart是靜態型別的語言,我們必須提前定義好他們輸入及輸出的型別

輸出型別 方法名稱(輸入型別 輸入變數){

}

因此會長這樣

String t2h(String number) {
  var num = int.parse(number);
  for (var i = 0; i < 16; i++){
    for (var j = 0;j < 16; j++){
      for (var k = 0; k < 16; k++){
        if (math.pow(16,2)*i+math.pow(16,1)*j+math.pow(16,0)*k == num)
          return returnAE(i)+returnAE(j)+returnAE(k);
        }
      }
    }
  }

輸入值及輸出值的型別都是string
並且沒有宣告方法的關鍵字
只要格式對了Dart就會自動判定你寫的是方法

型別

跟C#及部份語言類似
var這個宣告詞會自動幫你判定型別

另外由於Dart是強型別的語言,因此這邊需要轉型
字串轉型成數值的方式是

var int = int.parse(string)

反過來則是

int.toString();

迴圈for

Dart的迴圈也是常見的

for (var i=0; i < 16; i++){

}

的結構

注意迴圈宣告的起始值一樣要宣告,因此你會看到var這個關鍵字

邏輯if

if的結構也是常見的

if (math.pow(16,2)*i+math.pow(16,1)*j+math.pow(16,0)*k == num)
  return returnAE(i)+returnAE(j)+returnAE(k);

這邊由於我們確認完if的條件後需要執行的程式只有一行
因此可以省略{}
如果不習慣這個結構可以加回去,同樣可以執行成功

冪次

這段if裡面我們用到了冪次的計算

結構長這樣

math.pow(x,exp)

x可以是int,exp如果也是非負數的int的話,那麼輸出值就會是int的型別
反之則回傳double型別
詳細的用法可以看這裡

邏輯switch

我們往下看returnAE裡面的程式吧

String returnAE(int number){
  switch (number){
    case 10: return "A";
    case 11: return "B";
    case 12: return "C";
    case 13: return "D";
    case 14: return "E";
    case 15: return "F";
    default : return number.toString();
  }
}

這邊沒有break是因為我們使用了return
break本來的目的就是要中止case的判斷
而return則直接中止方法,並回傳值,因此不需要使用break告知程式碼我們要結束switch了

迴圈While

我們來看跟t2h相對的h2t這個方法吧

int h2t(String number){
  int output = 0;
  int i = 0;
  while (i<number.length){
    output += AEreturn(number.substring(i,i+1))*(math.pow(16,number.length-i-1));
    i++;
  }
  return output;
}

while的用法跟常見的方法相同,這裡不多做描述

字串處理

string.length

則是取出字串長度屬性的方式,型別為int
因此在math.pow內不需要轉型即可當作輸入

math.pow(16,number.length-i-1)

迴圈的內部雖然我們使用字串內建的substring方法來將字串內部的字元取出
但我們也能這樣寫

output += AEreturn(number[i])*(math.pow(16,number.length-i-1));

把字串當作字元的陣列來取出字元

以上就是Dart的基本語法拉

小結

來複習今天學的語法吧

  • 程式結構
    • 編譯式語言,需要使用main方法當作程式進入點
    • 使用import來引入函式庫
    • 行尾需要;
  • 印出/讀取
    • 輸入輸出可以使用io這個函式庫提供的方法來使用
    • stdin.readLineSync() 作為讀取輸入
    • stdout.writeln("") 作為讀取輸出
    • 輸出還可以使用print來當作基本的輸出手段
  • 邏輯控制
    • switch跟常見的用法相同
    • if 跟常見的用法相同,如果執行句只有一行也可以不使用{}
  • 迴圈控制
    • for跟常見的用法相同
    • while跟常見的用法相同
  • 方法定義
    • 靜態型別的語言,必須事先定義好輸入值與輸出值的型別
    • 沒有宣告用的關鍵字

雖然Dart是前端語言,但實際上要作為後端也是可行的
如同我們今天寫的終端機執行程式

但真正要發揮Dart的語言特性還是必須要配合Flutter
雖然相較於火熱的React Native,起步晚了兩年的Flutter不管在使用人數上還是library的數量上都少了許多
但是從Java或是C++轉過來的人在學習上並不會困難,因此也能當作後端工程師的前端備選語言

而且在flutter的youtube頻道上還算活躍
又有google這個靠山在
算是值得期待的語言

語言結算

明天,我們來做這十五種語言的總結吧


上一篇
Kotlin google為了防背刺而留的一手
下一篇
語言的比較
系列文
你會十五種程式語言?不,我會十五種HelloWorld.為了避免這種狀況,因此寫了這篇:淺入淺出十五種程式語言30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
skycover
iT邦新手 4 級 ‧ 2020-09-24 21:01:57

如果有任何寫不清楚或是觀念沒有很明白的話請留言告知我
會盡快補上

如果有任何寫錯的地方也麻煩留言告知我
會盡快修正

感謝各位

geomm iT邦新手 4 級 ‧ 2021-10-01 10:47:59 檢舉

以我用了 ReactNative 半年以及 Flutter 2 年的經驗, 我只能說, ReactNative 呼叫底層模組 Debug 的效能真是讓人欲哭無淚 (也許現在有改變, 但是 FB 的開發文件真的是....). 所以 Flutter 出來我就跳船了.

Flutter 生態系跟 React 比起來當然還是差很多, 但是需要大量與底層整合的工作, Flutter 給我的體驗比 React Native 好太多了. 也許 UI Debug 比較不順手, 但是我的經驗是 Flutter 在 UI 能做的不會輸給 JS.

至於 Dart, 我覺得是一個實用性很高的語言, 有夠用的物件導向與泛型實作. 也有現代語言的簡潔. 雖然不是100分但是也有87分.

好有說服力@@我信你了

我要留言

立即登入留言