Flutter/Dartの関数(メソッド)で複数の戻り値(返り値)を返す方法

Flutter

Flutter/Dartの関数(メソッド)で、2つ以上の戻り値(返り値)を返したいけど、どうしたらいいの?

という方向けの記事です。

 

どうしても複数の戻り値を返したいときがあり、調べたところ、ニーズがないためか、当たり前過ぎるためか、、ググっても意外と日本語の情報が少なかったので、整理してみました。

 

調査・検討した結果、以下3つの方法があると理解しました。

 

  1. List型を戻り値にする
  2. Map型を戻り値にする
  3. Tuple型を戻り値にする(「tuble」パッケージが必要)

 

理解不足ゆえ、もっと良い方法があるようでしたら、是非ご指摘くださいm(_ _)m。

 

※クラス内の関数をメソッド(method)、クラス外の関数を関数(function)と呼びますが、本記事では「関数」に統一して記載しています。

 


 

40代からプログラミング(Flutter)を始めて、GooglePlayAppStoreにアプリを公開しているhalzo appdevです。

 

作成したアプリはこちら↓ 全てFlutterで開発したアプリです。

 

暗記用マーカー – シンプル穴埋め問題作成

Google Play で手に入れよう
Download on the App Store

 

超即ToDo –最短2タップで通知登録できるタスク管理アプリ

Google Play で手に入れよう
Download on the App Store

 

かんたんプリント管理:アラート・OCR文字認識・検索機能を搭載

Google Play で手に入れよう
Download on the App Store

 

シンプルメモ帳「BasicMemo」 – 文字カウント、ワンタッチ入力、タグ管理等の機能を搭載

Macのデスクトップ版もリリースしました。

Google Play で手に入れよう
Download on the App Store

 

Dartの標準文法にはない模様

Dartの公式サイト内を探ってみましたが、複数の戻り値を返す方法について、説明は見当たりませんでした。

 

「Functions」の説明

 

「Methods」の説明

 

こちらの記事にも、Dartで検討中との情報がありました。

 

 

もう少し調べると、GitHubにズバリのイシューが立っていました。

 

 

まだOpen中なので、2022.8時点でも検討中のようです。

 

プログラミング言語には、複数の戻り値を返せる言語、返せない言語があるようですが、今のところ、Dartは返せない言語みたいです。

 

List型を戻り値にする

何か方法がないか考え、最初に思いついたのが、List型を戻り値にする方法です。

 

return [“文字列”, 100, 0.55, true]

 

のように、戻り値を指定します。

 

複数の型を返したい場合は、関数の戻り値の型を、

 

  • 書かない
  • varにする
  • List<dynamic>にする

 

のいずれかにすれば、問題なくできました。

 

ただ、戻り値を使用するとき、配列番号で指定する必要があるので、可読性にやや難がある印象です。

 

Map型を戻り値にする

次に考えたのは、Map型を戻り値にする方法です。

 

return {“戻り値1”: “文字列”, “戻り値2”: 100, “戻り値3”: 0.55, “戻り値4”: true}

 

のように、戻り値を指定します。

 

こちらも複数の型を返したい場合は、関数の戻り値の型を、

 

  • 書かない
  • varにする
  • Map<String, dynamic>にする

 

のいずれかにしておけば、問題なくできました。

 

Tuple型を戻り値にする

Tuple型について

こちらに紹介されていました。

 

 

Tuple型の定義は、言語によっても異なるようですが、大まかには複数の異なる型の組み合わせを、1つの変数で持つ方法で、List型やMap型と異なり、後で要素を直接変更できないものと理解しました。

 

Dartには標準でTuple型がないので、使用するには、下記の「tuple」パッケージを導入する必要があります。

 

 

ターミナルから、「flutter pub add tuple」でインポートします。

 

Tupleパッケージの使い方

例えば、4つの戻り値を返したい場合は、以下のように記述します。

 

return Tuple4<String, int, double, bool>(“文字列”, 100, 0.55, true);

 

「Tuple」の後に書く数字が、戻り値の数を表しています(直接数字を書くところがやや戸惑いましたが)。

 

ソースコードを調べると、「Tuple2」から「Tuple7」までのクラスが用意されているので、7つの値までなら定義できるようです。※「Tuple8」以上にしたらエラーになりました。

 

List型やMap型のケースと比べ、各要素の型を明示できるのはメリットかと思いました。

 

また、Tuple型の各要素にアクセスするには、「item1」から「item7」というプロパティが用意されているので、

 

Tuple型の変数名.item3

 

などとすることで、各要素を取り出すことができます(上記は3番目の要素にアクセスする例)。

 

Tuple型の注意点

前述のとおりTuple型は、要素を直接変更できません。

 

直接変更しようとすると、

 

‘item2’ can’t be used as a setter because it’s final.

 

のようなエラーになります。

 

但し、一度作成したTuple型の変数を、別のTuple型で再代入することは可能です。

 

サンプルコード

3つの戻り値を、List型、Map型、Tuple型で返す場合のサンプルコードを作成したので、ご参考に共有します。

 

なお、任意のモデルクラスも戻り値として返せることを確認するため、

 

  • String(文字列)型
  • ModelDataO(自作したモデルクラス)型
  • double型

 

の3つを返すケースとして作成しました。

 

コピーして貼り付ければ、そのまま実行いただけます。

 

※コンソールに結果を表示することが目的なので、画面表示は、ダミーの空Containerにより真っ暗になります。

// クラス名、メソッド名、プロパティ名(変数名)について、筆者が作成したもの(名前変更可のもの)
// の名前の末尾には、大文字のオー「O」をつけています
// ※ライブラリ(パッケージ)で予め決められているもの(名前の変更不可のもの)と、
//  自分で作成したもの(名前の変更可のもの)の区別をしやすくするため

import 'package:flutter/material.dart';
import 'package:tuple/tuple.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Sample code",
      home: SampleScreen(),
    );
  }
}

// bool型とint型の変数からなるモデルクラスを定義
class ModelDataO {
  final bool testBoolO;
  final int testIntO;

  const ModelDataO({
    required this.testBoolO,
    required this.testIntO,
  });
}

class SampleScreen extends StatefulWidget {
  @override
  _SampleScreenState createState() => _SampleScreenState();
}

class _SampleScreenState extends State<SampleScreen> {

  // 3つの戻り値をList型で返す場合のメソッド定義
  List<dynamic> testMethodByListO() {
    String textO = "Test text";
    ModelDataO modelDataO = ModelDataO(
      testBoolO: true,
      testIntO: 105,
    );
    double doubleValueO = 3.14;
    return [textO, modelDataO, doubleValueO];
  }

  // 3つの戻り値をMap型で返す場合のメソッド定義
  Map<String, dynamic> testMethodByMapO() {
    String textO = "Test text";
    ModelDataO modelDataO = ModelDataO(
      testBoolO: true,
      testIntO: 105,
    );
    double doubleValueO = 3.14;
    return {"String型": textO, "ModelDataO型": modelDataO, "double型": doubleValueO};
  }

  // 3つの戻り値をTuple型で返す場合のメソッド定義
  Tuple3<String, ModelDataO, double> testMethodByTupleO() {
    String textO = "Test text";
    ModelDataO modelDataO = ModelDataO(
      testBoolO: true,
      testIntO: 105,
    );
    double doubleValueO = 3.14;
    return Tuple3<String, ModelDataO, double>(textO, modelDataO, doubleValueO);
  }


  @override
  Widget build(BuildContext context) {

    // List型を返すメソッドの呼び出し
    List<dynamic> returnListO = testMethodByListO();
    print("Listを使った結果");
    // 1つ目の戻り値を表示
    print(returnListO[0]);
    // 2つ目の戻り値を表示(モデルクラス内の変数を個別に表示)
    print(returnListO[1].testBoolO);
    print(returnListO[1].testIntO);
    // 3つ目の戻り値を表示
    print(returnListO[2]);

    // Map型を返すメソッドの呼び出し
    Map<String, dynamic> returnMapO = testMethodByMapO();
    print("Mapを使った結果");
    // 1つ目の戻り値を表示
    print(returnMapO["String型"]);
    // 2つ目の戻り値を表示(モデルクラス内の変数を個別に表示)
    print(returnMapO["ModelDataO型"].testBoolO);
    print(returnMapO["ModelDataO型"].testIntO);
    // 3つ目の戻り値を表示
    print(returnMapO["double型"]);

    // Tuple型を返すメソッドの呼び出し
    Tuple3<String, ModelDataO, double> returnTupleO = testMethodByTupleO();
    print("Tupleを使った結果");
    // 1つ目の戻り値を表示
    print(returnTupleO.item1);
    // 2つ目の戻り値を表示(モデルクラス内の変数を個別に表示)
    print(returnTupleO.item2.testBoolO);
    print(returnTupleO.item2.testIntO);
    // 3つ目の戻り値を表示
    print(returnTupleO.item3);

    // 画面の描画は不要なため空Containerを設置
    return  Container();
  }

}

 

コンソールの実行結果は以下のとおりです。いずれの方法でも、同じ結果が得られています。

 

I/flutter ( 1751): Listを使った結果
I/flutter ( 1751): Test text
I/flutter ( 1751): true
I/flutter ( 1751): 105
I/flutter ( 1751): 3.14
I/flutter ( 1751): Mapを使った結果
I/flutter ( 1751): Test text
I/flutter ( 1751): true
I/flutter ( 1751): 105
I/flutter ( 1751): 3.14
I/flutter ( 1751): Tupleを使った結果
I/flutter ( 1751): Test text
I/flutter ( 1751): true
I/flutter ( 1751): 105
I/flutter ( 1751): 3.14

 

なお、戻り値用のモデルクラスを作り、それを戻り値にすることでも、同じことができると気づきました。。(記述量が多くなるので、かなり面倒ですが)

 

まとめ(どれがよいか?)

目的によって、以下のように使い分けるのが良いと感じました。

 

  • 手軽に済ませたいとき → List型
  • 可読性を高めたいとき → Map型
  • 要素(個々の戻り値)の型を明示したいとき → Tuple型

 


 

以上、ご参考になれば幸いです。

 

最後までお読みいただき、ありがとうございました。

 

個人アプリ開発で役立ったもの

おすすめの学習教材

超初心者向けでオススメな元Udemyの講座/

 

\Gitの基礎について無料で学べる/

 

おすすめの学習書籍

実用的image_pickerに関してかなり助けられた/

 

Dartの基礎文法を素早くインプットできる/


Dart入門 – Dartの要点をつかむためのクイックツアー

 

おすすめのソフトウェア

安くて高機能。アプリの独自ドメイン・紹介サイト構築に最適/

 

\アイコン作成・画面設計・クラウド保存…何でもできて超必須

 

おすすめのハードウェア

\リーズナブルな価格で検証端末を確保できる/

 

\目線の高さを調節しやすく、疲れにくい

 

\キータッチが超静音で心地よい/

 

おすすめのサポートアイテム

\部屋の中を仕切って、集中できる開発環境を作れる/

 

\部屋の中でも大き過ぎず、長時間座っても疲れない

 

\バグと格闘した後の肩こりを解消してくれる/

コメント

タイトルとURLをコピーしました