"El tipo de argumento '¿Cadena?' no se puede asignar al tipo de parámetro 'Cadena'" cuando se usa stdin.readLineSync()

Resuelto Bruno Proença asked hace 3 años • 3 respuestas

Soy nuevo en dardos. No sé qué tipo de error he cometido, pero este código no funcionó. Es un código simple, simplemente lea la edad en la terminal y diga que es menor o mayor de 18 años.

import 'dart:io'; 

main(){
  print("Entre com a sua idade: ");
  var input = stdin.readLineSync();
  var idade = int.parse(input);

  if(idade >= 18){
    print("É maior de idade");
  }else{
    print("É menor de idade");
  }
}

Y me sale este error:

algoritmo01.dart:15:25: Error: The argument type 'String?' can't be assigned to the parameter type 'String' because 'String?' is nullable and 'String' isn't.
  var idade = int.parse(input);
Bruno Proença avatar Mar 18 '21 23:03 Bruno Proença
Aceptado

Bienvenido a Dardo. Lo que está experimentando es la nueva característica de seguridad nula (introducida con Dart 2.12.0) donde las variables de forma predeterminada no pueden contener el valor nulo. Esto se verifica estáticamente, por lo que obtendrá un error incluso antes de que se ejecute su programa.

En su ejemplo el problema es la siguiente línea:

var input = stdin.readLineSync();

Si revisamos el manual podemos ver que este método tiene la siguiente firma:

String? readLineSync (
    {Encoding encoding = systemEncoding,
    bool retainNewlines = false}
) 

https://api.dart.dev/stable/2.12.2/dart-io/Stdin/readLineSync.html

String?significa que es un tipo que acepta valores NULL y, por lo tanto, se le permite contener cualquier cadena o nulo. Si el tipo fuera, Stringsignificaría que el resultado solo puede ser a Stringy never null.

Esto significa que su variable inputahora tiene el tipo String?. Esto (introducido en 2.12.0) es un problema si observa la segunda línea de su ejemplo:

var idade = int.parse(input);

Dado que la firma de int.parsees:

int parse (

    String source,
    {int? radix,
    @deprecated int onError(
        String source
    )}

) 

https://api.dart.dev/stable/2.12.2/dart-core/int/parse.html

Lo cual requiere un String(que por lo tanto nunca puede ser null). Por lo tanto, no se le permite dar su String?parámetro as a un método que solo maneja archivos String. Se habría permitido lo contrario (si el método toma String?y le das un String).

Entonces, ¿qué podemos hacer ante esta situación? Bueno, debes manejar el caso de nullo decirle a Dart que debería bloquear tu programa si inputes así null.

Entonces podrías manejarlo como:

import 'dart:io';

void main() {
  print("Entre com a sua idade: ");
  var input = stdin.readLineSync();
  
  if (input != null) {
    var idade = int.parse(input);

    if (idade >= 18) {
      print("É maior de idade");
    } else {
      print("É menor de idade");
    }
  } else {
    print('Input was null!');
  }
}

Como puede ver, esto está permitido incluso si inputtécnicamente siguen siendo del tipo String?. Pero Dart puede ver que su ifdeclaración impedirá inputtener el valor null, por lo que será "promovida" mientras Stringesté dentro de esta declaración if.

Otra solución es decirle a Dart que debería dejar de quejarse de errores estáticos inputy simplemente asumir inputque es Stringal compilar el código:

import 'dart:io';

void main() {
  print("Entre com a sua idade: ");
  var input = stdin.readLineSync()!;
  var idade = int.parse(input);

  if (idade >= 18) {
    print("É maior de idade");
  } else {
    print("É menor de idade");
  }
}

(El cambio se !agrega después readLineSync())

En este caso, Dart agregará su propia nullverificación y bloqueará el programa si stdin.readLineSyncproporciona un nullvalor. Esto es para garantizar que nunca daremos int.parseun valor nulo que podría hacer que su código falle en otro lugar. Al agregar null-check donde obtenemos el valor cuestionable, podemos asegurarnos de que fallamos rápidamente y en el lugar donde las cosas no fueron como esperábamos.

Puede leer mucho más sobre la seguridad nula en Dart aquí (también vinculado por Stephen): https://dart.dev/null-safety/understanding-null-safety

julemand101 avatar Mar 18 '2021 18:03 julemand101

La respuesta aceptada es correcta. Pero existe otra solución alternativa. Puede utilizar el operador "si es nulo" como este:

var idade = int.parse(input ?? "-1");

Entonces el código completo se verá así:

import 'dart:io'; 

main(){
  print("Entre com a sua idade: ");
  var input = stdin.readLineSync();
  var idade = int.parse(input ?? "-1");

  if(idade >= 18){
    print("É maior de idade");
  }else if(idade < 18 && idade > 0){
    print("É menor de idade");
  } else {
    print("entrada errada");
  }
}
Samuel Ricky Saputro avatar Aug 28 '2021 23:08 Samuel Ricky Saputro