Los operadores is y as
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 60 de 110.
Mientras que runtimeType te indica el tipo exacto, Dart proporciona dos operadores que son más prácticos para la comprobación de tipos y la conversión: is y as.
El operador is comprueba si un objeto es de un tipo específico y devuelve un booleano. A diferencia de runtimeType, también devuelve true para tipos padre:
class Animal {}
class Dog extends Animal {}
void main() {
Animal pet = Dog();
print(pet is Dog); // true
print(pet is Animal); // true (Dog ES un Animal)
print(pet is String); // false
}Cuando usas is dentro de una sentencia if, Dart promueve automáticamente el tipo, permitiéndote acceder a los miembros de la subclase sin un casting explícito:
void handleAnimal(Animal animal) {
if (animal is Dog) {
// Dart sabe que animal es un Dog aquí
animal.bark(); // Puede llamar a métodos específicos de Dog
}
}El operador as realiza una conversión explícita (cast) de un objeto a un tipo específico. Úsalo cuando estés seguro del tipo:
Animal pet = Dog();
Dog myDog = pet as Dog; // Convertir a Dog
myDog.bark();Ten cuidado con as: si la conversión falla, lanza una excepción. Por eso, combinar is con la promoción de tipos suele ser más seguro que usar as directamente. También puedes usar is! para comprobar si un objeto no es de un tipo determinado.
Desafío
FácilVamos a construir un sistema de procesamiento de formas que utiliza los operadores is y as para identificar y trabajar con diferentes tipos de formas. Crearás una jerarquía de formas y escribirás funciones que verifiquen tipos y accedan de forma segura a propiedades específicas de cada tipo.
Organizarás tu código en dos archivos:
shapes.dart: Define tu jerarquía de formas aquí:- Una clase
Shapecon una propiedadString namey un constructor. Incluye un métododescribe()que imprima'$name is a shape' - Una clase
Circleque extienda deShapecon una propiedad adicionaldouble radius. Añade un métodogetCircleInfo()que imprima'Circle with radius: $radius' - Una clase
Rectangleque extienda deShapecon propiedades adicionalesdouble widthydouble height. Añade un métodogetRectangleInfo()que imprima'Rectangle: $width x $height'
- Una clase
main.dart: Importa tu archivo de formas y crea una funciónprocessShape(Shape shape)que:- Primero llame a
describe()en la forma - Use
ispara verificar si la forma es unCircle; si es así, usa la promoción de tipos para llamar agetCircleInfo() - Use
ispara verificar si la forma es unRectangle; si es así, usa el operadoraspara realizar un casting y llamar agetRectangleInfo() - Use
is!para verificar si la forma NO es unCircley NO es unRectangle; si es así, imprime'Unknown shape type'
main():- Crea un
Circlellamado'Round'con un radio de5.0y pásalo aprocessShape() - Imprime una línea vacía
- Crea un
Rectanglellamado'Box'con un ancho de4.0y una altura de3.0y pásalo aprocessShape() - Imprime una línea vacía
- Crea una
Shapebase llamada'Mystery'y pásala aprocessShape()
- Primero llame a
Este desafío demuestra ambos enfoques: usar is con promoción automática de tipos para el Circle, y usar as para un casting explícito con el Rectangle. También verás cómo is! ayuda a identificar formas que no coinciden con ningún subtipo específico.
Salida esperada:
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 typeHoja de referencia
El operador is comprueba si un objeto es de un tipo específico y devuelve un booleano. También devuelve true para los tipos padre:
class Animal {}
class Dog extends Animal {}
void main() {
Animal pet = Dog();
print(pet is Dog); // true
print(pet is Animal); // true (Dog ES un Animal)
print(pet is String); // false
}Cuando usas is dentro de una sentencia if, Dart promueve automáticamente el tipo, permitiéndote acceder a los miembros de la subclase sin un casting explícito:
void handleAnimal(Animal animal) {
if (animal is Dog) {
// Dart sabe que animal es un Dog aquí
animal.bark(); // Puede llamar a métodos específicos de Dog
}
}El operador as realiza un casting explícito de un objeto a un tipo específico:
Animal pet = Dog();
Dog myDog = pet as Dog; // Casting a Dog
myDog.bark();Ten cuidado con as: si el casting falla, lanza una excepción. Combinar is con la promoción de tipos suele ser más seguro que usar as directamente.
Usa is! para comprobar si un objeto no es de un tipo determinado:
if (animal is! Dog) {
print("Not a dog");
}Pruébalo tú mismo
import 'shapes.dart';
// TODO: Crea una función processShape(Shape shape) que:
// 1. Primero llame a describe() en la forma (shape)
// 2. Use 'is' para verificar si shape es un Circle; si es así, usa la promoción de tipos para llamar a getCircleInfo()
// 3. Use 'is' para verificar si shape es un Rectangle; si es así, usa el operador 'as' para realizar el cast y llamar a getRectangleInfo()
// 4. Use 'is!' para verificar si shape NO es un Circle y NO es un Rectangle; si es así, imprime "Unknown shape type"
void main() {
// TODO: Crea un Circle llamado 'Round' con un radio de 5.0 y pásalo a processShape()
// TODO: Imprime una línea vacía
// TODO: Crea un Rectangle llamado 'Box' con un ancho de 4.0 y una altura de 3.0 y pásalo a processShape()
// TODO: Imprime una línea vacía
// TODO: Crea una Shape base llamada 'Mystery' y pásala a processShape()
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de POO
Archivos externosLibrerías e importacionesIntroducción a la POOClases vs. ObjetosLa palabra clave thisMétodosVariables de instanciaConceptos básicos de constructoresResumen - Calculadora sencilla4Seguridad de nulos
Introducción a la seguridad de nulosNulables vs No nulablesLos operadores ? y !Palabra clave Late y Null SafetyOperadores Null-awareNull Safety en clasesResumen - Sistema de perfil de usuario7Clases abstractas e interfaces
Clases abstractasMétodos abstractosInterfaces en DartInterfaces implícitasImplementar vs. ExtenderInterfaces múltiplesRepaso - Calculadora de figuras10Colecciones y Genéricos
Visión general de List, Set y MapColecciones con seguridad de tiposClases genéricasMétodos genéricosRestricciones genéricasIterable e IteratorResumen - Almacenamiento genérico2Constructores en Dart
Constructor por defectoConstructores nombradosListas de inicializaciónConstructores constantesConstructores de fábricaConstructores de redireccionamientoResumen - Constructor de formas5Encapsulamiento
Miembros públicos vs. privadosLa convención del prefijo _Privacidad a nivel de libreríaProfundidad en Getters y SettersOcultamiento de informaciónResumen - Registros de estudiantes8Mixins
Introducción a los MixinsCreación de MixinsUso de múltiples MixinsPalabra clave on en MixinsMixin vs HerenciaMixin vs InterfazResumen - Sistema Animal11Métodos especiales
Sobrescritura de toString()Sobrescritura de hashCode y ==Interfaz ComparableMétodo call()Sobrescritura de noSuchMethodResumen - Colección personalizada14Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy3Propiedades de clase
Miembros de instancia vs. estáticosCampos Final y ConstVariables LateMétodos y campos estáticosGetters y SettersResumen - Gestor de cuentas bancarias6Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosLa anotación @overrideLa palabra clave final en clasesConstructores y herenciaResumen - Jerarquía de empleados9Polimorfismo
Fundamentos del polimorfismoPolimorfismo mediante interfacesComprobación de tipos en tiempo de ejecuciónLos operadores is y asPalabra clave covariantResumen - Procesador de pagos12POO Asíncrona
Futures y async/awaitFundamentos de StreamsStream ControllersConstructores asíncronosAsincronía en métodos de claseRepaso - Data Fetcher15Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository