[コンパイル時計算]Dartでコンパイル時に計算を行うコンストラクタを書く方法と、それによる効果の検証。

## この記事の内容

定数コンストラクタを利用してコンパイル時にフィールドのvを定数式で初期化することを目的に宣言したクラスを宣言し、利用する方法を伝える。
この方法は関数などの、処理を呼び出して記述する方法の中で一番軽い方法であることが魅力です。
定数式で実現でき、関数を使いたい時に有用です。実行時にはすでにフィールドのvのみが残った定数インスタンスになっているので、同じ処理をする関数などより処理が絶対に軽くなります。
三項演算子も定数式で使用できるので、そこそこ複雑な処理も行え、
コンパイル時にべき乗などの計算などを行うことも可能です。
定数式について>>

https://qiita.com/riz21/items/e17048c6107968e13cd0

一番簡単な例
```dart:rei.dart
class addition{
    const addition(a,b):v=a+b;
    final int v;
}
void main() {
    const addition(1,1).v//この処理の実行時の負担が、「1+1」の記述と殆ど変わらない
    for(var i=0;i<100000;++i){print(const addition(1,1).v);}//この様に繰り返しても同様に、「1+1」の記述の場合と殆ど変わらない負担になる。
}
```
## 私の環境での実行時にかかる時間の一覧;
なお、私のパソコンはあまり高性能ではないので私より短い場合も十分にあり得ます。
### 要素検索
<details><summary>要素検索</summary>

```dart:const.dart
///tに該当する要素があるindexをvに格納。等価がなければdef(-1がデフォ);重複する要素がtnに指定された場合に後ろの要素が該当することはないので、名前引数版は無い
class HRSWITCH3<T>{
  const HRSWITCH3(T t,[int def=-1,T?t0,T?t1,T?t2]):v=//配列アクセスが、定数コンストラクタでは行えないのでこうして実装する
    t==t0?0:t==t1?1:
    t==t2?2:def;
  final int v;
}
```
```dart:jikankeisoku.dart
import 'const.dart';
void main() {
    DateTime startTime = DateTime.now();
    for(var i=0;i<100000;++i){
      const HSWITCH3<int>(1,-1,9,108,2020).v;
    }
    print(DateTime.now().difference(startTime));
}
```
4回実行した結果>>
0:00:00.000337
0:00:00.000356
0:00:00.000337
0:00:00.000332
```diff_dart
- const HSWITCH3<int>(1,-1,9,108,2020).v;
+ [9,108,2020].indexOf(108);
```
4回実行した結果>>
0:00:00.001524
0:00:00.001506
0:00:00.001546
0:00:00.001595
</details>

### べき乗

<details><summary>べき乗</summary>

```dart:const.dart
class exponentiation{//べき乗;a^8が上限
  const exponentiation(a,int b):v=//演算順序に注意!!括弧を外すと想定通りに動きません。
    1*(b<=0?1:
    a*(b<=1?1:
    a*(b<=2?1:
    a*(b<=3?1:
    a*(b<=4?1:
    a*(b<=5?1:
    a*(b<=6?1:
    a*(b<=7?1:a))))))));
  final num v;
}
```
```dart:jikankeisoku.dart
import 'const.dart';
void main() {
    DateTime startTime = DateTime.now();
    for(var i=0;i<100000;++i){
      const exponentiation(2,8).v;
    }
    print(DateTime.now().difference(startTime));
}
```
4回実行した結果>>
0:00:00.000340
0:00:00.000340
0:00:00.000323
0:00:00.000343
```diff_dart
- const exponentiation(2,8).v;
+ pow(2,8);
```
4回実行した結果>>
0:00:00.001563
0:00:00.001571
0:00:00.001545
0:00:00.001562
</details>


### indexの要素を検索

<details><summary>indexの要素を検索</summary>

「const[9,108,2020][1]」に負けていることに気が付いたが、こっちの方が色々処理を変えれる
```dart:const.dart
///iが指定したindexの要素になる。その要素がnullだったり、iが範囲外だった時にdefの値になる;
class HSWITCH3<T>{
  const HSWITCH3(int i,T?def,[T?t0,T?t1,T?t2]):v=//配列アクセスが、定数コンストラクタでは行えないのでこうして実装する
    i==0?t0==null?def:t0:
    i==1?t1==null?def:t1:
    i==2?t2==null?def:t2:
    def;
  final T?v;
}
```
```dart:jikankeisoku.dart
import 'const.dart';
void main() {
    DateTime startTime = DateTime.now();
    for(var i=0;i<100000;++i){
      const HSWITCH3<int>(1,-1,9,108,2020).v;
    }
    print(DateTime.now().difference(startTime));
}
```
4回実行した結果>>
0:00:00.000275
0:00:00.000332
0:00:00.000343
0:00:00.000345

```diff_dart
- const HSWITCH3<int>(1,-1,9,108,2020).v;
+ const[9,108,2020][1];
```
4回実行した結果>>
0:00:00.000288
0:00:00.000281
0:00:00.000284
0:00:00.000276
```diff_dart
- const HSWITCH3<int>(1,-1,9,108,2020).v;
+ HSWITCH3f<int>(1,-1,9,108,2020);
+ /*グローバル*/T? HSWITCH3f<T>(int i,T?def,[T?t0,T?t1,T?t2]){
+     return
+     i==0?t0==null?def:t0:
+     i==1?t1==null?def:t1:
+     i==2?t2==null?def:t2:
+     def;
+ }
```
4回実行した結果>>
0:00:00.001001
0:00:00.001017
0:00:00.001024
0:00:00.001015
</details>





### 足し算の実行;
<details><summary>足し算の実行</summary>

```dart:const.dart
class addition{
    const addition(a,b):v=a+b;
    final int v;
}
```
```dart:jikankeisoku.dart
import 'const.dart';
void main() {
    DateTime startTime = DateTime.now();
    for(var i=0;i<100000;++i){
      const addition(1,1).v;
    }
    print(DateTime.now().difference(startTime));
}
```
4回実行した結果>>
0:00:00.000353
0:00:00.000352
0:00:00.000355
0:00:00.000357
```diff_dart
- const addition(1,1).v;
+ 1+1;
```
4回実行した結果>>
0:00:00.000286
0:00:00.000279
0:00:00.000285
0:00:00.000293
```diff_dart
- const addition(1,1).v;
+ var i=1;
+ i+1
```
4回実行した結果>>
0:00:00.000280
0:00:00.000301
0:00:00.000291
0:00:00.000288
```diff_dart
- const addition(1,1).v;
+ additionf(1,1);
+ /*グローバルスコープ*/int additionf(int i,int i2){return i+i2;}
```
4回実行した結果>>
0:00:00.000359
0:00:00.000358
0:00:00.000362
0:00:00.000378
```diff_dart
- const addition(1,1).v;
+ (){return 1+1;}();
```
4回実行した結果>>
0:00:00.000663
0:00:00.000605
0:00:00.000598
0:00:00.000602
</details>

### printさせる;
<details><summary>足し算し、print</summary>

振れ幅が大きくなっただけかもしれないが、何故か定数インスタンスと定数の直書きの差が縮まっている。
```diff_dart
- const addition(1,1).v;
+ print(1+1);
```
4回実行した結果>>
0:00:00.111836
0:00:00.094220
0:00:00.093722
0:00:00.093974
```diff_dart
- const addition(1,1).v;
+ print(const addition(1,1).v);
```
4回実行した結果>>
0:00:00.125148
0:00:00.094860
0:00:00.093231
0:00:00.090786
</details>
他にもさまざまなコンパイル時に計算を行うコンストラクタを公開しています。>>

https://qiita.com/riz21/items/f52c24bd2561ba4338b1

ソースコード>>

https://github.com/rin00159/Dart_public

##
定数コンストラクタを利用してコンパイル時に計算をさせることの有用さが伝わったら幸いです。
検索したりしてもこれを書いているものがなかったので自分で考えて書きました。
他に使える形があったり、これに関するサイトなどがあれば、コメントで教えてくださると嬉しいです。