できそう(だと思われる)ことも質問してみましょうか。
私 :
name: String
age : int
job : String
上記のフィールドを持つ10人分のサンプルデータをJSON形式で示してください。
Bard : はい。以下は、10人の人に関するサンプルデータです。
[ { "name": "John Doe", "age": 30, "job": "Software Engineer" }, { "name": "Jane Doe", "age": 25, "job": "Teacher" }, { "name": "Peter Smith", "age": 40, "job": "Doctor" }, { "name": "Mary Jones", "age": 20, "job": "Student" }, { "name": "David Brown", "age": 50, "job": "Businessman" }, { "name": "Sarah Green", "age": 35, "job": "Lawyer" }, { "name": "Michael White", "age": 45, "job": "Engineer" }, { "name": "Susan Black", "age": 25, "job": "Nurse" }, { "name": "James Brown", "age": 30, "job": "Teacher" } ]
このデータはJSON形式で、各人は名前、年齢、職業の3つのフィールドを持っています。
こういうことはできるみたいですね。厳密に言えば九人分ですが😅
私 : OKです。では次に、
(1)Dartで”name”,”age”,”job”フィールドを持つPersonクラスを定義して (2)上記のJSONデータをList<Person>型のpersonsとして記述してください。
Bard : はい。以下は、Dart で「name」、「age」、「job」フィールドを持つ Person クラスです。
class Person { String name; int age; String job; Person({this.name, this.age, this.job}); }
まあおおむねいいのですが、フィールドをnon-nullable型として宣言する場合コンストラクタにrequiredキーワードが必要ですね。
そこらへんわかってるのかどうか微妙ですね。
次に、上記の JSON データを List<Person> 型の persons として記述します。
List<Person> persons = [ new Person(name: "John Doe", age: 30, job: "Software Engineer"), new Person(name: "Jane Doe", age: 25, job: "Teacher"), new Person(name: "Peter Smith", age: 40, job: "Doctor"), new Person(name: "Mary Jones", age: 20, job: "Student"), new Person(name: "David Brown", age: 50, job: "Businessman"), new Person(name: "Sarah Green", age: 35, job: "Lawyer"), new Person(name: "Michael White", age: 45, job: "Engineer"), new Person(name: "Susan Black", age: 25, job: "Nurse"), new Person(name: "James Brown", age: 30, job: "Teacher"), ];
newは要らないですが、まあ、いいでしょう。
私 : OK。では次に、直接Listを書くのではなく、JSONデータ(つまり文字列)をList<Person>型に変換するコードを示してください。
Bard : はい。以下は、JSON データを List<Person> 型に変換するコードです。
import 'dart:convert'; class Person { String name; int age; String job; Person({this.name, this.age, this.job}); } void main() { String jsonString = """ [ { "name": "John Doe", "age": 30, "job": "Software Engineer" }, { "name": "Jane Doe", "age": 25, "job": "Teacher" }, { "name": "Peter Smith", "age": 40, "job": "Doctor" }, { "name": "Mary Jones", "age": 20, "job": "Student" }, { "name": "David Brown", "age": 50, "job": "Businessman" }, { "name": "Sarah Green", "age": 35, "job": "Lawyer" }, { "name": "Michael White", "age": 45, "job": "Engineer" }, { "name": "Susan Black", "age": 25, "job": "Nurse" }, { "name": "James Brown", "age": 30, "job": "Teacher" } ] """; List<Person> persons = json.decode(jsonString).map((person) => Person.fromJson(person)).toList(); print(persons); }
はい、結構良さそうなコードを出してきましたが、動かしてみると、fromJsonを定義していないのでエラーが出ますね。惜しいですね。
とりあえず修正を指示してみます。
私 : 「fromJsonの定義が無い」というエラーが出るので、必要なコードを示してください。
Bard : 承知しました。Person クラスに fromJson() メソッドを追加するには、次のコードを使用できます。
class Person { String name; int age; String job; Person({this.name, this.age, this.job}); factory Person.fromJson(Map<String, dynamic> json) { return Person( name: json['name'], age: json['age'], job: json['job'], ); } }
このコードは、JSON オブジェクトから Person オブジェクトを作成するために使用できる fromJson() メソッドを Person クラスに追加します。
さらにrequiredキーワードが無いのでコンパイルエラーが出てます。そちらも修正依頼してみます。
私 : Personクラスの全てのフィールドがnon-nullable型として宣言されているのでそのコンストラクタだとコンパイルエラーが出ます。必要な修正を示してください。
Bard : 承知しました。Person クラスの各フィールドが非 nullable 型として宣言されている場合は、fromJson() メソッドを以下のように変更する必要があります。
factory Person.fromJson(Map<String, dynamic> json) { return Person( name: json['name'] as String, age: json['age'] as int, job: json['job'] as String, ); }
これにより、JSON オブジェクトから Person オブジェクトを作成するために使用できる fromJson() メソッドが Person クラスに追加されます。
ああ、それか、という感じですが、結局これだとコンパイルエラーは消えないですね。
私 : いや、その修正をしてもコンストラクタでコンパイルエラーが出る。コンストラクタに修正が必要ですよね。必要な修正を示してください。
Bard : ああ、なるほど。Person クラスのコンストラクターを以下のように変更する必要があります。
Person({ required this.name, required this.age, required this.job, });
これにより、Person クラスのコンストラクターが各フィールドに必要なパラメータを持つように変更されます。
ちょっと面白くなってきました。
わかってるじゃん!笑
じゃあ最初から出してよ、という気がしないでもないですが、まあ、いいのではないでしょうか。
はい、ここまででコンパイルエラーは出なくなりました。が、動かしてみると下記のエラーが出ます。
: TypeError: Instance of 'JSArray<dynamic>': type 'JSArray<dynamic>' is not a subtype of type 'List<Person>'Error: TypeError: Instance of 'JSArray<dynamic>': type 'JSArray<dynamic>' is not a subtype of type 'List<Person>
json.decode(jsonString)の返り値をListにキャストする必要がある、と。惜しいですね。
//修正前 List<Person> persons = json.decode(jsonString).map((person) => Person.fromJson(person)).toList(); //修正後 List<Person> persons = (json.decode(jsonString) as List).map((person) => Person.fromJson(person)).toList();
ここも修正依頼で正しいコードを出してくるか試してみます。
私 : 実行したら下記のエラーが出ました。対応策を示してください。 : TypeError: Instance of ‘JSArray<dynamic>’: type ‘JSArray<dynamic>’ is not a subtype of type ‘List<Person>’Error: TypeError: Instance of ‘JSArray<dynamic>’: type ‘JSArray<dynamic>’ is not a subtype of type ‘List<Person>’
Bard :
json.decode()
メソッドの出力は JSArray
型であり、これは List<Person>
型のサブタイプではないため発生しています。json.decode()
メソッドの出力を List<Person>
型に変換するには、.cast<Person>()
メソッドを使用できます。List<Person> persons = json.decode(jsonString).cast<Person>().toList();
これにより、json.decode()
メソッドの出力が List<Person>
型に変換され、persons 変数に格納されます。
本当にぱっと見なら行けそうに見えますが、ちょっとよく見てみると「ん? 違うんじゃない?」という感じですね。
実際動かすと実行時エラーが出ますね。
もう少し丁寧に(正解に導くように)Bardに質問文を書けばいけそうな気もしますが、そういうクイズゲームに時間を使っても仕方がないのでここまでにしておきます。
正解に導くためには質問者が正解を理解している必要がありますね。
正解を理解しているならコードを書く方が速いですね。
この種のコードを自分で書かずに済むためのパッケージもあるのですが、ここまで試してみた感触として
「サードパーティパッケージを使ったら使ったでパッケージの仕様に関する細かいミスが入り込み、結局そのパッケージの使い方(プラスDart言語の基礎知識)をしっかり把握している人でなければ動かせない」という状況は容易に想像できますね。
結局、そのパッケージの使い方をしっかり把握しているなら自分でコード書いたら良いじゃん、とまともなプログラマーは思うんじゃないでしょうか。
まあ0歳のサービスなわけですから、この時点であーだこーだ言うのは流石に評価するタイミングが早すぎる、ということでしょうか。
chatgpt同様、データ整形・サンプルデータ生成・簡単な調べ物など、もっとプログラミングよりも得意な種類の作業はあると思われるので、現時点ではそちらで利用するのが良さそうです。
現時点でもプログラマーの補助としては非常に優秀なツールと言えるでしょう。
今後も成り行きに注目していきたいですね。