Category: LẬP TRÌNH

  • Kiểu null trong Dart

    Kiểu null trong Dart

    Kiểu null trong Dart là một đối tượng đặc biệt dùng để biểu thị cho một đối tượng rỗng, trống, không chứa gì.

    Trước phiên bản 2.0 thì khi tạo mới một biến, Dart sẽ gán giá trị mặc định cho biến đó là null, nếu không được cung cấp.

    Từ phiên bản 2.0 trở đi thì Dart hỗ trợ tính năng null safety, do đó bạn cần cung cấp cho biến một giá trị trước khi sử dụng biến đó, nếu không Dart sẽ cảnh báo ngay trong khi soạn thảo mà không cần đợi đến khi biên dịch chương trình. Chi tiết, xin mời xem trong bài 🎯 Null safety Dart / Null safety Flutter là gì?

    Có một số toán tử đặc biệt làm việc với giá trị null??!

  • Kiểu logic bool trong Dart

    Kiểu logic bool trong Dart

    Kiểu logic bool trong Dart

    Kiểu logic bool trong Dart (kiểu Boolean) sử dụng từ khóa bool để khai báo.

    Kiểu dữ liệu bool trong Dart có 2 giá trị là true (đúng) và false (sai) được sử dụng để thể hiện kết quả của một mệnh đề logic (các phép toán so sánh, kiểm tra, các hàm…)

    void main() {
     
      print(1 > 2);// kết quả false
      print((1/0).isInfinite);// kết quả true
    
      var s = ''; 
      print(s.isEmpty);// kết quả true
    
      print(true & false); // kết quả false
      print(true | false); // kết quả false
      print(!true); // kết quả false
    }

    Trong Dart, giá trị 1 hoặc 0 không được sử dụng để thay thế truefalse như trong các ngôn ngữ khác.

    Các phép toán trên kiểu bool trong Dart gồm có and &, or | và not !. Bạn có thể xem chi tiết ở bài Các phép toán trong Dart (Toán tử Dart/Flutter)

    toan tu bool trong Python Toán tử Boolean trong Python

  • Deploy Flutter web app to Firebase Hosting

    Deploy Flutter web app to Firebase Hosting

    Step 1: Create a project on Firebase console
    Step 2: Download Firebase CLI from here  Firebase CLI binary for Windows.
    Step 3: Login via CLI, execute the command firebase login

    Deploy Flutter web app to Firebase Hosting 1

    Step 4: Choose Firebase “Hosting” for Flutter web app when asked for a feature

    Deploy Flutter web app to Firebase Hosting 2

    Step 5: Then, Select an existing Project

    Deploy Flutter web app to Firebase Hosting 3

    Step 6: Choose build/web as a directory & configure as a single-page app

    Deploy Flutter web app to Firebase Hosting 4

    If you see, File build/web/index.html already exists. Overwrite?
    Then select NO. So it will not generate a default index.html file

    Step 7: Deploy Flutter web to Firebase!

    firebase deploy
    Deploy Flutter web app to Firebase Hosting 5
  • Kiểu enum trong Dart là gì?

    Kiểu enum trong Dart là gì?

    Kiểu enum trong Dart là gì?

    Kiểu enum trong Dart còn gọi là kiểu liệt kê (kiểu liệt kê thứ tự enumerated) được sử dụng để liệt kê các giá trị hằng số. Kiểu liệt kê được khai báo bằng cách sử dụng từ khóa enum. Kiểu liệt kê enum cũng là một kiểu iterable, tức là cũng có thể duyệt tuần tự qua từng phần tử của nó.

    enum HoaQua { Apple, Pear, Grapes, Banana, Orange }
    void main() {
      HoaQua liked = HoaQua.Apple;
      var disliked = HoaQua.Banana;
      print(liked.toString()); // kết quả 'HoaQua.Apple'
      print(disliked.toString()); // kết quả 'HoaQua.Banana'
    }
    

    Mỗi phần tử của một enum được gán với một con số, gọi là index, tương ứng với vị trí của phần tử đó trong enum bắt đầu từ số 0.

    enum HoaQua { Apple, Pear, Grapes, Banana, Orange }
    void main() {
      print(HoaQua.Apple.index); //kết quả 0
      print(HoaQua.Banana.index); //kết quả 3
    }

    Duyệt qua các giá trị của enum trong Dart

    Để duyệt qua các giá trị của enum, chúng ta sử dụng phương thức values thì sẽ trả về một List các phần tử của enum. Khi đó, kết hợp với phương thức forEach của Kiểu danh sách List trong Dart để duyệt qua các giá trị này.

    enum HoaQua { Apple, Pear, Grapes, Banana, Orange }
    void main() {  
      print(HoaQua.values);
      HoaQua.values.forEach((v) => print('value: $v, index: ${v.index}'));
    }

    Chạy chương trình trên, được kết quả như hình sau:

    kiểu enum trong dart

     

  • Iterator trong Dart là gì?

    Iterator trong Dart là gì?

    Iterator trong Dart là gì?

    Iterator trong Dart là một tập hợp các giá trị, hoặc “phần tử”, có thể được truy cập tuần tự. Nói cách khác lớp Iterator bao gồm các đối tượng có thể duyệt (Iterable) tuần tự, tức là cho phép ta lấy từng phần tử của nó, hành động này có thể được lặp đi lặp lại. Ví dụ, ListSet đều là các Iterable

    Iterator/ Iterable có thể hiểu nôm na là kiểu “liệt kê”, sử dụng để liệt kê tuần tự các phần tử.

    iterator trong dart, iterable trong dart

    Trong Dart, một Iterator/Iterable là một lớp trừu tượng, có nghĩa là bạn không thể khởi tạo trực tiếp nó. Tuy nhiên, bạn có thể tạo mới Iterable bằng cách tạo mới một danh sáchListhoặc tập hợp Set.

    void main() {
      var iterable = ['Salad', 'Popcorn', 'Toast'];
      for (var element in iterable) {
        print(element);
      }
    }
    

    Trong ví dụ trên thì biến iterable chính là một List, chúng ta sử dụng từ khóa var nên Dart sẽ tự nhận dạng kiểu dữ liệu cho chúng ta. Để tạo một Iterator, chúng ta chỉ có cách sử dụng phương thức iterator đối với các biến thuộc kiểu List, Set

    Truy cập các phần tử của lớp Iterator

    Với lớp Iterator, bạn không thể truy cập trực tiếp các phần tử như lớp List mà phải lần lượt duyệt qua tất cả các phần tử phía trước. Thay vào đó, bạn có thể đọc các phần tử với elementAt() bằng cách duyệt lần lượt qua các phần tử của nó cho đến khi nó đạt đến vị trí đó.

    Chính vì lí do đó, bạn không thể gọi iterable[0] để truy cập phần tử đầu tiên của biến iterable mà phải sử dụng thuộc tính first, lấy phần tử đầu tiên. Tương tự, bạn không thể sử dụng toán tử [] để truy cập phần tử cuối cùng, nhưng bạn có thể sử dụng thuộc tính last.

    void main() {
    
      Iterable numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];  
      int value = numbers.elementAt(3);
      print(value); //kết quả 3
      print('The first value is ${numbers.first}');//kết quả 0
      print('The last value is ${numbers.last}');//kết quả 10
    }

    Lưu ý, việc truy cập phần tử cuối cùng của một Iterator yêu cầu phải duyệt qua tất cả các phần tử khác nên có thể rất chậm.

    Để duyệt qua các phần tử của một Iterator, bạn có thể sử dụng vòng lặp for.

    Các thuộc tính và phương thức của kiểu Iterator trong Dart

    • current trả về phần tử hiện tại của một Iterator
    • moveNext() trả về true nếu phần tử hiện tại chưa phải phần tử cuối cùng đồng thời đặt phần tử current là phần tử tiếp theo, trả về false nếu phần tử hiện tại đang là phần tử cuối cùng của một Iterator và đặt iterator.currrent = null
    • firstWhere()để tìm phần tử đầu tiên thỏa mãn các điều kiện nhất định
    • singleWhere()có thể giúp bạn tìm một phần tử thỏa mãn một vị từ nhất định
    • where()sử dụng để tìm tất cả các phần tử thỏa mãn một điều kiện nào đó
    • any(): Trả về true nếu có ít nhất một phần tử thỏa mãn điều kiện.
    • every(): Trả về true nếu tất cả các phần tử thỏa mãn điều kiện.

    Duyệt qua các phần tử của List bằng vòng lặp for

    void main(){
        //list
        var myList = [25, 63, 84];
         
        //traverse through each element of list
        for(var i=0;i<myList.length;i++){
            print(myList[i]);
        }
    }

    hoặc sử dụng phương thức forEach() của kiểu List

    void main(){
        var myList = [24, 63, 84];
         
        myList.forEach((element) => 
            print(element)
        );
    }

    hoặc chuyển List sang Iterator và sử dụng vòng lặp while

    void main(){
        //list
        var myList = [25, 63, 84];
         
        //get iterator to the list
        var myListIter = myList.iterator;
         
        //iterate over the list
        while(myListIter.moveNext()){
            print(myListIter.current);
        }
    }

    Kiểu Map không phải là một đối tượng Iterable, tuy nhiên bạn có thể duyệt qua từng phần tử của Map bằng các sử dụng thuộc tính keyvalue của nó.

    void main() {
    
      Map kidsBooks = {
        'Matilda': 'Roald Dahl',
        'Green Eggs and Ham': 'Dr Seuss',
        'Where the Wild Things Are': 'Maurice Sendak'
      };
      for (var book in kidsBooks.keys) {
        print('$book was written by ${kidsBooks[book]}');
      }
    }

    Khi chạy chương trình, chúng ta được kết quả như hình sau:

    Iterator trong Dart là gì? 6

    Bạn có thể xem thêm tại https://dart.dev/codelabs/iterables

  • Kiểu xâu String trong Dart/Flutter

    Kiểu xâu String trong Dart/Flutter

    Kiểu xâu String trong Dart/Flutter

    Kiểu xâu String trong Dart là một trong những kiểu dữ liệu cơ bản (built in type) cùng với kiểu số (số nguyên int, số thực double) và các kiểu tập hợp set, kiểu danh sách List

    1. Kiểu xâu String là gì?

    Kiểu String trong Dart sử dụng để biểu diễn chuỗi ký tự Unicode(UTF-16) (bạn có thể sử dụng các xâu có kí tự tiếng Việt hoặc bất cứ thứ tiếng nào mà sử dụng được với mã Unicode.

    Để khai báo/sử dụng một xâu (từ giờ chúng tôi sẽ gọi trực tiếp là String) chúng ta sử dụng cách khai báo như trong bài Biến và các kiểu dữ liệu trong Dart, và đặt String đó trong cặp dấu nháy đơn ' hoặc cặp dấu nháy kép "Ví dụ 'Phan Văn Phương' hoặc  "là người đẹp trai nhất thế giới"

    Theo gợi ý của Visual Studio Code, thì chúng ta nên sử dụng cặp dấu nháy đơn ' để bao nội dung của một String.

    Nếu của String của bạn gồm nhiều dòng, có thể đặt chúng trong cặp nháy tam '''(gồm 3 dấu nháy đơn ') hoặc """ (gồm 3 dấu nháy kép "), ví dụ:

    xau1 = '''đây là một String
    nằm 
    trên
    nhiều dòng''';
    
    xau2 = """mùa xuân sang có hoa anh đào
    blah blah...
    tôi là một con gà""";
    
    

    2. Truy cập đến từng kí tự của String

    Các kí tự của một String đều được đánh chỉ số từ 0 cho đến n-1, với n là độ dài của String và được truy cập qua thuộc tính length

    void main() {
      String viDu = 'abcdef';
      print(viDu.length); //kết quả 6
      print(viDu[2]); //kết quả 'c'
    }

    Kiểu String là một kiểu dữ liệu immutable, tức là kiểu dữ liệu không thể thay đổi. Do đó, các phép gán làm thay đổi nội dung của String đều không hợp lệ. Chẳng hạn với xâu viDu ở trên, nếu bạn cố tình gán viDu[2] = '3' thì Dart sẽ rủa cho bạn một trận 🙂

    Tuy nhiên, bạn có thể sử dụng nhiều phương thức (method) trên một String như nối, tách, cắt khoảng trống… của một String, vì khi đó thực ra String ban đầu không thay đổi mà kết quả của các phương thức này được gán vào một String mới!

    void main() {
      String viDu = '  ab  cdef    ';
      viDu.trim();
      print(viDu);//kết quả vẫn là '  ab  cdef    '
      print(viDu.trim());//kết quả là 'ab  cdef'
    }

    3. Các kí tự đặc biệt của một String

    • Để viết một kí tự nháy đơn ' bạn có thể bao trong một String sử dụng cặp ngoặc nháy kép " và ngược lại, ví dụ
    void main() {  
      print("đây là dấu nháy đơn ' này");
      print('còn đây là dấu nháy kép "');
    }
    • Hoặc sử dụng kí tự thoát \ (string escape) cùng với các dấu nháy đó, cách này có thể sử dụng cho cả các kí tự khác như \ $
    void main() {
      print('in các kí tự ~!@#%^&*() dễ oẹt');//in các kí tự ~!@#%^&*() dễ oẹt
      print('các kí tự đặc biệt: \' $ \\');//các kí tự đặc biệt: ' $ \
      print('còn đây là kí tự xuống \n dòng');
    }
    • Kí tự xuống dòng \n
    • Kí tự tab \t
    • Kí tự xóa kí tự liền trước \b
    • Kí tự trở về đầu của xâu \r
    void main() {
      print('nu na nu nống\n cái cống nằm trong\ncon ong nằm ngoài\b\b\b\rủ khoai chấm\tmật');
    }
    

    Khi chạy chương trình, chúng ta thu được kết quả như sau:

    kiểu xâu string trong dart flutter

    4. Các thuộc tính và phương thức của kiểu xâu String trong Dart

    Lưu ý rằng kiểu xâu String trong Dart là immutable, nên các phương thức sau đều trả về một xâu mới, còn xâu ban đầu thì không hề thay đổi.

    4.0. Các thuộc tính của kiểu xâu String trong Dart

    • length cho độ dài của xâu
    • isEmpty kiểm tra xem một String có là xâu rỗng hay không
    • isNotEmpty kiểm tra xem một String có khác xâu rỗng hay không

    4.1. Xâu con trong Dart

    Sử dụng phương thức subString(i,j) để lấy ra một xâu con từ chỉ số i tới chỉ số j-1 của xâu đã cho.

    void main() {
      String xauMe = 'abcdefgh';
      String xauCon = xauMe.substring(2,5);
      print(xauCon);//kết quả 'cde'
    }
    
    • indexOf(Pattern pattern,[int start = 0]) trả về số nguyên là vị trí index xuất hiện đầu tiên của pattern ở trong xâu, bắt đầu tìm từ vị trí start (mặc định là 0, tức tìm từ đầu xâu), nếu không tìm thấy thì trả về -1
    void main(){
      var string = 'Dartisans';
      string.indexOf('art');                 //kết quả 1
      string.indexOf(RegExp(r'[A-Z][a-z]')); //kết quả 0
      string.indexOf(RegExp(r'dart'));       //kết quả  -1
    }
    • lastIndexOf(Pattern pattern,[int? start]) tương tự như trên nhưng là vị trí xuất hiện cuối cùng của pattern
    void main(){
      var string = 'Dartisans';
      string.lastIndexOf('a');                    //kết quả  6
      string.lastIndexOf(RegExp(r'a(r|n)'));      //kết quả 6
      string.lastIndexOf(RegExp(r'DART'));        //kết quả -1
    }

    4.2. Các phương thức kiểm tra xâu con

    • startsWith(String other) kiểm tra xem xâu có bắt đầu bằng xâu other hay không.
    • endsWith(String other) kiểm tra xem xâu có kết thúc bằng xâu other hay không.
    • contains(Pattern other,[int startIndex = 0]) dùng để kiểm tra một xâu có chứa other hay không, bắt đầu từ kí tự index, mặc định bằng 0. Kết quả trả về là true nếu tìm thấy và false nếu không tìm thấy. Ở đây other có thể là một xâu, một kí tự hoặc một biểu thức chính quy regex

    4.3. Chuyển đổi sang chữ hoa, chữ thường

    • toLowerCase() trả về một xâu mới dạng chữ thường của xâu ban đầu
    • toUpperCase() trả về một xâu mới dạng chữ HOA của xâu ban đầu

    4.4. Cắt khoảng trắng

    • trim() dùng để cắt các khoảng trắng (cấu cách, dấu tab, kí tự xuống dòng) ở 2 đầu của xâu
    • trimLef()trimRight() dùng để cắt các khoảng trắng (cấu cách, dấu tab, kí tự xuống dòng) ở đầu bên trái, đầu bên phải của xâu
    void main() {
      String str1 = ' \n \t Mua Xuan sang co hoa anh dao\n   ';
      print('|' + str1.trim() + '|');
      print('|' + str1.trimRight() + '|');
      print('|' + str1.trimLeft() + '|');
      print('|' + str1 + '|');
    }

    4.5. Nối hai xâu trong Dart

    Bạn có thể sử dụng toán tử + để nối hai xâu String trong Dart.

    void main() {
      String str1 = 'Xuân Hạ Thu Đông';
      String str2 = '... Rồi Lại Xuân';
      print(str1 + str2);//kết quả 'Xuân Hạ Thu Đông... Rồi Lại Xuân'
    }

    4.6. Tách một xâu trong Dart

    Sử dụng phương thức split(kí_tự_tách) để tách một String thành các xâu con, ngăn cách nhau bởi kí_tự_tách

    void main() {
      var text = "mùa xuân sang có hoa anh đào";
    
      var parts = text.split(' ');
      print(parts);
    
      print(text);
    }

    4.7. Thay thế xâu con

    Sử dụng phương thức replaceAll(s, t) để thay thế tất cả các xâu con s bởi xâu t trong xâu ban đầu. Đương nhiên, kết quả trả về là một xâu mới.

    void main() {
      String str1 = 'Mua Xuan sang co hoa anh dao';
      print(str1.replaceAll('Xuan', 'Dong'));//kết quả 'Mua Dong sang co hoa anh dao'
      print(str1); //vẫn là 'Mua Xuan sang co hoa anh dao'
    }

    4.8. Chuyển số sang xâu

    Bạn sử dụng hàm toString() đối với các đối tượng kiểu số (xem chi tiết trong bài Kiểu số trong Dart/Flutter)

    5. Duyệt qua các kí tự của String

    Phương thức runes trả về một Iterable gồm các mã Unicode của từng kí tự trong xâu. Kết hợp phương thức runes với vòng lặp for, chúng ta có thể duyệt qua từng kí tự của xâu.

    void main() {
      var word = 'abcdefgh';
    
      print(word.runes); //kết quả (97, 98, 99, 100, 101, 102, 103, 104)
      for (var c in word.runes) {
        print(String.fromCharCode(c));
      }
    
      for (var c in word.runes) {
        print(c);
      }
    }

    6. Nội suy chuỗi (String Interpolation)

    Sử dụng kí tự $ để nội suy nội dung của một xâu.

    void main() {
      int a = 5;
      int b = 7;
    
      String ketQua = "Tổng của $a và $b là ${a + b}";
      print(ketQua); //Tổng của 5 và 7 là 12
    }
    
  • Kiểu danh sách List trong Dart

    Kiểu danh sách List trong Dart

    Kiểu danh sách List trong Dart

    Kiểu dữ liệu danh sách List trong Dart được sử dụng để biểu diễn cho một tập hợp các đối tượng theo một thứ tự nhất định. Kiểu danh sách List trong Dart tương đương với kiểu mảng Array trong các ngôn ngữ khác (Python chẳng hạn).

    Một List là một nhóm có thứ tự các đối tượng. Một List sử dụng để chứa nhiều đối tượng / giá trị – ta gọi chung là phần tử – trong một biến duy nhất.

    1. Khai báo một danh sách List trong Python

    var monAn = ['cơm', 'canh', 'cà', 'cá'];
    
    List<String> hoaQua = ['nho', 'táo', 'cam', 'bưởi', 'sầu riêng'];
    monAn.length; //kết quả 4
    hoaQua.length; //kết quả 5
    • Để truy cập đến một phần tử của List danh_sách, chúng ta dùng cú pháp danh_sách[index] với index là chỉ mục của phần tử đó trong danh_sách. Ví dụ với List monAn ở trên, thì phần tử có index 1 là 'canh'
    monAn[1]; //kết quả 'canh'
    
    hoaQua[0]; //kết quả 'nho'
    • Để truy cập đến nhiều phần tử liên tiếp nhau của List, chúng ta dùng cú pháp

    tenDanhSach.sublist(i,j)

    trong đó i là chỉ số của phần tử đầu tiên, j là chỉ số của phần tử cuối cùng cần lấy ra tính từ đầu List. Nếu muốn lấy từ phần tử từ chỉ số i đến cuối danh sách, chúng ta dùng tenDanhSach.sublist(i,)

    • Tuy nhiên, chúng ta ưu tiên cách khai báo sử dụng từ khóa var vì tính ngắn gọn của nó.

    2. Các loại danh sách List trong Dart

    Trong Dart, danh sách List có thể được phân loại thành:

    • Danh sách độ dài cố định
    • Danh sách có thể mở rộng

    Danh sách độ dài cố định (Fixed Length List)

    • Một đối tượng List trong Dart có thể được khai báo với kích thước cố định, không thể thay đổi bằng cú pháp:

    var list_name = List(size);

    • Một danh sách được khai báo không có kích thước/độ dài cụ thể được gọi là Danh sách có thể phát triển (Growable List). Độ dài của danh sách có thể phát triển có thể thay đổi trong thời gian chạy.
    • Cách khai báo một List có độ dài có thể phát triển như ở phần 1.

    3. Các thuộc tính của kiểu List trong Dart

    Dưới đây là danh sách các thuộc tính được hỗ trợ bởi Dart List.

    Thuộc tính Ý nghĩa
    first Trả về phần tử đầu tiên của List.
    isEmpty Trả về true nếu List là rỗng (không có phần tử nào).
    isNotEmpty Trả về true nếu List có ít nhất một phần tử.
    length Trả về độ dài / kích thước của List, đây chính là số phần tử trong List.
    last Trả về phần tử cuối cùng trong List.
    contains(phần_tử) Kiểm tra xem List có chứa phần_tử hay không.
    reversed Trả về một Iterable  chứa các phần tử của List ban đầu nhưng theo thứ tự ngược lại.
    Single Được sử dụng để kiểm tra xem danh sách có phải chỉ có một phần tử không và trả về phần tử đó.

    Ví dụ.

    void main() {
      var khaiVi = ['súp', 'gỏi tôm', 'sò huyết', 'sườn', 'thịt nguội' ];
      
      print(khaiVi.first); //súp
      print(khaiVi.last); //thịt nguội
      print(khaiVi.isEmpty); //false
      print(khaiVi.reversed); //(thịt nguội, sườn, sò huyết, gỏi tôm, súp)
    }

    4. Các phương thức của kiểu danh sách List trong Dart

    4.1. Chèn các phần tử vào danh sách

    • add()Hàmadd(phần_tử) được sử dụng để nối  thêm một phần_tử vào cuối một List và trả về List mới này.
    • addAll() Hàm addAll(các_phần_tử) được sử dụng để thêm nhiều phần tử vào một List, các_phần_tử được phân tách bằng dấu phẩy và được đặt trong dấu ngoặc vuông []. Bạn hình dung hàm addAll() chính là nối thêm một danh sách khác vào danh sách đang có.
    • insert() Hàm insert(index, phần_tử) dùng để chèn thêm một phần_tửtử vào vị trí index xác định.
    void main() {
      var evenList = [2, 10];
      print(evenList);
      evenList.insertAll(1, [4, 6, 8]);
      print(evenList);
    }

    4.2. Cập nhật danh sách

    • Cách đơn giản nhất một phần tử danh sách có thể được sửa đổi bằng cách truy cập phần tử và gán giá trị mới cho phần tử đó.

    tenDanhSach[index] = giá_trị_mới;

    void main() {
      var evenList = [2, 4, 5, 8, 10];
      print("Danh sách trước khi cập nhật ${evenList}");
      evenList[2] = 6;
      print("Danh sách sau khi cập nhật ${evenList}");
    }
    • replaceRange() Hàm replaceRange(i,j,các_giá_trị_mới) được sử dụng để cập nhật một loạt các phần tử của danh sách từ vị trí chỉ mục i tới vị trí j-1 bởi các_giá_trị_mới.

    4.3. Xóa các phần tử danh sách

    • remove() Hàm remove(phần_tử) dùng để xóa một phần_tử xuất hiện đầu tiên tính từ đầu danh sách khỏi danh sách đó. Kết quả trả về là true nếu phần_tử bị xóa khỏi danh sách.
    void main() {
      var evenList = [2, 4, 6, 8, 10, 6, 12];
      print("Danh sách trước khi xóa ${evenList}");
      evenList.removeRange(2,3);
      print("Danh sách sau khi xóa ${evenList}"); //[2, 4, 8, 10, 6, 12]
    }

    5. Các phương thức nâng cao của List

    5.1. Duyệt các phần tử của List trong Dart

    Trong Dart, chúng ta có thể duyệt tuần tự qua các phần tử danh sách bằng phương thức forEach như sau:

    void main() {
      var list = ["Xuân", "Hạ", "Thu", "Đông"];
      list.forEach((item) {
        print('$item');
      });
    }

    5.2. Sắp xếp các phần tử trong List

    Sử dụng phương thức sort. Bạn có thể đọc thêm về hàm này tại đây https://api.dart.dev/stable/2.12.2/dart-core/dart-core-library.html

    void main() {
      var khaiVi = ['súp', 'gỏi tôm', 'sò huyết', 'sườn', 'thịt nguội' ];
      
      khaiVi.sort();
      print(khaiVi);//[gỏi tôm, sò huyết, súp, sườn, thịt nguội]
    }

    5.3. Hàm map

    Hàm map(f(e)) → Iterable dùng để ánh xạ mỗi phần tử e của List qua hàm f thành phần tử f(e) của một Iterable mới.

    void main() {
      var soChan = [0, 2, 4, 6, 8, 10];
    
      print(soChan.map((i) => i +1)); //kết quả (1, 3, 5, 7, 9, 11)
    }
    

    5.4. Hàm every

    Hàm every(bool f(E element)) sử dụng để kiểm tra xem mọi phần tử element của E có thỏa mãn hàm f hay không.

    void main() {
      var soChan = [0, 2, 4, 6, 8, 10];
      var soLe = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    
      print(soChan.every((i) => i % 2 == 0)); //true
      print(soLe.every((i) => i.isOdd)); //false
    }

    6. Danh sách của danh sách trong Dart

    Vì Dart không hỗ trợ kiểu mảng 2 chiều nên chúng ta phải sử dụng danh sách của danh sách. Tức là mỗi phần tử của List lại là một List khác.

    void main() {
      var khaiVi = ['súp', 'gỏi tôm', 'sò huyết', 'sườn', 'thịt nguội' ];
      var monChinh = ['tôm hùm', 'cua hoàng đế', 'nem công', 'chả phượng'];
      var trangMieng = ['bánh chuối', 'chè sen', 'bánh cuộn', 'bánh nếp'];
      var monAn = [khaiVi, monChinh, trangMieng];
      print(monAn);
    }

    Khi đó, để truy cập đến một phần tử cụ thể của danh sách, chúng ta dùng cú pháp

    tenDanhSach[i][j]

    Ví dụ, monAn[1] sẽ trả về danh sách ['tôm hùm', 'cua hoàng đế', 'nem công', 'chả phượng'] còn monAn[1][2] sẽ trả về phần tử 'nem công'

    Xem tài liệu về kiểu List đầy đủ nhất tại https://api.dart.dev/stable/2.10.5/dart-core/List-class.html

  • Kiểu số trong Dart/Flutter

    Kiểu số trong Dart/Flutter

    Kiểu số trong Dart/Flutter

    Kiểu số trong Dart/Flutter bao gồm 2 loại:

    • int Kiểu số nguyên. Tùy thuộc vào bộ nhớ máy, nền tảng máy (32 bit hay 64 bit) mà kiểu số nguyên trong Dart có giá trị từ -2^63 đến 2^63 - 1. Ngoài kiểu số nguyên int, trong Dart còn có kiểu số nguyên BigInt để làm việc với các số nguyên lớn.
    • doubleKiểu số thực. Các phiên bản cũ của Dart thì kiểu số thực bắt buộc phải có dấu . chẳng hạn để khai báo biến số thực a có giá trị 3 chúng ta phải viết rõ double a = 3.0Tuy nhiên các phiên bản hiện nay đã bỏ phần dấu . này đi, bạn có thể khai báo double a = 3

    Từ phiên bản 2.0 trở đi thì khi khai báo biến kiểu số, Dart không gán giá trị mặc định null nữa, mà bạn phải gán giá trị thuộc kiểu phù hợp cho biến trước khi sử dụng biến đó. (Xem thêm trong bài Null safety Dart / Null safety Flutter là gì?)

    Cả hai kiểu số nguyên int và kiểu số thực double đều là subclasses (lớp con) của lớp num. Bạn nên sử dụng một trong hai kiểu int hoặc double thay vì kiểu num.

    Kiểu số thực có thể viết dưới dạng kí pháp khoa học, ví dụ 1.35e2 tương đương với 1.35*10^2

    Các phép toán trên kiểu số nguyên int và kiểu số thực double trong Dart/Flutter

    Chi tiết về các phép toán (toán tử) xin mời bạn xem trong bài Các phép toán trong Dart (Toán tử Dart/Flutter)

    • +- * / Các phép toán cộng, trừ, nhân, chia thông thường
    • ~/ Phép chia lấy phần nguyên (tương tự như phép toán div trong các ngôn ngữ khác)
    • % Phép chia lấy số dư (tương tự như phép toán mod trong các ngôn ngữ lập trình khác)

    Các phương thức và thuộc tính của kiểu số trong Dart / Flutter

    • isNaN để kiểm tra xem một biểu thức có không phải là số hay không. Ví dụ, phép chia 0/0 trả về kết quả NaN
    • isFinite kiểm tra một số có là số hữu hạn hay không
    • isInfinite kiểm tra một số có phải dương vô cùng không, ví dụ phép chia 1/0 trả về kết quả dương vô cùng
    • abs()trả về giá trị tuyệt đối của một số, ví dụ (-15.3).abs() cho kết quả 15.3
    • ceil()trả về số nguyên nhỏ nhất không nhỏ hơn số đó (làm tròn lên), ví dụ (-15.3).ceil() cho kết quả -15, 15.2.ceil() cho kết quả 16
    • floor() trả về số nguyên lớn nhất không lớn hơn số đó (làm tròn xuống), ví dụ (-15.3).floor() cho kết quả -1615.2.ceil() cho kết quả 15

    Để dễ hình dung về hàm ceil()floor(), bạn tưởng tượng mỗi số thực x sẽ bị chặn trên và dưới bởi hai số nguyên ab, nghĩa là a <= x <= b thì số nguyên a được gọi là x.floor() còn số nguyên b được gọi là là x.ceil()

    • round() làm tròn số đến số nguyên gần nhất
    • isEven, isOdd kiểm tra một số nguyên là chẵn (even) hay lẻ (odd)
    • isNegative() kiểm tra xem một số có là số âm hay không
    • sign thuộc tính dấu của một số, trả về -1 nếu số đó âm, trả về 1 nếu số đó dương

    Chuyển đổi số sang xâu trong Dart

    Để chuyển đổi số sang xâu trong Dart, chuyển đổi xâu sang số,  chúng ta sử dụng hai phương thức quen thuộc sau:

    • parse(String source) dùng để chuyển đổi một source có kiểu chuỗi String sang kiểu số.
      Đối với kiểu số nguyên int thì phương thức int.parse(String source) còn có thêm tham số tùy chọn radix cho biết cơ số của số cần chuyển, ví dụ int.parse("111", radix:2) cho kết quả 7 (vì số 111 trong hệ nhị phân có giá trị 7 trong hệ thập phân). Khi không cung cấp giá trị thì tham số radix nhận giá trị mặc định là 10, tức là xâu cần chuyển được viết ở dạng số thập phân.

    Đối với kiểu số thực double thì phương thức double.parse(String source) chấp nhận source có dạng sau:

    "3.14"
    " 3.14 \xA0"
    "0."
    ".0"
    "-1.e3"
    "1234E+7"
    void main() {
      int? a; 
      double b = 0;
      num? c;
    
      a = int.parse("111", radix:2);//kết quả 7
      print(a);
    
      a = int.parse('001');
      print(a);
      print(a.runtimeType); //kết quả int
    
      b = double.parse('.0314');
      print(b);//kết quả 0.0314
      print(b.runtimeType); //kết quả double
    
      c = num.parse('0x22');//số 22 trong hệ hexa (cơ số 16)
      print(c);//kết quả 34
      print(c.runtimeType);//kết quả int
    }
    • toString() sử dụng để chuyển một số sang xâu String
    void main() {
      num? c;
      
      print(3.14.toString());//kết quả '3.14'
      c = num.parse('0x22');//số 22 trong hệ hexa (cơ số 16)  
      print(c.toString());//kết quả '34'
    }

    Để chuyển số thực sang xâu (double to String) chúng ta còn có hai phương thức nữa:

    • toStringAsFixed(n) chuyển đổi một số thực sang xâu với n chữ số sau dấu phảy
    1.toStringAsFixed(3);  // 1.000
    (4321.12345678).toStringAsFixed(3);  // 4321.123
    (4321.12345678).toStringAsFixed(5);  // 4321.12346
    123456789012345.toStringAsFixed(3);  // 123456789012345.000
    10000000000000000.toStringAsFixed(4); // 10000000000000000.0000
    5.25.toStringAsFixed(0); // 5
    • toStringAsPrecision(n) với độ chính xác đến n chữ số (n chữ số có nghĩa)
    1.toStringAsPrecision(2);       // 1.0
    1e15.toStringAsPrecision(3);    // 1.00e+15
    1234567.toStringAsPrecision(3); // 1.23e+6
    1234567.toStringAsPrecision(9); // 1234567.00
    12345678901234567890.toStringAsPrecision(20); // 12345678901234567168
    12345678901234567890.toStringAsPrecision(14); // 1.2345678901235e+19
    0.00000012345.toStringAsPrecision(15); // 1.23450000000000e-7
    0.0000012345.toStringAsPrecision(15);  // 0.00000123450000000000
  • Các phép toán trong Dart (Toán tử Dart/Flutter)

    Các phép toán trong Dart (Toán tử Dart/Flutter)

    Các phép toán trong Dart (Toán tử Dart/Flutter)

    Các phép toán trong Dart (các toán tử trong Dart) chính là các phương thức method được định nghĩa trong các lớp với một cú pháp đặc biệt. Chẳng hạn, khi bạn sử dụng các toán tử như x == y, thì cũng chính là bạn đang gọi phương thức x. == (y) để so sánh đẳng thức.

    các phép toán trong dart flutter, toán tử trong dart

    Các phép toán trong Dart gồm có các loại sau:

    • Toán tử số học
    • Toán tử tăng và giảm
    • Toán tử so sánh
    • Toán tử logic
    • Toán tử thao trên bit
    • Toán tử null safety

    Toán tử số học trong Dart

    Toán tử số học có tác dụng đối với kiểu dữ liệu số nguyên int, số thực double và kiểu số num nói chung.

    • + Phép cộng. Ví dụ 3 + 1 kết quả 4
    • - Phép trừ. Ví dụ 5 - 6 kết quả -1
    • * Phép nhân. Ví dụ 3 * 3 kết quả 9
    • / Phép chia. Ví dụ 5 / 6 kết quả 0.8333333333333334
    • ~/ Phép chia lấy phần nguyên (tương tự phép toán div trong các ngôn ngữ khác). Ví dụ 6 ~/ 4 kết quả 1
    • % Phép chia modulo (lấy phần dư, tương tự phép toán mod trong các ngôn ngữ khác). Ví dụ 6 % 4 kết quả 2
    • -(biểu_thức) Đổi dấu kết quả của biểu_thức. Ví dụ -(5 - 6) cho kết quả 1

    Toán tử tăng và giảm trong Dart

    • ++var
      • Tăng giá trị của biến var lên 1, tương đương với phép gánvar = var + 1 hoặc var +=1.
      • Tuy nhiên, toán tử ++ có thể đặt trong các biểu thức tính toán, khi đó việc tăng giá trị này được tiến hành trước khi thực hiện tính toán biểu thức. Ví dụ sau thì biểu thức b+(++a) có giá trị 16
    void main() {   
      int a = 5;
      int b = 10;
      print(b +(++a)); //cho kết quả 16
      print(a); //a vẫn có giá trị 6
    }
    • var++
      • Tăng giá trị của biến var lên 1, tương đương với phép gánvar = var + 1 hoặc var +=1.
      • Tuy nhiên, toán tử ++ có thể đặt trong các biểu thức tính toán, khi đó việc tăng giá trị này được tiến hành sau khi thực hiện biểu thức. Ví dụ sau thì biểu thức b+(a++) có giá trị 15 dù sau đó biến a vẫn được tăng thêm 1 thành giá trị 6.
    void main() {   
      int a = 5;
      int b = 10;
      print(b +(a++)); //cho kết quả 15
      print(a);//a vẫn có giá trị 6
    }
    • --var Tương tự ++var nhưng là giảm đi 1.
    • var-- Tương tự var++ nhưng là giảm đi 1.

    Phép gán trong Dart

    Phép gán là =, để thực hiện gán giá trị biểu thức bên phải vào biến ở phía bên trái toán tử =.

    biến = biểu_thức;

    Mời các bạn xem chi tiết về phép gán trong bài Bài 2. Biến và các kiểu dữ liệu trong Dart

    Phép gán tăng, giảm giá trị

    • var += x tăng biến var lên x đơn vị
    • var -= x giảm biến var lên x đơn vị
    void main() { 
    
      var a = 5;
      print(a+=1); //cho kết quả 6
      print(a-=4); // cho kết quả 2
    }

    Toán tử so sánh trong Dart

    Các toán tử này thực hiện trên biểu thức logic, kết quả là true hoặc false

    • ==So sánh bằng. Ví dụ 5 == 5 kết quả true5 == 6 kết quả false
    • !=So sánh không bằng. Ví dụ 5 != 5 kết quả false5 != 6 kết quả true
    • >So sánh lớn hơn. Ví dụ 5 > 5 kết quả false6 > 5 kết quả true
    • <So sánh nhỏ hơn. Ví dụ 5 < 5 kết quả false5 > 6 kết quả true
    • <=So sánh nhỏ hơn hoặc bằng
    • >=So sánh lớn hơn hoặc bằng

    Toán tử logic Dart

    • |Phép logic hoặc (toán tử or trong Toán học), a | b kết quả true nếu a hoặc b là true
    • & Phép logic và (toán tử and trong Toán học), a & b kết quả true nếu a và b đều true
    • !(biểu_thức)Phép phủ định (toán tử not trong Toán học) !a nếu a là true thì kết quả phép toán là false

    Chi tiết về các toán tử logic, bạn có thể xem ở bài Kiểu logic bool trong Dart/Flutter. Dưới đây là bảng giá trị chân lý của các phép toán and, ornot trong Toán học.

    toan tu bool trong Python Toán tử Boolean trong Python

    Toán tử điều kiện

    điều_kiện ? biểu_thức_1 : biểu_thức_2

    Nếu biểu_thức_điều_kiệnđúng thì trả về giá trị củabiểu_thức_1, ngược lại là biểu_thức_2

    void main() {
      var a = 1; 
      var b = 2;
      print((a > b) ? a : b); //kết quả trả về 2
    }

    biểu_thức_1 ?? biểu_thức_2

    Nếu biểu_thức_1 khác null thì lấy biểu_thức_1, ngược lại lấy giá trị từ biểu_thức_2

    Một số phép toán trong Dart khác

    • []
      • Truy cập phần tử của danh sách, mảng (kiểu list)
      • Ví dụ với List temp = [1,12,31] thì temp[1]trả về phần tử thứ hai (có index bằng 1 vì index của phần tử đầu tiên là 0) của mảng, là 12.
    • .Truy cập phương thức, thuộc tính đối tượng
    • asChuyển kiểu: (var as MyClass)
    • isKiểm tra kiểu: (var is MyClass)
    • is!Kiểm tra kiểu: (var is! MyClass)