getters - ¿Cómo crear variables privadas en Dart?
dartlang (3)
Quiero crear una variable privada pero no puedo.
Aquí está mi código:
void main() {
var b = new B();
b.testB();
}
class A {
int _private = 0;
testA() {
print(''int value: $_private'');
_private = 5;
}
}
class B extends A {
String _private;
testB() {
_private = ''Hello'';
print(''String value: $_private'');
testA();
print(''String value: $_private'');
}
}
Cuando ejecuto este código, obtengo el siguiente resultado:
String value: Hello
int value: Hello
Breaking on exception: type ''int'' is not a subtype of type ''String'' of ''value''.
Además, no recibo ningún error o advertencia al editar este código fuente.
¿Cómo puedo crear una variable privada en Dart?
De la documentación de Dart:
A diferencia de Java, Dart no tiene las palabras clave pública, protegida y privada. Si un identificador comienza con un guión bajo
_
, es privado a su biblioteca.
Las bibliotecas no solo proporcionan API, sino que son una unidad de privacidad: los identificadores que comienzan con un guión bajo _
son visibles solo dentro de la biblioteca.
La privacidad en Dart existe en la biblioteca, en lugar del nivel de clase.
Si other.dart
que colocar la clase A en un archivo de biblioteca separado (por ejemplo, other.dart
), como por ejemplo:
library other;
class A {
int _private = 0;
testA() {
print(''int value: $_private''); // 0
_private = 5;
print(''int value: $_private''); // 5
}
}
y luego impórtelo en su aplicación principal, como:
import ''other.dart'';
void main() {
var b = new B();
b.testB();
}
class B extends A {
String _private;
testB() {
_private = ''Hello'';
print(''String value: $_private''); // Hello
testA();
print(''String value: $_private''); // Hello
}
}
Obtienes el resultado esperado:
String value: Hello
int value: 0
int value: 5
String value: Hello
La respuesta principal a partir de ahora es definitivamente correcta.
Intentaré entrar en más detalles en esta respuesta.
Responderé a la pregunta, pero diré con esto: no es así como se pretende escribir Dart, en parte porque los miembros de bibliotecas privadas facilitan la definición de operadores como ==
. (Las variables privadas de un segundo objeto no se pudieron ver para la comparación).
Ahora que lo hemos dejado de lado, comenzaré mostrándole cómo se debe hacer (biblioteca-privada en lugar de clase-privada), y luego le mostraré cómo hacer una variable clase-privada si Todavía realmente quieres eso. Aquí vamos.
Si una clase no tiene nada que ver con las variables en otra clase, puede preguntarse si realmente pertenecen a la misma biblioteca:
//This should be in a separate library from main() for the reason stated in the main method below.
class MyClass {
//Library private variable
int _val = 0;
int get val => _val;
set val(int v) => _val = (v < 0) ? _val : v;
MyClass.fromVal(int val) : _val = val;
}
void main() {
MyClass mc = MyClass.fromVal(1);
mc.val = -1;
print(mc.val); //1
//main() MUST BE IN A SEPARATE LIBRARY TO
//PREVENT MODIFYING THE BACKING FIELDS LIKE:
mc._val = 6;
print(mc.val); //6
}
Eso debería ser bueno. Sin embargo, si realmente quieres datos de clase privada:
Aunque técnicamente no se le permite crear variables privadas, puede emularlo utilizando la siguiente técnica de cierre.
(¡SIN EMBARGO, debes considerar CUIDADOSAMENTE si realmente lo necesitas y si existe una manera mejor, más parecida a un dardo, de hacer lo que estás tratando de lograr!)
//A "workaround" that you should THINK TWICE before using because:
//1. The syntax is verbose.
//2. Both closure variables and any methods needing to access
// the closure variables must be defined inside a base constructor.
//3. Those methods require typedefs to ensure correct signatures.
typedef int IntGetter();
typedef void IntSetter(int value);
class MyClass {
IntGetter getVal;
IntSetter setVal;
MyClass.base() {
//Closure variable
int _val = 0;
//Methods defined within constructor closure
getVal = ()=>_val;
setVal = (int v) => _val = (v < 0) ? _val : v;
}
factory MyClass.fromVal(int val) {
MyClass result = MyClass.base();
result.setVal(val);
return result;
}
}
void main() {
MyClass mc = MyClass.fromVal(1);
mc.setVal(-1); //Fails
print(mc.getVal());
//On the upside, you can''t access _val
//mc._val = 6; //Doesn''t compile.
}
Así que sí. Solo tenga cuidado y trate de seguir las mejores prácticas del idioma y estará bien.
EDITAR
Aparentemente hay una nueva sintaxis de typedef que se prefiere para Dart 2. Si estás usando Dart 2, deberías usar esa. O, mejor aún, usar tipos de funciones en línea.
Si usa el segundo, será menos detallado, pero los otros problemas permanecerán.