この記事は 2026 年 8 月 14 日に投稿しました。

目次
1. はじめに
こんにちは、iOS のエディタアプリPWEditorとその後継PWEditorNextの開発者の二俣です。 2018年5月から毎日技術ブログを更新しています。
今回はDartのHashSetの要素を、別の型のSetとして扱うcastメソッドについてです。
2. DartのHashSetの要素を別の型として扱う
DartのHashSetでは、castメソッドを使用すると、現在のSetを指定した型のSetとして扱うことができます。
castメソッドの形式は以下になります。
Set<R> cast<R>()
型パラメータRには、変換後に要素をどの型として扱うかを指定します。
例えば、HashSet<Object>に文字列を格納し、それをSet<String>として扱う場合は次のようになります。
実装例
import 'dart:collection'; void main() { final set = HashSet<Object>(); set.addAll([ 'Dart', 'Flutter', 'Swift', ]); final stringSet = set.cast<String>(); print(stringSet); }
実行すると、HashSet<Object>に格納されている要素をStringとして扱うSet<String>を取得できます。
例えば、次のように要素を取り出すことができます。
for (final value in stringSet) { print(value); }
HashSetは要素の順序を保証しないため、表示される順番は決まっていませんが、Dart、Flutter、Swiftの各要素をStringとして取得できます。
また、戻り値の型はSet<String>になるため、例えば次のように記述できます。
Set<String> stringSet = set.cast<String>();
このようにcastメソッドを使用すると、元のHashSetを別の要素型を持つSetとして扱うことができます。
3. castメソッドは新しい要素を作成しない
castメソッドを使用する場合に重要なのが、元のHashSetの各要素を別の型の値へ変換しているわけではないという点です。
例えば、
final set = HashSet<Object>(); set.addAll([ '100', '200', '300', ]); final stringSet = set.cast<String>();
とした場合、元の要素を新しいStringオブジェクトへ変換しているわけではありません。
元のSetに対して、要素をStringとして扱うビューが返されます。
そのため、castメソッドは、
final stringSet = set.cast<String>();
とした時点で、元のすべての要素を別のSetへコピーする処理ではありません。
また、元のSetとcastメソッドで取得したSetは連動しています。
例えば、次のようになります。
import 'dart:collection'; void main() { final set = HashSet<Object>(); set.addAll([ 'Dart', 'Flutter', ]); final stringSet = set.cast<String>(); set.add('Swift'); print(stringSet); }
元のsetへSwiftを追加すると、stringSetからもSwiftを確認できます。
逆に、castメソッドで取得したSetを変更した場合も、元のSetへ反映されます。
stringSet.add('C#');
print(set);
この場合、元のsetにもC#が追加されます。
このように、castメソッドの戻り値は元のSetとは独立したコピーではありません。
元のSetとデータを共有したまま、異なる要素型のSetとして扱いたい場合に利用できます。
4. 型が一致しない要素が含まれている場合
castメソッドでは、呼び出した時点ですべての要素が指定した型であるかを確認するわけではありません。
例えば、次のようなHashSet<Object>があるとします。
final set = HashSet<Object>(); set.addAll([ 'Dart', 100, 'Flutter', ]);
このHashSetには、Stringだけでなくintの100も含まれています。
この状態でも、
final stringSet = set.cast<String>();
としてSet<String>として扱うことはできます。
ただし、実際に要素を取得する際に、指定した型として扱えない要素があるとエラーになります。
例えば、
import 'dart:collection'; void main() { final set = HashSet<Object>(); set.addAll([ 'Dart', 100, 'Flutter', ]); final stringSet = set.cast<String>(); for (final value in stringSet) { print(value); } }
では、int型の100をStringとして取得しようとした時点で型エラーが発生します。
そのため、
set.cast<String>();
と記述できたからといって、元のHashSetに含まれているすべての要素がStringへ変換されたわけではありません。
元の要素が実際に指定した型として扱えることを確認して使用する必要があります。
5. castメソッドを使用する場合の注意点
castメソッドは、要素そのものの型を変換するためのメソッドではありません。
例えば、次のようなHashSet<int>があるとします。
final set = HashSet<int>(); set.addAll([ 100, 200, 300, ]);
これを、
final stringSet = set.cast<String>();
としたからといって、
100 200 300
という数値が、
'100' '200' '300'
という文字列へ変換されるわけではありません。
intからStringへ実際に値を変換したい場合は、例えばmapメソッドとtoSetメソッドを使用して次のように処理できます。
final stringSet = set
.map((value) => value.toString())
.toSet();
print(stringSet);
この場合は、各int要素に対してtoString()が実行され、新しいStringの要素を持つSet<String>が作成されます。
つまり、
set.cast<String>();
と、
set.map((value) => value.toString()).toSet();
では目的が異なります。
castメソッドは、
HashSet<Object>
のような広い型で扱われているSetの中身が、実際にはすべてStringであることがわかっている場合などに、
Set<String>
として扱うために使用できます。
一方、要素そのものを別の値へ変換したい場合は、mapメソッドなどを使用します。
また、castメソッドで取得したSetに要素を追加する場合にも注意が必要です。
例えば、
final set = HashSet<Object>(); final stringSet = set.cast<String>(); stringSet.add('Dart');
のように、変換先の型であるStringの値を追加できます。
追加した値は元のsetにも反映されます。
ただし、元のSetが受け入れることのできない型の値を、castメソッドで取得したSetを通して追加しようとすると、実行時にエラーになる場合があります。
そのため、castメソッドを使用する場合は、元のSetの要素型と、指定する型との関係を理解して使用する必要があります。
なお、castメソッドはHashSet固有のメソッドではありません。
Setで定義されているメソッドなので、HashSet以外のSetでも利用できます。
リファレンス
6. おわりに
DartのHashSetを別の要素型を持つSetとして扱うには、castメソッドを使用します。
例えば、
final set = HashSet<Object>(); set.addAll([ 'Dart', 'Flutter', 'Swift', ]); final stringSet = set.cast<String>();
とすると、HashSet<Object>をSet<String>として扱うことができます。
ただし、castメソッドは各要素を別の型へ変換するメソッドではありません。
例えば、
final stringSet = set.cast<String>();
としても、元の要素を新しいStringの値へ変換しているわけではなく、元のSetをSet<String>として扱うためのビューを取得します。
そのため、元のHashSetに指定した型として扱えない要素が含まれている場合は、実際にその要素へアクセスした際に型エラーが発生します。
要素そのものを別の値へ変換したい場合は、
final stringSet = set
.map((value) => value.toString())
.toSet();
のようにmapメソッドなどを使用します。
castメソッドは、広い型で定義されたSetの要素が、実際には特定の型であることがわかっており、その型のSetとして扱いたい場合に便利です。
また、castメソッドで取得したSetは元のSetと連動しているため、一方に対する変更はもう一方にも反映されます。
この点も、新しいSetを作成するmapメソッドやtoSetメソッドなどとの違いとして覚えておくとよさそうです。
私が技術者として所属している ニューラル では、 組み込み・制御系ソフトウェアを中心に、モバイルアプリや業務アプリなど、さまざまなソフトウェアの開発を行っています。
組み込み分野では、リアルタイムOSを利用したシステム開発をはじめ、弊社製品のハイブリッドOS Bi-OS など、長年培ってきた組み込み・制御系の技術を活かした開発に取り組んでいます。
また、iOS(Swift/SwiftUI)やWindows(C#)をはじめとしたアプリケーション開発、Webシステムの開発などにも対応しています。
組み込みソフトウェア、モバイルアプリ、Windowsアプリ、Webシステムなど、ソフトウェア開発に関するご相談がございましたら、お気軽にお問い合わせください。
また、ニューラルでは一緒にソフトウェア開発に取り組んでいただける技術者の方も募集しています。 ご興味がございましたら、お気軽にお問い合わせください。
EMAIL : info-nr@newral.co.jp / m-futamata@newral.co.jp TEL : 042-523-3663 FAX : 042-540-1688