"The argument type 'String?' can't be assigned to the parameter type 'String'" when using stdin.readLineSync()
Solution 1:
Welcome to Dart. What you are experience is the new null-safety feature (introduced with Dart 2.12.0) where variables by default cannot contain the value null. This is statically checked so you will get an error even before your program are executed.
In your example the problem is the following line:
var input = stdin.readLineSync();
If we check the manual we can see this method have the following signature:
String? readLineSync (
{Encoding encoding = systemEncoding,
bool retainNewlines = false}
)
https://api.dart.dev/stable/2.12.2/dart-io/Stdin/readLineSync.html
String?
means it is a nullable type and is therefore allowed to contain any String or null. If the type instead was String
it would mean the result can only be a String
and never null
.
This means that your variable input
now has the type String?
. This (introduced with 2.12.0) is a problem if you take a look at the second line of your example:
var idade = int.parse(input);
Since the signature of int.parse
is:
int parse (
String source,
{int? radix,
@deprecated int onError(
String source
)}
)
https://api.dart.dev/stable/2.12.2/dart-core/int/parse.html
Which takes a String
(which can therefore never be null
). You are therefore not allowed to give your String?
as parameter to a method which only handles String
. The opposite would have been allowed (if method takes String?
and you give it a String
).
So what can we do about this situation? Well, you need to handle the case of null
or tell Dart that it should just crash your program if input
are null
.
So you could handle it like:
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!');
}
}
As you can see, this is allowed even if input
are technically still of the type String?
. But Dart can see that your if
statement will prevent input
to have the value null
so it will be "promoted" to String
as long as you are inside this if-statement.
Another solution is to tell Dart that it should stop complain about statically errors about input
and just assume input
is String
when compiling the code:
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");
}
}
(The change is the !
added after readLineSync()
)
Dart will in this case instead add its own null
-check and crash the program if stdin.readLineSync
does give a null
value. This is to ensure that we are still never going to give int.parse
a null value which could make your code crash somewhere else. By adding the null
-check where we get the questionable value, we can ensure we fails fast and at the place where things was not as we expected it to be.
You can read a lot more about null-safety in Dart here (also linked to by Stephen): https://dart.dev/null-safety/understanding-null-safety