rust_like_result 2.7.1 rust_like_result: ^2.7.1 copied to clipboard
The Result<T> type implemented in Ok<T> and Err<T> types with unwrap methods.
import 'dart:convert';
import 'dart:io';
import 'package:rust_like_result/rust_like_result.dart';
void main() async {
// Ok:
Result<Map> res = Ok({'Forward': 'yes', 'Back': 'no'});
print(res); // Ok({Forward: yes, Back: no})
print(res is Ok ? 'Ok' : 'Err'); // Ok
print(res.unwrap); // {Forward: yes, Back: no}
print(res.unwrapOrDefault({})); // {Forward: yes, Back: no}
print(res.unwrapOrElse((e) => {'error': e})); // {Forward: yes, Back: no}
// Err:
res = Err(ArgumentError('Bad name'));
print(res); // Err(Invalid argument(s): Bad name)
print(res is Ok ? 'Ok' : 'Err'); // Err
// print(res.unwrap); // <--try uncomment it. Raises exception 'Invalid argument(s): Bad name'
print(res.unwrapOrDefault({})); // {}
print(res.unwrapOrElse(
(e) => {'Got error': e})); // {Got error: Invalid argument(s): Bad name}
// tryAsResult...() - calls function and return result as Ok, or Err if exception was raised:
var res1 =
await tryAsResultAsync(() => File('notExistsFile').rename('newPath'));
print(res1); // Err(Bad state: FileSystemException: Cannot rename ...
var res2 = await tryAsResultAsync(() => Directory('.').list());
print(res2); // Ok(Instance of '_ControllerStream<FileSystemEntity>')
var res3 = tryAsResultSync(() => File('notExistsFile').renameSync('newPath'));
print(res3); // Err(Bad state: FileSystemException ...
var res4 = tryAsResultSync(() => Directory('.').listSync());
print(res4); // Ok([File:...
// ok() - use it when you sure that will produce value for Ok(),
// pipe() - use it when can produce value for Ok(), Err(), Error() or null:
var r = Ok(123).ok((x) => x * 2).pipe((x) => 246 / x);
print(r); // Ok(1)
// Long cascading:
var r2 = Ok(123)
.ok((x) => x * 2)
.ok((x) => x + 4)
.onResult(stderr.writeln) // <-- print current Result to stderr
.ok((x) => x * 2)
.ok((x) => x / 5)
.ok((x) => 'My answer is: $x')
.unwrapOrElse((e) => 'Was some error:$e');
print(r2); // My answer is: 100.0
// All after Err() will not calculated:
var r3 = Err(ArgumentError('Your argument is bad'))
.ok((x) => x * 2)
.ok((x) => x + 4)
.ok((x) => x * 2)
.ok((x) => x / 5)
.ok((x) => 'My answer is: $x')
.unwrapOrElse((e) => 'Was some error:$e');
print(r3); // Was some error:Invalid argument(s): Your argument is bad
var r4 = Ok(123)
.ok((x) => x * 2)
// Possible to use pipe() if function may return Ok,Err,Error, null,
// but it's better to define a type parameter (because pipe() not infer returned type):
.pipe<int>((x) => Ok(x + 4))
// With pipe() not need to wrap error with Err() like:
// .pipe((x) => Err(AssertionError('My assertion error')))
// Be simple:
.pipe<int>((x) => AssertionError('My assertion error'))
.ok((x) => x / 5)
.ok((x) => 'My answer is: $x')
.unwrapOrElse((e) => 'Was some error:$e');
print(r4); // Was some error:Assertion failed: "My assertion error"
// =========== Realworld cascading sample: =========================
var client = HttpClient();
var addr1 = Uri.parse('https://vlang.io/utc_now');
// When function returns Future, use tryAsResultAsync(), pipeAsync(), okAsync().
// And remember about `await` before whole expression.
// ( Otherwise - use tryAsResultSync(), pipe(), ok() and so on ).
await tryAsResultAsync(() => client.getUrl(addr1))
.pipeAsync<HttpClientResponse>((request) => request.close())
.pipeAsync<String>((response) => response.transform(utf8.decoder).join())
.pipe<int>((text) => int.tryParse(text))
.ok((shortMilliseconds) => shortMilliseconds * 1000)
.pipe<DateTime>(
(timestamp) => DateTime.fromMillisecondsSinceEpoch(timestamp))
// execute only when Ok():
.onOk((dt) => stderr.writeln('Got datetime: $dt'))
// execute only when Err():
.onErr((e) => stderr.writeln('Cant get datetime: $e'));
// It's cool, but...
// All operations above may be rewrited as one simple function.
// Note that you don't need to catch any exceptions inside this function.
// Code can throws exception.
// Or it can return null if you want. Then it return type will like a Future<DateTime?>.
Future<DateTime> dateTimeFromVlang() async {
var request = await client.getUrl(addr1);
var response = await request.close();
var text = await response.transform(utf8.decoder).join();
var timestamp = int.parse(text) * 1000;
return DateTime.fromMillisecondsSinceEpoch(timestamp);
}
// tryAsResultAsync() will catch any axceptions inside your function dateTimeFromVlang().
// ( See also tryAsResultSync() method. )
// Also, if dateTimeFromVlang() will return null, then tryAsResultAsync() will return Future of Err().
await tryAsResultAsync(dateTimeFromVlang)
// there is interesting way to print any result:
.onResult(print); // Ok(2022-05-...)
// Let declare alternative way to get datetime:
var addr2 = Uri.parse('http://worldtimeapi.org/api/ip');
Future<DateTime> dateTimeFromWTA() async {
var request = await client.getUrl(addr2);
var response = await request.close();
var text = await response.transform(utf8.decoder).join();
// Again, we don't worry about possible exceptions here:
var timestamp = jsonDecode(text)['unixtime'] * 1000;
return DateTime.fromMillisecondsSinceEpoch(timestamp);
}
// Now we can chain two alternative ways via `orAsync()` method.
// (See alse `or()` method for sync calculations. )
// If first way will failed then second will tried:
await tryAsResultAsync(dateTimeFromVlang)
.onResult((r) => stderr.writeln('First way give me: $r'))
.orAsync(dateTimeFromWTA)
.onResult((r) => stderr.writeln('Result is: $r'));
// First way give me: Ok(2022-05-...)
// Result is: Ok(2022-05-...)
// Try replace first addr1 to some bad (then calling of dateTimeFromVlang() will failed):
addr1 = Uri.parse('https://some_bad_addr');
await tryAsResultAsync(dateTimeFromVlang)
.onResult((r) => stderr.writeln('First way give me: $r'))
.orAsync(dateTimeFromWTA)
.onResult((r) => stderr.writeln('Result is: $r'));
// First way give me: Err(Bad state: SocketException: Failed host lookup...))
// Result is: Ok(2022-05-...)
}