flutter_rust_bridgeのResult型
はじめに
flutter_rust_bridgeでRustを呼び出す方法を勉強中です。
今回は、RustでResult型を返すとFlutter側ではどうなるか、を調べました。
- Windows 11
- Flutter 3.22.2
- Dart 3.4.3
- rustc 1.76.0
プロジェクト作成
cargo install flutter_rust_bridge_codegen && flutter_rust_bridge_codegen create my_app && cd my_app && flutter run
&& flutter runによりアプリ立ち上がりまで進みます
作成されたソースコードを編集していきます。
呼び出すRustのコードがResult型を返すように変更をしていきます。
Result<T,E>
を返す対応
FlutterにRustソース編集
rust\src\api\simple.rs
- MyError型の作成
- Display/Debug/Error traitを実装
- greetの修正
- 戻り値をcore::result::Result<T, MyError> に変更
- 引数nameが空のときエラーを返すように変更
use std::fmt::Display;
#[derive(Debug)]
pub enum MyError{
Empty,
}
impl Display for MyError{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self{
MyError::Empty => f.write_str("Empty!!!"),
}
}
}
impl std::error::Error for MyError{}
pub type Result<T> = core::result::Result<T, MyError>;
#[flutter_rust_bridge::frb(sync)] // Synchronous mode for simplicity of the demo
pub fn greet(name: String) -> Result<String> {
if !name.is_empty(){
Ok(format!("Hello, {name}!"))
}else{
Err(MyError::Empty)
}
}
Dartコード自動生成
flutter_rust_bridge_codegen generate --watch
UIの変更
lib\main.dart
- greetの引数nameを入力可能に書き換える
- StatefulWidgetに変更
- TextEditingControllerを配置しonSubmittedでgreetを呼び出して結果を表示
class MyApp extends StatefulWidget {
const MyApp({super.key});
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
TextEditingController nameController = TextEditingController();
String disptext = "";
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('flutter_rust_bridge quickstart')),
body: Column(
children: [
TextField(
controller: nameController,
onSubmitted: (name) {
setState(() {
try {
disptext = greet(name: name);
} catch (e) {
disptext = e.toString();
}
});
},
),
Center(
child: Text(disptext),
),
],
),
),
);
}
}
fn greet(name:String)->Result<String>の実行
正常時は Hello, {name}!
が表示されます。
エラー時は、コードのほうでネタバレしていますが、例外となります。flutter_rust_bridgeではResult::Errは例外に変換されます。
Arbitrary custom error type (fn f() -> Result<String, YourErrorType>): The YourErrorType will be automatically converted to a Dart exception.
試しに実行してみるとAnyhowException(Empty!!!)
が表示されました。
Crate anyhowになるのですね
では、Rustと同じようにenum{Ok(T),Err(E)}
にできるのか?
下記リンクに説明があります。
freezed
というDart libraryで対応しているようです。こちらも試してみます。
enum{Ok(T),Err(E)}
を返す対応
Flutterにfreezed導入
flutter pub add freezed_annotation
flutter pub add dev:build_runner
flutter pub add dev:freezed
# if using freezed to generate fromJson/toJson, also add:
flutter pub add json_annotation
flutter pub add dev:json_serializable
Rust修正
- enum CustomResultの作成
- greetの戻り値をCustomResultに変更した関数を作成
pub enum CustomResult{
Ok(String),
Err(MyError),
}
#[flutter_rust_bridge::frb(sync)] // Synchronous mode for simplicity of the demo
pub fn greet2(name: String) -> CustomResult {
if !name.is_empty(){
CustomResult::Ok(format!("Hello, {name}!"))
}else{
CustomResult::Err(MyError::Empty)
}
}
UIの変更
lib\main.dartを変更
setState(() {
greet2(name: name).when(
ok: (field0) => disptext2 = field0,
err: (field0) => disptext2 = field0.toString(),
);
});
greet2のwhenは以下のように定義されています。
okのときとerrのときのクロージャをそれぞれ設定しているようですね。
TResult when<TResult extends Object?>({
required TResult Function(String field0) ok,
required TResult Function(MyError field0) err,
}) =>
throw _privateConstructorUsedError;
fn greet2(name:String)->CustomResultの実行
正常時はgreetと同じです。
エラー時はMyError.empty
が表示されました。
Display traitの結果ではなく、型名が表示されているようですね
enumのマッチングのやり方がちょっと違いますが、雰囲気は同じですね。
あとがき
flutter_rust_bridgeを調べ始めた理由は、Rust Core 1.0というものがリリースされたという記事を見たのがきっかけです。
正直なところ、なぜこんなものを…というのが第一印象です。Result型も対応されていたりしますが、DartにRustっぽさが入ってくることになるのですが、どうなのでしょうか?
とはいえ興味はあるので今後触れたらいいなと思っています。
Discussion