Skip to content

Instantly share code, notes, and snippets.

@guid-empty
Last active February 24, 2021 21:32
Show Gist options
  • Save guid-empty/662d220318031a484de09006adcbb6dd to your computer and use it in GitHub Desktop.
Save guid-empty/662d220318031a484de09006adcbb6dd to your computer and use it in GitHub Desktop.
(?. and ??=) - Conditional member access, if-null, and is-null-assignment operators

/// /// Flutter Mobile Developer /// "Conditional member access" or "null safe" operator /// Still actual but keep in the mind /// https://nullsafety.dartpad.dev/ ///

class Address { String postalCode; }

class Employee { Address address; }

class EmployeeFactory { static Employee createEmployee() => null; }

void main() { final employee = EmployeeFactory.createEmployee();

// Мы не уверены, будет ли инстанс класса Employee создан // поэтому для чтения поля postalCode // мы должны выполнить следующие проверки // Без проверки получим Null Pointer Exception в runtime // Обычный сценарий - это проверка на null всей вложенной структуры // Сначала проверяем, что сам инстанс not null, затем address not null // и так далее - код становится трудно читать if (employee != null && employee.address != null) { print(employee.address.postalCode); }

// но мы можем использовать более удобный способ // для безопасного доступа к полю, используя conditional member access // используя синтаксис ?. мы возвращаем null, если при обращении к какому то полю // по всей цепочке вниз это поле оказалось null print(employee?.address?.postalCode); // should be null

// еще один интересный оператор ?? - возвращает нам левую часть выражения, // если она != null, в противном случае возвращает прравую print(employee?.address?.postalCode ?? 'empty'); // should be empty string

// в dart есть еще один интересный assignment оператор ??=, // который можно использовать для инициализации переменной // только в том случае, если она еще == null // в примере дальше переменная firstValueInLoop получит свое значение // только при первой попытке присвоить новое значение int firstValueInLoop; for (var index = 10; index > 0; index--) { firstValueInLoop ??= index; } print('firstValueInLoop is $firstValueInLoop'); // should be 10

// этот же оператор можно использовать для // ленивой инициализации полей класса (keep in the mind "late" keyword) // например, как для свойство fibonacci в классе // ExpensiveInitialization final expensive = ExpensiveInitialization(5); print('first call > ${expensive.fibonacci}'); print('second call > ${expensive.fibonacci}'); }

class ExpensiveInitialization { int _fibonacci;

final int _number;

int _calculateFibonacci(int n) { print('expensive operation'); return n <= 2 ? 1 : _calculateFibonacci(n - 2) + _calculateFibonacci(n - 1); }

ExpensiveInitialization(this._number) { print('ExpensiveInitialization intance ctor'); }

/// здесь приватное поле _fibonacci получает свое новое значение при первом обращении, /// и потом это же значение (на самом деле значение операции assignment) возвращается геттером свойства fibonacci int get fibonacci => _fibonacci ??= _calculateFibonacci(_number); }

///
/// Flutter Mobile Developer
/// "Conditional member access" or "null safe" operator
/// Still actual but keep in the mind
/// https://nullsafety.dartpad.dev/
///
class Address {
String postalCode;
}
class Employee {
Address address;
}
class EmployeeFactory {
static Employee createEmployee() => null;
}
void main() {
final employee = EmployeeFactory.createEmployee();
// Мы не уверены, будет ли инстанс класса Employee создан
// поэтому для чтения поля postalCode
// мы должны выполнить следующие проверки
// Без проверки получим Null Pointer Exception в runtime
// Обычный сценарий - это проверка на null всей вложенной структуры
// Сначала проверяем, что сам инстанс not null, затем address not null
// и так далее - код становится трудно читать
if (employee != null && employee.address != null) {
print(employee.address.postalCode);
}
// но мы можем использовать более удобный способ
// для безопасного доступа к полю, используя conditional member access
// используя синтаксис ?. мы возвращаем null, если при обращении к какому то полю
// по всей цепочке вниз это поле оказалось null
print(employee?.address?.postalCode); // should be null
// еще один интересный оператор ?? - возвращает нам левую часть выражения,
// если она != null, в противном случае возвращает прравую
print(employee?.address?.postalCode ?? 'empty'); // should be empty string
// в dart есть еще один интересный assignment оператор ??=,
// который можно использовать для инициализации переменной
// только в том случае, если она еще == null
// в примере дальше переменная firstValueInLoop получит свое значение
// только при первой попытке присвоить новое значение
int firstValueInLoop;
for (var index = 10; index > 0; index--) {
firstValueInLoop ??= index;
}
print('firstValueInLoop is $firstValueInLoop'); // should be 10
// этот же оператор можно использовать для
// ленивой инициализации полей класса (keep in the mind "late" keyword)
// например, как для свойство fibonacci в классе
// ExpensiveInitialization
final expensive = ExpensiveInitialization(5);
print('first call > ${expensive.fibonacci}');
print('second call > ${expensive.fibonacci}');
}
class ExpensiveInitialization {
int _fibonacci;
final int _number;
int _calculateFibonacci(int n) {
print('expensive operation');
return n <= 2 ? 1 : _calculateFibonacci(n - 2) + _calculateFibonacci(n - 1);
}
ExpensiveInitialization(this._number) {
print('ExpensiveInitialization intance ctor');
}
/// здесь приватное поле _fibonacci получает свое новое значение при первом обращении,
/// и потом это же значение (на самом деле значение операции assignment) возвращается геттером свойства fibonacci
int get fibonacci => _fibonacci ??= _calculateFibonacci(_number);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment