🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

Q&A

1回答

1020閲覧

DartのListクラスのイテレート機能に関する実装について

moriman

総合スコア615

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

0グッド

0クリップ

投稿2020/11/27 05:10

編集2020/11/29 07:03

Dart(Flutter)のIterable,iteratorについて調べています。
Iterable,iteratorなどのざっくりとした仕組みについてはつかめたのですが、
Iterableの代表的な型であるList型について、ソースコードを見ると、

↓まず、List<E>クラスが抽象クラスEfficientLengthIterable<E>クラスを実装している。
List<E>クラス内にiteratorプロパティに関する記述がない。
コンストラクタで初期化しているようなコードも見当たらない。

//list.dart abstract class List<E> implements EfficientLengthIterable<E> { ...

↓EfficientLengthIterable<T>クラスのスーパークラスがIterable<T>クラス。
EfficientLengthIterable<T>自体にはiteratorプロパティの実装コードはない。
(少し下にListIterable<E>クラスが定義されており、ListIterableクラスにはiteratorプロパティの初期化コードがある。
しかしList<E>クラスがListIterable<E>を継承などしているようなコードが見当たらない。)

//internal/iterable.dart abstract class EfficientLengthIterable<T> extends Iterable<T> { const EfficientLengthIterable(); int get length; } abstract class ListIterable<E> extends EfficientLengthIterable<E> { ...

↓Iterable<E>クラスのiteratorプロパティは宣言されているが、宣言されているだけで初期化はされていない。(抽象クラスなので、それが普通だと思いますが。)

//core/iterable.dart abstract class Iterable<E> { ... Iterator<E> get iterator; ...

ざっと見るとこういう感じで、これだとList<E>クラスのインスタンスのiteratorプロパティは初期化されてないのでnullになってしまうような気がします。
それだとリストのイテレートもできないと思うのですが、
実際は(当然のように)普通にイテレートできます。

EfficientLengthIterable<T>クラスの定義の下に
ListIterable<E>クラス
ListIterator<E>クラス
などの定義があり、List<E>クラスがListIterable<E>クラスを継承していれば辻褄が合うように思います。
(細かく見たわけではないですが、ざっくりと見て辻褄が合いそうな感じはします。)
名前を見ても継承してそうな感じがします(笑)
でもそのような関係性を示すコードが見当たりません。

普通に見るとクラス階層は、
スーパークラス ← Iterable<E> ← EfficientLengthIterable<T> ← List<E> ←サブクラス
のようにしか見えません。
(implementsが使われているので、List<E>はEfficientLengthIterable<T>のサブクラスではありませんが。)
上記のクラス階層だと、ListIterable<E>のメンバ(ListIteratorインスタンスで初期化されたiteratorプロパティ)をList<E>が継承することはできないですよね。

どこか他の場所でList<E>クラスとListIterable<E>クラスの関係性を示すコードがあるのでしょうか?
それともこのコードでList<E>クラスのインスタンスのiteratorプロパティは適切に初期化されるのでしょうか?

2020/11/29/15:30追記
質問の主旨なのですが、

iterable、iteratorなどの基本を学ぶ中で、

リストリテラルなどで生成したList<E>型のインスタンスがfor-inループでイテレートできる以上、List<E>インスタンス内のiteratorプロパティに有効なIterator<E>(あるいはそのサブクラス)のインスタンスがセットされているはずなので、それをソースコードで確認したい、

という考えが発生しました。
それを確認するためにソースコードのどこを見れば良いか、ということが質問の主旨です。
リストリテラルで生成されるリストがList<E>型のコンストラクタで生成されるとすると、

結局List<E>クラスのコンストラクタが、(toast-uz様にお示し頂いた)Iterable.generate()コンストラクタを呼び出しているなら、
ListIterableのサブクラスが生成されるので、全てつながると思うのですが、
List<E>クラスのコンストラクタを見ると

external factory List.filled(int length, E fill, {bool growable = false});

のようにコンストラクタは全てexternal修飾子がついていて、ボディが記述されていないようです。
externalというのは、メソッド(コンストラクタ)のボディは別の場所で定義されている、ということらしいのですが、
その場所ってどこなのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ドキュメントとGitHubを行ったり来たりして解き明かしてみました。

まず、Iterableクラスそのものにiteratorプロバティが定義されていますので、Listを見る必要はありません。
Iterable<E> class

Iterableクラスの実装を見ると、Iterator<E> get iterator;と書かれているのは質問者様のご報告通りです。
GitHub dart-lang/sdk - sdk/lib/core/iterable.dart

しかし「iteratorプロパティは初期化されてない」としたのが誤解でした。実は、Iterableクラスのコンストラクタをちゃんと見る必要がありました。実際、コンストラクタの1つであるIterable.generateの実装を見ると、以下のようになっています。

Dart

1 factory Iterable.generate(int count, [E generator(int index)?]) { 2 if (count <= 0) return EmptyIterable<E>(); 3 return _GeneratorIterable<E>(count, generator); 4 }

_GeneratorIterableという別のクラスを呼んでいます。同じファイルにクラス定義がありました。

Dart

1class _GeneratorIterable<E> extends ListIterable<E> {

なんと! ListIterableを見つけました!

実際にDartPadでIterableを操作してみます。

Dart

1void main(){ 2 Iterable<int> itr = Iterable.generate(5, (i)=>i+1); 3 print(itr.iterator); 4 print(itr); 5}

実行結果

Instance of 'ListIterator<int>' (1, 2, 3, 4, 5)

確かに、ListIteratorが生成されています。

今回、generateだけを確認しましたが、ミッシングリンクは確かに存在していました。他のコンストラクタも同様ではないでしょうか。

投稿2020/11/28 12:06

toast-uz

総合スコア3266

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moriman

2020/11/29 03:33

回答を頂きましてありがとうございます。 お示し頂いた部分を見たのですが、 確かにIterable.generateコンストラクタによってListIterable(のサブクラス)を返すので、Iterable.generateコンストラクタにより生成されたインスタンスは、そのiteratorプロパティにListIteratorを有する、という流れになると思います。 なので、リストリテラルなどで生成したList<E>型のリストがIterable.generateコンストラクタにより生成されたものなら、辻褄が合うと思うのですが、 それを示すコードが見つけられません。 List<E>型のインスタンスはIterable.generateコンストラクタにより生成されるのでしょうか? それってどこを見れば確認できますでしょうか?
toast-uz

2020/11/29 03:55 編集

「List<E>型のインスタンスはIterable.generateコンストラクタにより必ず生成される」といったことは一言も申しておりません。「今回、generateだけを確認しましたが、ミッシングリンクは確かに存在していました。他のコンストラクタも同様ではないでしょうか。」という末尾の文を再確認ください。 ご質問である「List<E>クラスとListIterable<E>クラスの関係性を示すコードがあるのでしょうか」に対して、「ありました」という答えを記載しているだけです。 List<E>型のインスタンスは必ず何らかのコンストラクタを呼び出しているはずですので、その他のコンストラクタがどうなっているかは、質問者様にて確認いただければと思います。少なくとも今までの質問者様は、コンストラクタの実装を追うことをされていなかったため、今回の回答はかなりのヒントになったものと考えます。 「リストリテラルで生成したList<E>型のリストは、どのコンストラクタを使っているのか」というご質問は別のご質問になると思います。私も未確認です。ただ、Iterable型のコンストラクタで実質的な意味があるのはgenerateだけですので、generateである可能性は高いように思います。
moriman

2020/11/29 05:45

回答を頂きましてありがとうございます。 私自身teratailの利用方法を理解しきれていないのかもしれないのですが、 回答と回答に対する返信が続く中で別の疑問に話題が移ることもあると思うのですが、そういう場合一旦その質問については終了して、また新しい質問として投稿すべきなのでしょうか? まあ「別の疑問」と言ってもいろいろで、全く別の論点に関してなら流石に新しく質問した方が良いだろう、という気はしますが、今回はほぼ同じ論点に関してだと思います。 teratailのルールとしてそうであるならばそれに従うだけなのですが。 新しく質問した方が回答が得られる可能性が高い、という話ですかね? ここでも「List<E>型のインスタンスはIterable.generateコンストラクタにより生成されるのか」についてはここで質問すべきではなく、新しい質問として投稿した方が良いのでしょうか。
toast-uz

2020/11/29 06:22 編集

この欄は、回答に対するコメントですので、回答が理解できない、回答が質問の意図と異なる、というのであれば、ここを使うとよいと思います。やりとりの中から新たな質問が生まれたのであれば、類似テーマであっても、新規に質問を立てるべきと思います。私としては「List<E>型のインスタンスはIterable.generateコンストラクタにより生成されるのか」というのは元の質問の論理の範囲からは逸脱していると思います。そもそも質問で説明されていたListやIterableのクラス定義とは別に、Dartの構文解析を見る必要があるように思います。質問者様がこれは元の質問の範囲である、と主張されるのであれば、質問そのものを修正追記して欲しいです。 私の理解としては、teratailは質問者と回答者とのチャットの場ではなく、質問と回答を価値あるコンテンツとして広く見ている人に共有するものです。なので、質問主旨から離れたことをコメント欄でやりとりするのは好ましく無いと思います。また、一度回答がついた質問を、回答の正当性(質問に対しての回答になっているのかを含め)が損なわれるレベルで修正を図るのも好ましく無いと思います。第三者が、後からでも、質問の回答になっていないと判断したら、回答にマイナス評価がつけられるしくみになっています。 なお、新規質問を立てる際には、質問者様の努力の範囲で自分で調べてから、不明な点を質問されるように お願いします。この質問そのものからは、そういったことが十分できる質問者様であると思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問