Menu
CoddyTech

Toán tử is và as

Thuộc phần Lập trình hướng đối tượng trong hành trình Dart của Coddy. Bài học 60 trên 110.

Trong khi runtimeType cho bạn biết kiểu chính xác, Dart cung cấp hai toán tử thiết thực hơn để kiểm tra kiểu (type checking) và ép kiểu (casting): is và as.

Toán tử is kiểm tra xem một đối tượng có thuộc một kiểu cụ thể hay không và trả về giá trị boolean. Khác với runtimeType, toán tử này cũng trả về true cho các kiểu cha:

class Animal {}
class Dog extends Animal {}

void main() {
  Animal pet = Dog();
  
  print(pet is Dog);     // true
  print(pet is Animal);  // true (Dog là một Animal)
  print(pet is String);  // false
}

Khi bạn dùng is bên trong câu lệnh if, Dart tự động nâng cấp kiểu, cho phép bạn truy cập các thành viên của lớp con mà không cần ép kiểu tường minh:

void handleAnimal(Animal animal) {
  if (animal is Dog) {
    // Ở đây, Dart biết animal là một Dog
    animal.bark();  // Có thể gọi các phương thức (method) của riêng Dog
  }
}

Toán tử as chuyển đổi tường minh một đối tượng sang một kiểu cụ thể. Hãy dùng toán tử này khi bạn chắc chắn về kiểu:

Animal pet = Dog();
Dog myDog = pet as Dog;  // Ép kiểu sang Dog
myDog.bark();

Hãy cẩn thận với as: nếu ép kiểu thất bại, nó sẽ gây ra ngoại lệ. Vì vậy, kết hợp is với việc nâng cấp kiểu thường an toàn hơn dùng trực tiếp as. Bạn cũng có thể dùng is! để kiểm tra xem một đối tượng có không thuộc một kiểu nhất định hay không.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống xử lý hình dạng dùng các toán tử is và as để nhận diện và làm việc với các loại hình dạng khác nhau. Bạn sẽ tạo một hệ thống phân cấp các hình dạng và viết các hàm kiểm tra kiểu dữ liệu, đồng thời truy cập an toàn vào các thuộc tính riêng của từng kiểu.

Bạn sẽ sắp xếp code vào hai tệp:

  • shapes.dart: Định nghĩa hệ thống phân cấp hình dạng tại đây:
    • Một lớp Shape có thuộc tính String name và hàm khởi tạo. Thêm phương thức describe() để in ra [name] is a shape
    • Một lớp Circle kế thừa Shape và có thêm thuộc tính double radius. Thêm phương thức getCircleInfo() để in ra Circle with radius: [radius]
    • Một lớp Rectangle kế thừa Shape và có thêm các thuộc tính double width và double height. Thêm phương thức getRectangleInfo() để in ra Rectangle: [width] x [height]
  • main.dart: Nhập tệp hình dạng và tạo hàm processShape(Shape shape) để:
    • Gọi describe() trên hình dạng trước tiên
    • Dùng is để kiểm tra hình dạng có phải là Circle không. Nếu đúng, dùng cơ chế nâng kiểu tự động để gọi getCircleInfo()
    • Dùng is để kiểm tra hình dạng có phải là Rectangle không. Nếu đúng, dùng toán tử as để ép kiểu rồi gọi getRectangleInfo()
    • Dùng is! để kiểm tra hình dạng KHÔNG phải là Circle và KHÔNG phải là Rectangle. Nếu đúng, in ra Unknown shape type
    Sau đó, trong hàm main():
    • Tạo một Circle có tên 'Round', bán kính 5.0, rồi truyền nó vào processShape()
    • In ra một dòng trống
    • Tạo một Rectangle có tên 'Box', chiều rộng 4.0 và chiều cao 3.0, rồi truyền nó vào processShape()
    • In ra một dòng trống
    • Tạo một Shape cơ sở có tên 'Mystery', rồi truyền nó vào processShape()

Thử thách này minh họa cả hai cách: dùng is với cơ chế nâng kiểu tự động cho Circle, và dùng as để ép kiểu tường minh cho Rectangle. Bạn cũng sẽ thấy is! giúp nhận diện những hình dạng không thuộc bất kỳ kiểu con cụ thể nào.

Đầu ra mong đợi:

Round is a shape
Circle with radius: 5.0

Box is a shape
Rectangle: 4.0 x 3.0

Mystery is a shape
Unknown shape type

Tự làm thử

import 'shapes.dart';

// TODO: Tạo hàm (function) processShape(Shape shape) thực hiện các bước sau:
// 1. Đầu tiên, gọi describe() trên shape
// 2. Dùng 'is' để kiểm tra shape có phải là Circle không. Nếu đúng, dùng cơ chế nâng kiểu để gọi getCircleInfo()
// 3. Dùng 'is' để kiểm tra shape có phải là Rectangle không. Nếu đúng, dùng toán tử 'as' để ép kiểu rồi gọi getRectangleInfo()
// 4. Dùng 'is!' để kiểm tra shape không phải là Circle và cũng không phải là Rectangle. Nếu đúng, in ra "Unknown shape type"

void main() {
  // TODO: Tạo một Circle tên 'Round' có bán kính 5.0 rồi truyền vào processShape()
  
  // TODO: In ra một dòng trống
  
  // TODO: Tạo một Rectangle tên 'Box' có chiều rộng 4.0 và chiều cao 3.0 rồi truyền vào processShape()
  
  // TODO: In ra một dòng trống
  
  // TODO: Tạo một Shape cơ sở tên 'Mystery' rồi truyền vào processShape()
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Dart online