Элегантная обработка ошибок в Dart, например Scala's `Try` - PullRequest
0 голосов
/ 27 ноября 2018

Класс данных в Dart:

import 'package:validate/validate.dart';
class AuthUser {
  final String email, token, username, bio, image;

  AuthUser(this.email, this.token, this.username, this.bio, this.image) {
    Validate.isEmail(this.email);
  }

  @override
  String toString() {
    return 'AuthUser{email: $email, token: $token, username: $username, bio: $bio, image: $image}';
  }
}

, где Validate.isEmail выдает ошибку, если не удается найти соответствие:

static void matchesPattern(String input, RegExp pattern,[String message = DEFAULT_MATCHES_PATTERN_EX]) {
    if (pattern.hasMatch(input) == false) {
        throw new ArgumentError(message);
    }
}

static void isEmail(String input,[String message = DEFAULT_MATCHES_PATTERN_EX]) {
    matchesPattern(input,new RegExp(PATTERN_EMAIL),message);
}

Теперь я хочу использовать элегантный способ для новогоэтот класс.При использовании Scala я могу использовать Try(new AuthUser(...)) и сопоставлять его с паттенами.

И в Dart сначала я попробовал RxDart,

void main() {
  testWidgets('Counter increments smoke test', (WidgetTester tester) async {
    Observable.just(AuthUser("email", "token", "username", "bio", "img"))
        .doOnError((e, s) => print("oh no"))
        .listen((e) => print(e.toString()));
  });
}

Не работает, тест не пройден для ошибки (что означает, что RxDart вообще не распознает ошибки !!!)

И я хочу попробовать Future, также не удалось.

И я хочу использовать dartz, но я волнуюсь, потому что естьтолько один сопровождающий ...

Любой совет?

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018

Если вам нужна только базовая функциональность возврата любого типа в зависимости от того, произошло исключение или нет, вы можете легко создать служебный класс, такой как ниже.

В противном случае я рекомендую @ SergGr ответить на вопрос об использовании Future.sync, так как он дает вам более монадический конвейер.

void main() {
  Try<Error, void> result = Try.it(() => Validate.isEmail("test-example.com"));

  if (result is Success) {
    print("Good");
  } else if (result is Failure) {
    print("Error: " + result.exception().toString());
  }
}

typedef TryExec<V> = V Function();

abstract class Try<E extends Error, V> {

  static Try<E, V> it<E extends Error, V>(TryExec<V> fn) {
    try {
      return Try.success(fn());
    } catch (e) {
      return Try.failure(e);
    }
  }

  static Try<E, V> failure<E extends Error, V>(Error e) {
    return new Failure(e);
  }

  static Try<E, V> success<E extends Error, V>(V v) {
    return new Success(v);
  }
}

class Failure<E extends Error, V> extends Try<E, V> {
  final E _e;
  Failure(this._e);

  E exception() => _e;
}

class Success<E extends Error, V> extends Try<E, V> { 
  final V _v;
  Success(this._v);

  V value() => _v;
}
0 голосов
/ 28 ноября 2018

Если вы согласны с использованием Future, что не так с этим советом: Использование Future.sync () для переноса кода ?Код будет выглядеть следующим образом:

void main() {
  var f = Future.sync(() {AuthUser("email", "token", "username", "bio", "img"); });
  f.then((v) =>  print("Value: " + v.toString())).catchError((e) => print("Failure: " +e.toString()));
}

Основная хитрость заключается в том, что Future.sync эффективно разрешает ленивую оценку параметра, но вы должны передать свой параметр, заключенный в функцию.На самом деле это тот же трюк, который компилятор Scala делает для Try (то есть для параметров вызова по имени), но требует добавления нескольких скобок.

...