今までの話
さて、今までは基本的な操作方法などを記載してきましたが、ここからは関数や色々なものを記載していきますよ。まぁ。。。今回は関数とクラスあたりを解説していきましょうか。
特に関数や、クラスといったものは他の関数とそんなに変わりはないと思います。
まぁ...「全然違いますよ...(眼鏡クイッ!!)」という方もいるかもしれませんが、そこまで違いはないと私は思います。。。多分!!
では、始めていきましょう。
関数
さて、関数を定義していきましょうか
関数を簡単にいうと
その関数を呼び出し → 実行する
ということですね。
まぁ、文面だけの表現だけでは「何やら・・・?」と思うかもしれないのでコードをいつも通り書いていきましょう。
返す型を定義して関数を作る
これは、最初に返り値の型を書いて関数を定義する方法です。/*
int 関数名(){処理}
String 関数名(){処理}
double 関数名(){処理}
void 関数名(){処理}
※ちなみにvoidは返り値を指定しない時に使います
*/
//お試しでint型
int hoge(int a, int b){
return a + b;
}
void main(){
print(hoge(1, 3));
}
//-----出力-----
//4
こんな感じで、最初に返り値の型を定義し関数を作成することができます。
関数を作成し、void main()で関数を呼び出し処理を実行させるための文言を書きます。
今回の場合は hoge()内に値を格納し、処理をreturnで返し結果を表示します。
int型なので、数字以外をvoid main(){print(hoge())}のhoge()にはint型の値を入れましょう。そうしないとエラーが出ます。
さて、どんどんいきましょうか。
/*
略記が可能な関数の書き方
関数ないの処理が1行な場合は以下のように略記が可能
*/
//voidでも書けます
/*
voidではprintを記載することができるので
実行時で呼び出す時にprintを記載する必要が
なくなります。
*/
void test(int a, int b) => print(a + b);
//intでもOK
/*
voidとは違い、実行時にprintを記載しないと
実行結果を表示することができませんので、注意
*/
int hoge(int a, int b) => a + b;
void main(){
test(1, 9);
print(hoge(2, 10));
}
//-------出力--------
//10
//12
こんな感じにできます。
定義と処理の間にある[ => ]はなんだ?という方も
いると思うので、解説しますと、、、
これは「アロー関数」と言います。
このアロー関数は、関数で定義したいコードを1行でまとめられる際に使用できるものですね。
こんな感じで関数を定義できます。
さて、もう少し複雑な処理(Null-Sefetyを考慮しながら)を記載していきましょう。
最後に参考になるサイトを貼りますので、そちらも一緒に参考としてください。
/*
リスト形式で格納してある部分には、
なにも格納されない可能性があるため、
Nullが返ってきてしまいエラーになるので
Null-Sefetyの場合は注意してください。
{int}の部分に{int?}をつけてエラーを避けましょう。
*/
int hoge(int a, int b, [int? c, int? d]){
int result = a + b;
if (c != null) result += c;
if (c != null) result += d;
return result;
}
/*
さて、上記と一緒のような注意をする必要がありますが、
こちらはcまたはdに[:]をつけて、代入する数字を与える
ことで、計算のresultに値を追加することができます。
*/
int hogehoge(int a, int b, {int? c, int? d}){
int result = a + b;
if (c != null) result += c;
if (d != null) result += d;
return result;
}
void main(){
print(hoge(1, 2, 3, 4));
print(hogehoge(1, 2, c:3, d:4));
}
//------出力-------
//10
//10
クラス
さぁ、いよいよクラスですね。 プログラミング初心者はここら辺から躓く部分ですね。 なるべくわかりやすく、より具体的に見える化させながら、やりましょうか。よく、私も言われました。(というか、現在進行形でもよく言われてますね)「何かを伝えるとき、考えるときは、見える化をしなさい」と
まぁ、その言葉の意味は今度、ポエム形式で書きましょうか。
さて、話を戻しましょうか
クラスに関するあれこれ
まずは、クラスとはなにか?ですね。少し表現が難しいので、
わかりやすいサイトがあったので、引用します。
クラスとはオブジェクト(インスタンス)を生成(インスタンス化)するための設計図
この文を読んで「あぁ。。。そういうことね!!」となる人はほぼいないでしょう。
まぁ、クラスに関するあれこれを書きつつ、コードによる記述で見えるかをしていきましょう。
さて、クラスには「インスタンス」というものがあります。
インスタンスとは、クラスから生成されたものを言います。
この、生成されたものをオブジェクトと言います。
オブジェクトについては様々な解釈があるので、何とも言えない部分はありますが、ここも引用してみましょう。
オブジェクトとは?
オブジェクトとは、全ての総称です。
つまり、変数、関数、クラス、データなどプログラミングで使う全てのものがオブジェクトです。よってクラスから生成されたインスタンスもオブジェクトの一つです。
本来、オブジェクトは全ての総称ですがプログラマーの間では「オブジェクト=クラスから生成されたインスタンス」と定着しているので、クラスから生成したインスタンスをオブジェクトと呼ぶんだなと思っておきましょう。
とのことです。
「オブジェクト=クラスから生成されたインスタンス」ここは重要ですね。
この文言で定借しているらしいので、これは覚えておいて損はないですね。
(私が教えられたのは、どちらかというとオブジェクトはプログラムが使用する道具?的な教え方をされましたね。まぁ、ここはいいでしょうか)
では、クラスを定義してみましょうか。
/*
クラスの定義
class クラス名
*/
class Powder{}
このようにクラスを定義します。
次に、インスタンス化を見てみましょう
//インスタンス化
//クラス名 オブジェクト名 = コンストラクタ;
void main(){
Powder powder = Powder();
}
class Powder(){}
このように、クラスのインスタンス化は変数の宣言と同じように宣言します。
ただし、このクラスの状態では何の機能もしません。
よって、プロパティ/コンストラクタ/メソッドを使ってクラスに機能を追加します。
//それぞれを定義していきましょう。
class Powder{
//プロパティ
int flour;
int sugar;
//コンストラクタ
Powder({int flour, int sugar}){
this.flour = flour;
this.sugar = sugar;
}
//メソッド
void Particle(){
print('I am Powder!!')
}
}
(粉関連でせめてみましたが、なかなか。。。)
では、細かく見ていきましょうか。
プロパティ(property)
//プロパティを見ていきましょう
class Powder{
//プロパティ
int flour = 100;
String sugar;
}
さて、プロパティとは、単にクラスの中で使う変数のこと。よって、プロパティは変数と同様にクラス内で宣言していきます。
プロパティの使用例
//プロパティの呼び出し方
オブジェクト名.プロパティ名;
void main(){
Powder powder = Powder();
print(powder.flour);
}
class Powder{
//プロパティ
int flour = 100;
}
//出力
//4
このように、クラスをインスタンス化した後に、プロパティを呼び出すことができます。
メソッド(method)
class Powder{
//メソッド
void flour(){
print('I am Powder');
}
}
このように、メソッドとは、単にクラスの中で使う関数のことです。
メソッドは関数と同じようにクラスで定義します。
メソッドの使用例
//メソッドの呼び出し方
オブジェクト名.メソッド名();
void main(){
Powder powder = Powder();
powder.flour();
}
class Powder{
//メソッド
void flour(){
print('I am Powder');
}
}
//出力
//I am driving
クラスをインタンス化した後に、メソッドを呼び出せます。
コンストラクタ(constructor)
//コンストラクタ
class クラス名{
クラス名(){
(実行したい処理)
}
}
コンストラクタは、クラスのオブジェクトがインスタンスかされる時に、一度だけ実行されます。
また、パラメータを使えば、クラスに引数を渡すことができます。
インスタンス化時にだけ使われる
//例
main(){
//クラスのインスタンス化
Powder powder = Powder();
}
class Powder{
Powder(){
print('Hello World');
}
}
//出力
//Hello World
この例の場合は、クラスのインスタンス化時に
[Hello World]が出力されます。
コンストラクタ(パラメータありの場合)
```dart class Powder{ //プロパティ int flour;//コンストラクタ
Powder(int flour){
this.flour = flour; //プロパティにパラメータを代入します
}
}
コンストラクタでクラスのプロパティを使用する際には[this.]をプロパティの頭につけます。
また、[this = インスタンス化した際のオブジェクトの名前]と覚えておくといいでしょう。
<h3>コンストラクタの省略化</h3>
```dart
//例
class Powder{
//プロパティ
int flour;
//コンストラクタ
Powder(this.flour){}
}
パラメータを使用せず、直接プロパティに値を代入できます。
キーワード引数の場合
//例
class Powder{
//プロパティ
int flour = 100;
//コンストラクタ
Powder({this.flour}) {}
}
キーワード引数にするにはパラメータを{}で囲みます。
キーワード引数を使うコンストラクタのインスタンス化
//例(引数を使用する場合)
Powder powder = Powder(100, 150);
//例(キーワード引数を使用する場合)
Powder powder = Powder(flour:100, sugar:150);
※Flutterについては後々、やっていきますが、flutterのWidgetはキーワード引数を使ったクラスのオブジェクトです。
さて、クラス関連のあれこれはやってきましたので
クラスについてのコードを記載して、終わりにしましょうか
少々コードに補足も書いてあるので、気になる方は読んで見るといいかもしれませんね。
/*
引数は「関数の中に入っていくもの」
返り値は「関数から出ていく(出力)もの」
*/
class Powder1{
//これはメンバ変数とも言います
String? flour;
//コンストラクタ
Powder1(String flour){
this.flour = flour;
}
//メソッド
String sugar(){
return "I'm $flour.";
}
}
class Powder2{
//メンバ変数
String? flour;
int? price;
String? effect;
//コンストラクタ
Powder2(this.flour, this.price);
//セッター
set powdersetting(String text) => effect = "$flour: $text";
//ゲッター
String get powdergetting => "flour: $flour\nprice:$price\n$effect";
}
void main(){
Powder1 powder1 = Powder1("粉");
print(powder1.sugar());
Powder2 powder2 = Powder2("重曹",100,);
powder2.powdersetting = "安いよ。。。";
print(powder2.powdergetting);
}
こんな感じでクラスを定義していきます。
また、クラスの継承などもありますがそれはまたの機会に追記します。
追記:クラスの継承(2021/11/3:追記)
クラスの継承とは何でしょうか?
(私的には親クラスから子クラスにクラスのメソッドを継承するだったかな?といううろ覚えの記憶なので)
早速、引用していきましょう。
継承(Inheritance)とは?
継承とは、別のクラス(親クラス)の機能を引き継いで、新しいクラス(子クラス)を定義することです。
なるほど、だいたい私の認識と合っている。。。と思います。はい。
継承のメリット
継承することで、ベースとなる親クラスのプログラムの機能または変更を、全ての継承したクラスに反映できます。
よって、複数のクラスで繰り返し使われるコードを別のクラスで定義しておき、新しいクラスで継承します。
なるほど、まぁ、継承のメリットはこんな感じですね。
では、ささっとコードを書いていきましょうか。
親クラスのコンストラクタにパラメータがない場合
では、定義していきましょうか。
//定義していきましょう
class 子クラス名 extends 親クラス名{}
定義の方法はこんな感じです。
文言にすると
class 子クラス を 親クラス から継承します
こんな感じですかねぇ?
さて、例を挙げてみましょう。
//例(今回も粉関連で)
void main(){
Flour flour = Flour();
flour.mass();
flour.price();
}
//親クラスの定義(パラメータなしの場合)
class Powder{
void price(){
print('I am Powder!!!!!!');
}
}
//子クラスの定義
class Flour extends Powder{
void mass(){
print('It is a powder mass');
}
}
//出力
//It is a powder mass
//I am Powder!!!!!!
extendsを使って親クラスを継承します。
継承したクラスは通常のクラス同様にインスタンス化でき、親クラス/子クラス両方のプロパティ/メソッドを使用できます。
親クラスのコンストラクタにパラメータがある場合
さて、今回はパラメータがある場合を見ていきましょうか
//定義していきましょうか
class 子クラス名 extends 親クラス名{
子クラス名(子パラメータ): super(親パラメータ:子パラメータ) //親クラスでキーワード引数を使う場合
}
このように定義します
では、例を書いていきましょう。
//では、やっていきましょうか。
void main(){
Flour flour = Flour(mass: 100, price: 300);
print(flour.mass);
print(flour.powderparameters);
}
//親クラスの定義(パラメータありの場合)
class Powder{
int? powderparameters;
Powder({this.powderparameters}){}
}
//子クラスの定義
class Flour extends Powder{
int? mass;
Flour({this.mass, int? price}) : super(powderparameters: price){}
}
//出力
//100
//300
親クラスで引数を必要とする場合は、まず、子クラスのコンストラクタで親クラスの引数を受け取ります。次に「super」を使って親クラスのコンストラクタを呼び出し、受け取った引数を親クラスに渡します
上の例では、子クラスのコンストラクタで親クラスの「powderparametersプロパティ」の引数となる値と、子クラスの「massプロパティ」の引数となる値を受け取るコンストラクタを定義しています。
super
superを使えば、親クラスのプロパティ/コンストラクタ/メソッドを子クラスで使用できます。
これだけでは、何言ってんだ。。。って感じになってしまうのでコードを書いていきましょう。
//さあ、始めていきましょうか
void main(){
Flour flour = Flour(price:100);
flour.powderprice();
}
//親クラスの定義
class Powder{
int? powderparameters;
Powder({this.powderparameters}){}
void parameter(){
print('I am 粉');
}
}
//子クラスの定義
class Flour extends Powder{
//親クラスのコンストラクタを使用
Flour({int? price}) : super(powderparameters : price){}
void powderprice(){
print(super.powderparameters);//親クラスのプロパティを使用
super.parameter();//親クラスのメソッドを使用
}
}
//出力
//100
//I am 粉
子クラスで親クラスのプロパティ/メソッドを使用するには、この例のように頭に「super.」をつけます。
「super=親クラス名」と覚えておきましょう。
しっかし、私のサンプルはわかりづらいですね。。。
ここは私の改善点ですね。。。
override
@overrideを使えば、クラスを継承する際、親クラスがもつメソッドを上書きすることができます。
私はあまり[@override]を使用したことがなく、こちらをみて「あ。。。そういうことか」と思いましたね。
まぁ、私の話はいいでしょうか。
コードを書いてみましょうか
//定義していきましょう.
class 子クラス名 extends 親クラス名{
@override
変更したい親クラスメソッド名(){
(実行したい処理)
}
}
こんな感じですか、なるほどなぁ。
(なんで私がなるほど。。。ってなってるのかな?)
//さて、サンプルコードです(まーた私のオリジナルです)
main(){
Flour flour = Flour();
flour.price();
}
//親クラスの定義
class Powder{
void price(){
print('粉の価格');
}
}
//子クラスの定義
class Flour extends Powder{
@override //親クラスの[priceメソッド]を上書き
void price(){
print('粉の粒子');
}
}
親クラスのpriceメソッドを継承するクラスで上書きしています。
まぁ、こんな感じで、クラスの継承はOKでしょう
では、追記は以上です。
では、また次回。
挨拶
どうも、組込みエンジニアとして、とある企業におります粉です。・組込みエンジニアですがAIエンジニア、機械学習エンジニアとして転職したいので、自身でいろいろと勉強を行っております。
・なんでAIエンジニアや機械学習エンジニアになりたいの?と疑問をもたれる方も多いと思いますので、簡単に説明させていただきます。
1、元はAIを作ってみたい、社会問題、労働に関してもっと働きやすい環境が必要なのではないか?と考えたため様々な課題をAIなどの先端技術でアプローチをかけてみたいと思い、AIエンジニアを目指しました。
2、ですが、今やっているのは組込みエンジニアのため、使用する技術、言語が違うといったことから、独学でやってみようと思いまして、最近勉強をはじめました。
3、転職を目指す、自身の夢を叶えたいという願いもありますので、こうやって学んだことを記事しています。
・いろいろとお話ししましたが、まずは、私よりも知識、技術が豊富な先輩方から多くのことを意見、修正点、アドバイスをいただけることを楽しみにしています。
・まだまだ新参者、理解が足りていない部分もあるので記事を書きながら、修正を繰り返して理解を深めれればと思っております。(AIを研究している企業や研究機関に転職したいです。
・こんな手法もあるぞ、やり方はこうだ!!などの意見も募集しております。