Move 2.0
Desde la versión del compilador 2.0
Move 2.0 introduce varias características nuevas significativas al lenguaje Move, incluyendo mejoras de sintaxis, nuevos tipos de datos y herramientas de desarrollo mejoradas. Esta página resume las adiciones y cambios principales introducidos en Move 2.0.
Características Principales de Move 2.0
Sección titulada «Características Principales de Move 2.0»1. Tipos Enum
Sección titulada «1. Tipos Enum»Los tipos enum permiten definir tipos con múltiples variantes, habilitando patrones de programación más expresivos:
enum Shape { Circle { radius: u64 }, Rectangle { width: u64, height: u64 }, Triangle { base: u64, height: u64 }}
enum Option<T> { Some(T), None}
enum Result<T, E> { Ok(T), Err(E)}
Beneficios:
- Modelado de datos más expresivo
- Coincidencia de patrones exhaustiva
- Mejor manejo de errores
- Tipos de datos algebraicos
2. Coincidencia de Patrones (Pattern Matching)
Sección titulada «2. Coincidencia de Patrones (Pattern Matching)»La expresión match
proporciona una manera poderosa de trabajar con enums y otros tipos:
fun calculate_area(shape: Shape): u64 { match (shape) { Shape::Circle { radius } => 3 * radius * radius, // π ≈ 3 Shape::Rectangle { width, height } => width * height, Shape::Triangle { base, height } => base * height / 2, }}
fun handle_result<T, E>(result: Result<T, E>): T { match (result) { Result::Ok(value) => value, Result::Err(_error) => abort 1, }}
Características:
- Coincidencia exhaustiva (todos los casos deben manejarse)
- Deconstrucción de patrones
- Guardas de patrones para lógica condicional
- Patrones comodín (
_
) para valores ignorados
3. Sintaxis de Bucle For Mejorada
Sección titulada «3. Sintaxis de Bucle For Mejorada»Nueva sintaxis más ergonómica para iterar sobre colecciones:
fun sum_vector(numbers: &vector<u64>): u64 { let mut sum = 0; for (num in numbers) { sum = sum + *num; }; sum}
fun process_range() { for (i in 0..10) { // Procesar índice i (0 a 9) debug::print(&i); };}
Mejoras:
- Sintaxis más limpia e intuitiva
- Soporte para iteradores
- Rangos incorporados
- Mejor ergonomía de desarrollo
4. Variables Mutables con mut
Sección titulada «4. Variables Mutables con mut»Declaración explícita de mutabilidad para mayor claridad:
fun mutable_variables() { let x = 10; // Inmutable por defecto let mut y = 20; // Explícitamente mutable
// x = 15; // Error: x es inmutable y = 25; // OK: y es mutable
let mut vec = vector::empty<u64>(); vector::push_back(&mut vec, 1); vector::push_back(&mut vec, 2);}
Ventajas:
- Intención clara del código
- Prevención de mutaciones accidentales
- Mejor documentación de la lógica
- Herramientas de linting mejoradas
5. Índices de Vectores
Sección titulada «5. Índices de Vectores»Sintaxis directa para acceso a elementos de vectores:
fun vector_indexing() { let vec = vector[1, 2, 3, 4, 5];
// Nuevo: acceso directo por índice let first = vec[0]; // 1 let third = vec[2]; // 3
// Comparar con la sintaxis anterior: // let first = *vector::borrow(&vec, 0); // let third = *vector::borrow(&vec, 2);}
fun mutable_indexing() { let mut vec = vector[10, 20, 30];
// Modificación directa vec[0] = 100; // vec ahora es [100, 20, 30] vec[2] = 300; // vec ahora es [100, 20, 300]}
6. Literales de Vector Mejorados
Sección titulada «6. Literales de Vector Mejorados»Sintaxis más concisa para crear vectores:
fun vector_literals() { // Nueva sintaxis let numbers = vector[1, 2, 3, 4, 5]; let strings = vector[b"hello", b"world"]; let addresses = vector[@0x1, @0x2, @0x3];
// Vector vacío con tipo inferido let empty: vector<u64> = vector[];
// Vector con repetición let zeros = vector[0; 10]; // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}
7. Operador de Propagación de Errores (?
)
Sección titulada «7. Operador de Propagación de Errores (?)»Manejo simplificado de errores para tipos Result:
fun divide(x: u64, y: u64): Result<u64, String> { if (y == 0) { Result::Err(string::utf8(b"División por cero")) } else { Result::Ok(x / y) }}
fun complex_calculation(a: u64, b: u64, c: u64): Result<u64, String> { let step1 = divide(a, b)?; // Propaga error si divide falla let step2 = divide(step1, c)?; // Propaga error si divide falla Result::Ok(step2 * 2)}
// Sin el operador ?, sería:fun complex_calculation_verbose(a: u64, b: u64, c: u64): Result<u64, String> { match (divide(a, b)) { Result::Ok(step1) => match (divide(step1, c)) { Result::Ok(step2) => Result::Ok(step2 * 2), Result::Err(error) => Result::Err(error), }, Result::Err(error) => Result::Err(error), }}
8. Función main
Mejorada
Sección titulada «8. Función main Mejorada»Mejor soporte para puntos de entrada de scripts:
script { use std::debug;
fun main() { debug::print(&b"¡Hola, Move 2.0!");
let shapes = vector[ Shape::Circle { radius: 5 }, Shape::Rectangle { width: 4, height: 6 }, ];
for (shape in &shapes) { let area = calculate_area(*shape); debug::print(&area); }; }}
Características de Desarrollador
Sección titulada «Características de Desarrollador»1. Mensajes de Error Mejorados
Sección titulada «1. Mensajes de Error Mejorados»Move 2.0 proporciona mensajes de error más claros y útiles:
// Error anterior:// Error: Invalid argument
// Error en Move 2.0:// Error en la línea 15: El patrón match no es exhaustivo// Falta el caso: Shape::Triangle { .. }// Sugerencia: Agrega el patrón faltante o usa un comodín '_'
2. Herramientas de Formato
Sección titulada «2. Herramientas de Formato»Formateo automático de código para consistencia:
# Formatear un archivoaptos move fmt src/my_module.move
# Formatear todo el proyectoaptos move fmt
3. Linter Mejorado
Sección titulada «3. Linter Mejorado»Detección de problemas comunes y sugerencias de mejores prácticas:
# Ejecutar linteraptos move lint
# Ejemplo de sugerencias:# Warning: Variable 'unused_var' nunca se usa# Suggestion: Considera usar '_unused_var' o eliminar la variable# Warning: El match podría simplificarse usando un patrón comodín
4. Modo Interactivo
Sección titulada «4. Modo Interactivo»REPL para experimentación rápida:
# Iniciar modo interactivoaptos move shell
# Ejemplo de sesión:> let x = 42;> let y = x * 2;> debug::print(&y);84
Ejemplos de Migración
Sección titulada «Ejemplos de Migración»De Move 1.x a Move 2.0
Sección titulada «De Move 1.x a Move 2.0»Antes (Move 1.x):
Sección titulada «Antes (Move 1.x):»module 0x42::example_old { use std::vector; use std::option::{Self, Option};
public fun process_data(data: vector<u64>): Option<u64> { if (vector::is_empty(&data)) { option::none() } else { let sum = 0; let len = vector::length(&data); let i = 0; while (i < len) { sum = sum + *vector::borrow(&data, i); i = i + 1; }; option::some(sum / len) } }}
Después (Move 2.0):
Sección titulada «Después (Move 2.0):»module 0x42::example_new { use std::vector;
enum Option<T> { Some(T), None }
public fun process_data(data: vector<u64>): Option<u64> { if (vector::is_empty(&data)) { Option::None } else { let mut sum = 0; for (value in &data) { sum = sum + *value; }; Option::Some(sum / vector::length(&data)) } }
public fun use_result(data: vector<u64>): u64 { match (process_data(data)) { Option::Some(average) => average, Option::None => 0, } }}
Patrón Result para Manejo de Errores
Sección titulada «Patrón Result para Manejo de Errores»module 0x42::error_handling { enum Error { DivisionByZero, InvalidInput, Overflow }
enum Result<T, E> { Ok(T), Err(E) }
public fun safe_divide(x: u64, y: u64): Result<u64, Error> { if (y == 0) { Result::Err(Error::DivisionByZero) } else { Result::Ok(x / y) } }
public fun chain_operations(a: u64, b: u64, c: u64): Result<u64, Error> { let step1 = safe_divide(a, b)?; let step2 = safe_divide(step1, c)?; Result::Ok(step2) }
public fun handle_errors() { let result = chain_operations(100, 5, 2); match (result) { Result::Ok(value) => { debug::print(&string::utf8(b"Resultado: ")); debug::print(&value); }, Result::Err(Error::DivisionByZero) => { debug::print(&string::utf8(b"Error: División por cero")); }, Result::Err(_) => { debug::print(&string::utf8(b"Error desconocido")); } } }}
Guía de Compatibilidad
Sección titulada «Guía de Compatibilidad»Compatibilidad Hacia Atrás
Sección titulada «Compatibilidad Hacia Atrás»Move 2.0 mantiene compatibilidad hacia atrás con la mayoría del código Move 1.x:
- ✅ Los módulos existentes compilan sin cambios
- ✅ Las funciones públicas mantienen sus firmas
- ✅ Los tipos struct existentes funcionan igual
- ✅ Los patrones de almacenamiento global son idénticos
Características Opcionales
Sección titulada «Características Opcionales»Las nuevas características son opt-in y no rompen el código existente:
// Este código Move 1.x sigue funcionando en Move 2.0module 0x42::legacy { use std::vector;
struct OldStruct { data: u64 }
public fun old_function(x: u64): u64 { x + 1 }}
Migración Gradual
Sección titulada «Migración Gradual»Puedes adoptar características de Move 2.0 gradualmente:
module 0x42::gradual_migration { // Usar nuevas características donde sea beneficioso enum Status { Active, Inactive, Pending }
// Mantener código existente donde funcione bien struct LegacyData { value: u64, owner: address, }
// Mezclar sintaxis nueva y antigua public fun process(data: vector<u64>): u64 { let mut sum = 0; // Nueva sintaxis mutable
// Bucle tradicional sigue funcionando let len = vector::length(&data); let i = 0; while (i < len) { sum = sum + *vector::borrow(&data, i); i = i + 1; };
sum }}
Herramientas de Desarrollo
Sección titulada «Herramientas de Desarrollo»CLI Actualizado
Sección titulada «CLI Actualizado»# Nuevo comando para proyectos Move 2.0aptos move init --template move2.0
# Compilar con características Move 2.0aptos move compile --language-version 2.0
# Testing con nuevas característicasaptos move test --language-version 2.0
# Formateo de códigoaptos move fmt
# Linting avanzadoaptos move lint --level strict
IDE Support
Sección titulada «IDE Support»Las extensiones de VSCode y otros IDEs ahora soportan:
- ✅ Resaltado de sintaxis para enums y match
- ✅ Autocompletado para nuevas características
- ✅ Detección de patrones match no exhaustivos
- ✅ Refactoring automático para bucles for
- ✅ Hover information para tipos enum
Debugging Mejorado
Sección titulada «Debugging Mejorado»// Nuevas macros de debuggingfun debug_example() { let data = vector[1, 2, 3];
// Imprimir con formato mejorado debug::print_stack_trace(); debug::print_struct(&data);
// Assertions más informativos debug::assert!(vector::length(&data) == 3, b"Vector debe tener 3 elementos");}
Mejores Prácticas para Move 2.0
Sección titulada «Mejores Prácticas para Move 2.0»1. Usa Enums para Estados
Sección titulada «1. Usa Enums para Estados»// ✅ Bueno - estados explícitos con enumsenum OrderStatus { Pending { created_at: u64 }, Processing { started_at: u64 }, Shipped { tracking_number: vector<u8> }, Delivered { delivered_at: u64 }, Cancelled { reason: vector<u8> }}
// ❌ Evitar - estados implícitos con númerosstruct Order { status: u8, // 0=pending, 1=processing, etc.}
2. Patrón Result para Errores
Sección titulada «2. Patrón Result para Errores»// ✅ Bueno - errores explícitosenum TransferError { InsufficientBalance, InvalidRecipient, AmountTooLarge}
public fun transfer(from: address, to: address, amount: u64): Result<(), TransferError> { // Implementación con manejo explicito de errores}
// ❌ Evitar - abort codes sin contextopublic fun transfer_old(from: address, to: address, amount: u64) { assert!(balance >= amount, 1); // ¿Qué significa 1?}
3. Match Exhaustivo
Sección titulada «3. Match Exhaustivo»// ✅ Bueno - todos los casos manejadosfun handle_status(status: OrderStatus): vector<u8> { match (status) { OrderStatus::Pending{..} => b"Orden pendiente", OrderStatus::Processing{..} => b"Procesando orden", OrderStatus::Shipped{..} => b"Orden enviada", OrderStatus::Delivered{..} => b"Orden entregada", OrderStatus::Cancelled{..} => b"Orden cancelada", }}
// ❌ Evitar - casos faltantesfun handle_status_incomplete(status: OrderStatus): vector<u8> { match (status) { OrderStatus::Pending{..} => b"Orden pendiente", OrderStatus::Processing{..} => b"Procesando orden", // Faltan casos - error de compilación }}
4. Variables Mutables Mínimas
Sección titulada «4. Variables Mutables Mínimas»// ✅ Bueno - mutabilidad explícita y mínimafun calculate_sum(numbers: &vector<u64>): u64 { let mut sum = 0; // Solo esta variable es mutable let multiplier = 2; // Inmutable
for (num in numbers) { sum = sum + (*num * multiplier); };
sum}
Roadmap Futuro
Sección titulada «Roadmap Futuro»Move 2.0 es la base para futuras mejoras:
Características Planificadas
Sección titulada «Características Planificadas»- Generics mejorados con constraints más expresivos
- Traits/Interfaces para polimorfismo
- Async/await para operaciones asíncronas
- Macros para metaprogramación
- FFI mejorada para interoperabilidad
Herramientas en Desarrollo
Sección titulada «Herramientas en Desarrollo»- Debugger visual con stepping through code
- Performance profiler para optimización
- Documentation generator automático
- Package manager mejorado
- Testing framework avanzado
Conclusión
Sección titulada «Conclusión»Move 2.0 representa una evolución significativa del lenguaje Move, introduciendo características que hacen el desarrollo más expresivo, seguro y ergonómico. Las principales mejoras incluyen:
✅ Enums y pattern matching para modelado de datos rico
✅ Sintaxis mejorada para mejor ergonomía de desarrollador
✅ Manejo de errores robusto con tipos Result
✅ Herramientas de desarrollo avanzadas
✅ Compatibilidad hacia atrás para migración suave
Con estas características, Move 2.0 habilita patrones de programación más sofisticados mientras mantiene las garantías de seguridad y simplicidad que hacen a Move único en el espacio de smart contracts.
Para desarrolladores nuevos en Move, se recomienda comenzar directamente con Move 2.0. Para desarrolladores existentes, la migración puede ser gradual, adoptando nuevas características donde aporten valor mientras mantienen el código existente funcionando.