Search
Write a publication
Pull to refresh
10
0

Моя литера Т стремится к равнозначности линий

Send message

Как часто вы сталкивались с проблемой изменения данных, переданных в качестве параметра? Иллюстрация:

int getCountBagel(List<String> list) {
  list.retainWhere((e) => e == '?');
  return list.length;
}

main() {
  final basket = ['?', '?', '?', '?', '?'];
  final countBagel = getCountBagel(basket); // 2
  print(basket); // [?, ?]
}

Выполнив копирование getCountBagel([...basket]), вы обезопасите себя. Да, это ужасный способ посчитать количество элементов. Но представьте, что вы зависите от стороннего api, к которому у вас нет непосредственного доступа.

Обратная задача: в Dart примитивные типы всегда передаются по значению. Это означает, что если вы передаёте экземпляр примитивного типа в качестве параметра в функцию (или класс) и внутри его изменяете, то оригинальный экземпляр останется неизменным:

void increase(int i) => i++;

main() {
  int i = 0;
  increase(i);
  print(i); // 0
}

Если вы хотите передать что-то по ссылке, то заверните это в класс:

class Wrapper {
  Wrapper(this.i);
  int i;
}

void increase(Wrapper w) => w.i++;

main() {
  final w = Wrapper(0);
  increase(w);
  print(w.i); // 1
}

но такой способ ухудшит SRP (принцип единой ответственности) и усложнит тестирование функции increase... Ответ в комментарии ?

Tags:
Total votes 1: ↑1 and ↓0+1
Comments1

В Dart 3.0 появились Switch expressions, что позволяет сразу получить значение на основе выражения. Это может выглядеть так:

var x = switch (y) { ... };
print(switch (x) { ... });
return switch (x) { ... };

Сейчас я расскажу, какие преимущества даст новый подход. ?

habr...
habr...

Теперь, когда мы получили погодные данные (Pop.medium и temp = 17.0 ) из приложения Weather Today, наш код будет выглядеть следующим образом:

/// Probability of precipitation
enum Pop { low, medium, high }

enum Things {
  umbrella, // зонт
  raincoat, // дождевик
  windbreaker, // ветровка
  glasses, // очки
  ;

  List<Things> takeExtra(double temp /*Celsius*/, Pop pop) {
    return ...;
  }
}

Для удобства я определил метод takeExtra внутри enum, чтобы иметь доступ к значениям без использования Things. всякий раз. Подумайте, как бы вы реализовали данный метод.

У меня получился вот такой код:

List<Things> takeExtra(double temp /*Celsius*/, Pop pop) => 
    switch (pop) {
      Pop.low when temp >= 10 => [glasses, windbreaker],
      Pop.low when temp < 10 => [windbreaker],
      Pop.medium when temp > 24 => [windbreaker],
      Pop.medium => [umbrella, windbreaker],
      Pop.high => [umbrella, raincoat],
      _ => [glasses],
    };

Заметьте, это выглядит достаточно ёмко и выразительно. Страшно представить, какая цепочка switch case и if'ов могла выстроиться в этом методе. И всё же, используйте с умом данное новшество – лучше написать понятней, чем вычурней.

А в завтрашний поход я возьму зонт и ветровку. ?

Total votes 7: ↑7 and ↓0+7
Comments1

Как создать неизменяемый список – UnmodifiableListView или List.unmodifiable?

Для начала, давайте попробуем создать неизменяемый (именно unmodifiable, не путать с immutable) список разными способами:

// Dart version: 3.1.0 - 11.0.dev
import 'dart:collection';

void main() {
  // Выводимый тип - List<String>
  const colors = ['?', '?', '?', '?']; // или final

  // Выводимый тип - List<dynamic>
  final colors1 = List.unmodifiable(colors); 
  // используйте List<String>.unmodifiable(), чтобы тип выводился

  // Выводимый тип - UnmodifiableListView<String>
  final colors2 = UnmodifiableListView(colors);
}

Теперь давайте попробуем изменить первый элемент коллекции:

colors[0] = '?';
colors1[0] = '?';
colors2[0] = '?';

В каждом случае мы получим:

Unhandled Exception: Unsupported operation: Cannot modify an unmodifiable list

Неизменяемый список создан, что очень хорошо, однако, здесь есть подводные камни. Сложность алгоритма для List.unmodifiable – O(n), а для UnmodifiableListView – O(1)? Почему?

Продолжение в комментарии ↲

Total votes 3: ↑3 and ↓0+3
Comments3

Начиная с dart 2.3.0 были представлены новые функции, которые прокачивают возможности добавления новых элементов в коллекцию. Об одной из них и пойдёт речь – spread (распространение).

Как использовать? Поместите ... перед коллекцией внутри литерала коллекции, и элементы будут в неё добавлены. Предположим, у нас есть две корзины: с фруктами и ягодами. Необходимо всё переложить в нашу корзину:

final fruitBasket = ['?', '?', '?', '?'];
final berriesBasket = ['?', '?'];

final myBasket = [...fruitBasket, '?', ...berriesBasket, ...['?']];

Раньше мы бы написали так:

final myOldBasket = []
  ..addAll(fruitBasket)
  ..add('?')
  ..addAll(berriesBasket)
  ..addAll(['?']);

Казалось бы, не так страшно. Но, посмотрите, как старый способ будет выглядеть в flutter:

ProductsPage(
  child: ListView(
    children: [
      Text('Products'),
      Divider(),
    ]
      ..addAll(buildBasketWidget(fruitBasket))
      ..add(ProductWidget('?'))
      ..addAll(buildBasketWidget(berriesBasket))
      ..addAll(buildBasketWidget(['?'])),
  ),
);

List<Widget> buildBasketWidget(List basket) {...}

И с помощью оператора "распространения":

ProductsPage(
  child: ListView(
    children: [
      Text('Products'),
      Divider(),
      ...buildBasketWidget(fruitBasket),
      ProductWidget('?'),
      ...buildBasketWidget(berriesBasket),
      ...buildBasketWidget(['?']),
    ],
  ),
);

Очевидно, что spread позволяет сделать код более выразительным и декларативным, а также приятным для чтения.

Total votes 12: ↑12 and ↓0+12
Comments3

Information

Rating
11,649-th
Registered
Activity