I just finished my nullsafe migration. I'm finding that wrapping code with a null check only sometimes removes the need for the nullcheck ! operator? E.g.,
class MyClass {
double divideBy4(double numerator) {
return numerator / 4;
}
double quarteredWorks(double? value) {
if (value != null)
return divideBy4(value); // <- no intellisense warning
else
return 0;
}
double quarteredDoesntWork(double? value) {
return divideBy4(value); // <- intellisense: "double? can't be assigned to double"
}
double? value;
double divideBy2() {
if (value != null)
return value / 2; // <- intellisense: "receiver can be null"
else
return .0;
}
}
EDIT
Changed my example to show an example of wrapping with a null check that works
Related
here is the code and when I run code it's print my result correctly but there is a null as result (in line 4) :
main() {
var ferrari = Car();
ferrari.armor = 85;
print(ferrari.armor);
}
class Car {
int? _armor;
int? get armor {
return _armor;
}
set armor(int? armor) {
if (armor != null && armor < 100) {
print(true);
} else {
print(false);
}
}
you have a variable that you give to it a custom getter and setter, so basically when you call the getter ferrari.armor it returns the _armor from your class, but since you see the _armor in your code will be always null because actaully you didn't give it any value in the setter, so it stays always null.
here propably what you wanted to do.
main() {
var ferrari = Car();
ferrari.armor = 85;
print(ferrari.armor);
}
class Car {
int? _armor;
int? get armor {
return _armor;
}
set armor(int? armor) {
if (armor != null && armor < 100) {
_armor = armor; // add this
print(true);
} else {
print(false);
}
}
}
In the set function, you need to set the _armor.
set armor(int? armor) {
if (armor != null && armor < 100) {
_armor = armor; // Set _armor to armor here.
print(true);
} else {
print(false);
}
}
I try to make flutter null safety migration, I have this old code, that worked before null safety, but after upgrade I have some error when there is "null". How can I change this ?
error for bestMove : the non nullable local variable must be assigned before it can be used
errror for return ScoredMove(0, null); :
the argument null can"t be assigned to the parameter Position
Here is the code
class ScoredMove {
final int score;
final Position move;
const ScoredMove(this.score, this.move);
}
Position _findNextMove(MoveSearchArgs args) {
ScoredMove bestMove = _performSearchPly(
args.board, args.player, args.player, args.numPlies - 1);
return bestMove.move;
}
ScoredMove _performSearchPly(GameBoard board, PieceType scoringPlayer,
PieceType player, int pliesRemaining) {
List<Position> availableMoves = board.getMovesForPlayer(player);
if (availableMoves.isEmpty) {
return ScoredMove(0, null);
//the argument null can"t be assigned to the parameter Position
}
int score = (scoringPlayer == player)
? GameBoardScorer.minScore
: GameBoardScorer.maxScore;
ScoredMove bestMove;
for (int i = 0; i < availableMoves.length; i++) {
GameBoard newBoard =
board.updateForMove(availableMoves[i].x, availableMoves[i].y, player);
if (pliesRemaining > 0 &&
newBoard.getMovesForPlayer(getOpponent(player)).isNotEmpty) {
score = _performSearchPly(
newBoard, scoringPlayer, getOpponent(player), pliesRemaining - 1)
.score;
} else if (pliesRemaining > 0 &&
newBoard.getMovesForPlayer(player).isNotEmpty) {
// Opponent has no moves; player gets another turn.
score =
_performSearchPly(newBoard, scoringPlayer, player, pliesRemaining - 1)
.score;
} else {
score = GameBoardScorer(newBoard).getScore(scoringPlayer);
}
//bestMove error the non nullable local variable must be assigned before it can be used
if (bestMove == null ||
(score > bestMove.score && scoringPlayer == player) ||
(score < bestMove.score && scoringPlayer != player)) {
bestMove =
ScoredMove(score, Position(availableMoves[i].x, availableMoves[i].y));
}
}
return bestMove;
}
class MoveFinder {
final GameBoard initialBoard;
MoveFinder(this.initialBoard) : assert(initialBoard != null);
Future<Position> findNextMove(PieceType player, int numPlies) {
return compute(
_findNextMove,
MoveSearchArgs(
board: this.initialBoard,
player: player,
numPlies: numPlies,
),
);
}
}
You can't do
ScoredMove(0, null)
Because the move parameter is not allowed to be null. A possible solution is to make it nullable. You can do that by adding ? after the type, like
class ScoredMove { final int score; final Position? move;
const ScoredMove(this.score, this.move);
}
And for the other error you can try changing
ScoredMove bestMove;
to
ScoredMove? bestMove = null;
and also changing
return bestMove;
to
return bestMove!;
Every time I run my app. It shows
"Null check operator used on a null value".
I have shown some solutions but couldn't successfully apply them to my code. How do I solve this?
import 'dart:math';
class bmicalculator {
bmicalculator({required this.height, required this.weight});
int height;
double weight;
double? bmi;
String Calculation() {
bmi = weight / pow(height / 100, 2);
return bmi!.toStringAsFixed(2);
}
String getResult() {
if (bmi! >= 25) {
return 'Overweight';
} else if (bmi! > 18.5) {
return 'Normal';
} else
return 'UnderWeight';
}
String getInterpretation() {
if (bmi! >= 25) {
return 'String 1';
} else if (bmi! > 18.5) {
return 'String 2';
} else
return 'String 3';
}
}
The null check operator(!) is used at getResult() and getInterpretation() functions. This operator should NOT be used if the value can be null. The bmi value can be null, so you don't use the ! operator if that can be null.
Solution
Add condition before using the bmi value like below.
String getResult() {
if (bmi == null)
throw Exception(); // or return 'The bmi is null!';
if (bmi! >= 25) {
return 'Overweight';
} else if (bmi! > 18.5) {
return 'Normal';
} else
return 'UnderWeight';
}
this would happen when you call getResult or getInterpretation without calling Calculation previously, and the problem is that you are not initilizing the value of bmi which is a String? type and it's initial value is null, so when you try to use one of the methods getResult or getInterpretation you would get error because bmi is null,
you can solve the issue by initializing the bmi value in the constructor like:
bmicalculator({required this.height, required this.weight}){
bmi = weight / pow(height / 100, 2);
}
I have a function that returns a String, but when I call this function, the app screen goes red and I get this error: Expected a value of type 'string' but got one of type 'int'.
Here is my function that returns a String:
checkProportion(String predominantGamete, String resultado) {
var countBrown = 0;
var countBlack = 0;
var countWhite = 0;
var proportionCamundongo =
'Proporção: ${countBrown}:${countBlack}:${countWhite}';
if (predominantGamete == 'recessiva_aa' &&
resultado.contains('A') &&
resultado.contains('P')) {
return countBrown += 1;
} else if (predominantGamete == 'recessiva_aa' &&
resultado.contains('A') &&
resultado.contains('pp')) {
return countBlack += 1;
} else if (predominantGamete == 'recessiva_aa' &&
resultado.contains('aa')) {
return countWhite += 1;
}
return proportionCamundongo;
}
Here is how I call the function:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
title: Text(
checkProportion(widget.predominant, widget.result),
),
),
How to solve this error?
Here is an image that shows the colors of each result:
The issue here is that you are returning early, not breaking the if statement, when you do something like return countBrown += 1;;
Try incrementing the counters, then using string interpolation to display the value:
String checkProportion(String predominantGamete, String resultado) {
int countBrown = 0;
int countBlack = 0;
int countWhite = 0;
if (predominantGamete == 'recessiva_aa' &&
resultado.contains('A') &&
resultado.contains('P')) {
countBrown += 1;
} else if (predominantGamete == 'recessiva_aa' &&
resultado.contains('A') &&
resultado.contains('pp')) {
countBlack += 1;
} else if (predominantGamete == 'recessiva_aa' &&
resultado.contains('aa')) {
countWhite += 1;
}
return 'Proporção: ${countBrown}:${countBlack}:${countWhite}';
}
I'd also recommend specifing the return type of the function (String), using the correct types for counters (int). That will help your compiler catch the issues as well.
It isn't my best work, and there is probably a better way to check for if a string contains all occurrence of multiple substrings, but here you go:
bool isColorContained(String resultado, Set<String> requirements) {
for(String requirement in requirements) {
if (!resultado.contains(requirement)) {
return false;
}
}
return true;
}
String checkProportion(String predominantGamete, String resultado) {
Map<ColorType, Set<String>> colorType = {
ColorType.brown: {'A', 'P'},
ColorType.black: {'A', 'pp'},
ColorType.white: {'aa'},
};
Map<ColorType, int> colorTypeCount = {
ColorType.brown: 0,
ColorType.black: 0,
ColorType.white: 0,
};
for(MapEntry<ColorType, Set<String>> entry in colorType.entries ) {
if(predominantGamete != 'recessiva_aa') continue;
bool contained = isColorContained(resultado, entry.value);
if(contained) {
int count = colorTypeCount[entry.key] ?? 0;
colorTypeCount[entry.key] = count + 1;
}
}
return 'Proporção: ${colorTypeCount[ColorType.brown]}:${colorTypeCount[ColorType.black]}:${colorTypeCount[ColorType.white]}';
}
Also, declare the ColorType enum:
enum ColorType {
brown, black, white
}
This will scale with as many colors and requirements you have, by adding to the ColorType enum, the colorType map, and the colorTypeCount map.
How can i make _handlerRadioValuegender() update my count value which I declared as var count = 3 on top.
I tried what i can do and here are all debugprint() functions results. It is now always taking the value which I define on top means my _handler function has no effect on the count value.
var count = 3;
int _handleRadioValuegender(int value) {
setState(() {
_gender = value;
switch (_gender) {
case 0:
debugPrint('case0');
count++;
debugPrint('$count');
break;
case 1:
debugPrint('case1');
this.count++;
this.count++;
debugPrint('$count');
break;
}
});
}
String gender() {
if (count == 1) {
debugPrint('$count');
return 'Male';
} else if (count == 3) {
debugPrint('$count');
return 'Female';
} else {
debugPrint('$count');
}
}
I want my count value to be updated from my _handlerRadioValuegender() function and when gender() access it, then it should return value according to that.Screenshot of debugprints()