-
Notifications
You must be signed in to change notification settings - Fork 65
/
Copy pathvim9class.jax
1307 lines (1030 loc) · 58.1 KB
/
vim9class.jax
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
*vim9class.txt* For Vim バージョン 9.1. Last change: 2024 Apr 13
VIMリファレンスマニュアル by Bram Moolenaar
Vim9 のクラス、オブジェクト、インターフェイス、型定義と列挙型。 *vim9-class*
1. 概要 |Vim9-class-overview|
2. 単純なクラス |Vim9-simple-class|
3. クラス変数とメソッド |Vim9-class-member|
4. 抽象クラスを使う |Vim9-abstract-class|
5. インターフェイスを使う |Vim9-using-interface|
6. さらなるクラスの詳細 |Vim9-class|
7. 型定義 |Vim9-type|
8. 列挙型 |Vim9-enum|
9. 論理的根拠
10. 後でやる
==============================================================================
1. 概要 *Vim9-class-overview*
聞こえのいい呼び名は「オブジェクト指向プログラミング」である。このテーマに関す
る教材はたくさんある。ここでは、あなたが基本をすでに理解していることを前提とし
て、|Vim9| script が提供するものを文書化する。この機能を効果的に使用する方法に
関する役立つヒントも加えている。Vim9 のクラスとオブジェクトは、旧来の Vim
script や従来の関数では使用できない。
基本アイテムはオブジェクト:
- オブジェクトは状態を保存する。これには、それぞれ値を持つことができる 1 つ以
上の変数が含まれる。
- オブジェクトは、その状態を使用したり操作したりする関数を提供する。これらの関
数は「オブジェクト上で」呼び出され、これが従来のデータとデータを操作するコー
ドの分離とは異なる点である。
- オブジェクトには、型付きのメンバー変数とメソッドを備えた明確に定義されたイン
ターフェイスを持つ。
- オブジェクトはクラスから生成され、すべてのオブジェクトは同じインターフェイス
を持つ。これは実行時に変更されることはなく、動的なものではない。
オブジェクトはクラスによってのみ生成さる。クラスは以下を提供する:
- コンストラクタとしての new() メソッド、これはクラスのオブジェクトを返す。
このメソッドはクラス名で呼び出される: MyClass.new()。
- クラスのすべてのオブジェクトで状態を共有する: クラス変数(クラスメンバ)。
- スーパークラスとサブクラス、継承によるクラスの階層。
インターフェイスはオブジェクトのプロパティを指定するために使用される:
- オブジェクトはいくつかのインターフェイスを実装する宣言ができる。
- 同じインターフェイスを実装した異なるオブジェクトを同じように扱うことができ
る。
クラス階層は単一の継承になる。それ以外の場合は、必要に応じてインターフェイスを
使用すること。
クラスのモデリング ~
好きな方法でクラスをモデル化できる。何を構築しているのかを念頭に置き、現実世界
をモデル化しようとしないこと。これは、特に教師が現実世界のオブジェクトを使用し
てクラス関係を説明するので、モデルが現実世界を反映している必要があると考えるか
もしれず、混乱を招く可能性がある。そうではない! モデルは目的に合ったものでな
ければならない。
多くの場合、合成(オブジェクトに他のオブジェクトが含まれる)の方が継承(オブジェ
クトが別のオブジェクトを拡張する)よりも優れていることを念頭に置くこと。最適な
クラスモデルを見つけるために時間を無駄にする必要はない。あるいは、正方形が長方
形なのか、それとも長方形が正方形なのかを議論するのは時間の無駄である。それは問
題ではない。
==============================================================================
2. 単純なクラス *Vim9-simple-class*
簡単な例から始めよう: テキストの位置を保存するクラスだ (これをより効率的に行う
方法は後述する): >
class TextPosition
var lnum: number
var col: number
def new(lnum: number, col: number)
this.lnum = lnum
this.col = col
enddef
def SetLnum(lnum: number)
this.lnum = lnum
enddef
def SetCol(col: number)
this.col = col
enddef
def SetPosition(lnum: number, col: number)
this.lnum = lnum
this.col = col
enddef
endclass
< *object* *Object*
new() メソッドを使用して、このクラスからオブジェクトを作成できる: >
var pos = TextPosition.new(1, 1)
<
オブジェクト変数 "lnum" と "col" には直接アクセスできる: >
echo $'The text position is ({pos.lnum}, {pos.col})'
< *E1317* *E1327* *:this*
他のオブジェクト指向言語を使用したことがある場合は、Vim ではクラス定義内で宣言
されたオブジェクトのメンバが一貫してプリフィックス "this." で参照されることに
気づくだろう。これは、Java や TypeScript などの言語とは異なる。この命名規則に
より、オブジェクトのメンバを簡単に見つけることができる。また、変数にプリフィッ
クス "this." がない場合、それがオブジェクト変数ではないことが分かる。
*E1411*
クラス定義の外からオブジェクトのメソッドや変数にアクセスするには、オブジェクト
名の後にドットを付け、その後にメンバを続ける: >
pos.lnum
pos.SetCol(10)
<
*E1405* *E1406*
クラス名を式として使用することはできない。クラス名は、代入の左辺では使用できな
い。
オブジェクト変数の書き込みアクセス ~
*read-only-variable*
では、オブジェクト変数を直接変更してみよう: >
pos.lnum = 9
< *E1335*
これはエラーになる! デフォルトでは、オブジェクト変数は読み取ることはできても、
設定することはできないからである。TextPosition クラスがそのためのメソッドを提
供しているのはそのためだ: >
pos.SetLnum(9)
オブジェクト変数の読み取りは許可するが設定は許可しないのが、最も一般的で安全な
方法である。ほとんどの場合、値を使用しても問題はないが、値を設定すると注意が必
要な副作用が発生する可能性がある。この場合、SetLnum() メソッドは行番号が有効か
どうかをチェックし、エラーを返すか、最も近い有効な値を使用する。
*:public* *public-variable* *E1331*
副作用を気にせず、オブジェクト変数をいつでも変更できるようにしたい場合は、オブ
ジェクト変数をパブリックにすることができる: >
public var lnum: number
public var col: number
これで、SetLnum(), SetCol() および SetPosition() メソッドは必要なくなり、
"pos.lnum" を直接設定してもエラーが発生しなくなる。
*E1326*
存在しないオブジェクト変数を設定しようとすると、エラーが発生する: >
pos.other = 9
< E1326: Member not found on object "TextPosition": other ~
*E1376*
クラス名を使用してオブジェクト変数にアクセスすることはできない。
Protected 変数 ~
*protected-variable* *E1332* *E1333*
一方、オブジェクト変数をクラスまたはそのサブクラスの外部から直接読み取られたく
ない場合は、オブジェクト変数を保護することができる。これは、名前の前にアンダー
スコアを付けることによって行われる: >
var _lnum: number
var _col: number
次に、protected 変数の値を取得するメソッドを提供する必要がある。これらは一般に
ゲッターと呼ばれる。"Get" で始まる名前を使用することをお勧めする: >
def GetLnum(): number
return this._lnum
enddef
def GetCol(): number
return this._col
enddef
この例はあまり役に立たない。変数はパブリックでもよいだろう。値を確認するときに
便利である。例えば、行番号を総行数に制限する: >
def GetLnum(): number
if this._lnum > this._lineCount
return this._lineCount
endif
return this._lnum
enddef
<
Protected メソッド ~
*private-method* *E1366*
オブジェクトメソッドを同じクラスの他のメソッドからのみアクセス可能にし、クラス
の外部からは使用しないようにしたい場合は、オブジェクトメソッドを protected に
できる。これを行うには、メソッド名の前にアンダースコアを付ける: >
class SomeClass
def _Foo(): number
return 10
enddef
def Bar(): number
return this._Foo()
enddef
endclass
<
クラス外の protected メソッドにアクセスすると、エラーが発生する (上記のクラス
を使用した場合): >
var a = SomeClass.new()
a._Foo()
<
new() メソッドの単純化 ~
*new()* *constructor*
|default-constructor| および |multiple-constructors| も参照。
多くのコンストラクタはオブジェクト変数の値を受け取る。したがって、次のようなパ
ターンがよく見られる: >
class SomeClass
var lnum: number
var col: number
def new(lnum: number, col: number)
this.lnum = lnum
this.col = col
enddef
endclass
<
*E1390*
このテキストを記述する必要があるだけでなく、各変数の型も 2 回記述されている。
これは非常に一般的なので、new() を記述する短い方法が提供されている: >
def new(this.lnum, this.col)
enddef
セマンティクスは理解しやすい。"this." を含むオブジェクト変数名を new() の引数
として指定すると、new() 呼び出しで指定された値がそのオブジェクト変数に割り当て
られることを意味する。このメカニズムは Dart 言語から来ている。
new() を使用して変数をパブリックにするこの方法をまとめると、最初のクラス定義よ
りもはるかに短いクラス定義になる: >
class TextPosition
public var lnum: number
public var col: number
def new(this.lnum, this.col)
enddef
def SetPosition(lnum: number, col: number)
this.lnum = lnum
this.col = col
enddef
endclass
新しいオブジェクトを構築するシーケンスは次のとおり:
1. メモリが割り当てられ、クリアされる。すべての値はゼロ/偽/空でである。
2. 初期化子を持つ宣言されたオブジェクト変数ごとに、式が評価され、変数に割り当
てられる。これは、変数がクラスで宣言された順序で発生する。
3. "this.name" 形式の new() メソッドの引数が割り当てられる。
4. new() メソッドの本体が実行される。
クラスが親クラスを拡張する場合も、同じことが起こる。2 番目のステップでは、最初
に親クラスのオブジェクト変数が初期化される。親が "super()" または "new()" を呼
び出す必要はない。
*E1365*
new() メソッドを定義するときは、戻り値の型を指定しないこと。常にクラスのオブ
ジェクトを返す。
*E1386*
オブジェクトメソッドを呼び出すときは、メソッド名の前にオブジェクト変数名を付け
る必要がある。クラス名を使用してオブジェクトメソッドを呼び出すことはできない。
==============================================================================
3. クラス変数とメソッド *Vim9-class-member*
*:static* *E1337* *E1338* *E1368*
クラスメンバは "static" で宣言される。これらは、定義されているクラス内でプリ
フィックスなしの名前によって使用される: >
class OtherThing
var size: number
static var totalSize: number
def new(this.size)
totalSize += this.size
enddef
endclass
< *E1340* *E1341*
名前はそのまま使用されるため、メソッドの引数名やローカル変数名による名前のシャ
ドウイングは許可されていない。
*E1374* *E1375* *E1384* *E1385*
クラスメンバが定義されているクラスの外にあるクラスメンバにアクセスするには、ク
ラス名のプリフィックスを使用する必要がある。オブジェクトを使用してクラスメンバ
にアクセスすることはできない。
オブジェクトメンバと同様に、名前の最初の文字としてアンダースコアを使用すること
でアクセスを保護することができ、プリフィックス "public" を付けることでアクセス
を公開することができる: >
class OtherThing
static var total: number # 誰でも読み取り可、クラスのみ書き込
# み可
static var _sum: number # クラスのみ読み書き可
public static var result: number # 誰でも読み書き可
endclass
<
*class-method*
クラスメソッドも "static" で宣言される。クラス変数は使用できるが、オブジェクト
変数にはアクセスできず、"this" キーワードは使用できない。
>
class OtherThing
var size: number
static var totalSize: number
# 合計サイズをクリアし、以前の値を返す。
static def ClearTotalSize(): number
var prev = totalSize
totalSize = 0
return prev
enddef
endclass
クラス内では、クラスメソッドを名前で直接呼び出すことができるが、クラスの外で
は、クラス名がプリフィックスされている必要がある:
`OtherThing.ClearTotalSize()`。また、クラス変数初期化子、ラムダ式、入れ子になっ
た関数といった特殊なコンテキストでは、パブリッククラスメソッドに名前プリフィッ
クスを使用しなければならない:
>
class OtherThing
static var name: string = OtherThing.GiveName()
static def GiveName(): string
def DoGiveName(): string
return OtherThing.NameAny()
enddef
return DoGiveName()
enddef
static def NameAny(): string
return "any"
enddef
endclass
<
オブジェクトメソッドと同様に、メソッド名の最初の文字としてアンダースコアを使用
することで、アクセスを protected にすることができる: >
class OtherThing
static def _Foo()
echo "Foo"
enddef
def Bar()
_Foo()
enddef
endclass
<
*E1370*
Note コンストラクタは "static" として宣言できないことに注意。これらは staticの
ように呼び出されるが、オブジェクトメソッドとして実行される。これらは "this"に
アクセスできる。
拡張クラス内のスーパークラスのクラスメソッドとクラス変数にアクセスするには、定
義クラスの外部からの場合と同様に、クラス名のプリフィックスを使用する必要がある:
>
vim9script
class Vehicle
static var nextID: number = 1000
static def GetID(): number
nextID += 1
return nextID
enddef
endclass
class Car extends Vehicle
var myID: number
def new()
this.myID = Vehicle.GetID()
enddef
endclass
<
クラス変数とメソッドは子クラスに継承されない。子クラスは、スーパークラスと同じ
名前の静的変数またはメソッドを宣言できる。メンバが使用されるクラスに応じて、対
応するクラスのメンバが使用される。子クラスのクラスメンバの型は、スーパークラス
のクラスメンバの型とは異なる場合がある。
クラスメソッドまたはオブジェクトメソッド名の 2 重アンダースコア (__) プリフィッ
クスは、将来の使用のために予約されている。
*object-final-variable* *E1409*
|:final| キーワードを使用すると、クラス変数またはオブジェクト変数を定数にする
ことができる。例: >
class A
final v1 = [1, 2] # final オブジェクト変数
public final v2 = {x: 1} # final オブジェクト変数
static final v3 = 'abc' # final クラス変数
public static final v4 = 0z10 # final クラス変数
endclass
<
final 変数はコンストラクタ関数からのみ変更できる。例: >
class A
final v1: list<number>
def new()
this.v1 = [1, 2]
enddef
endclass
var a = A.new()
echo a.v1
<
Note final 変数の値は変更できることに注意。例: >
class A
public final v1 = [1, 2]
endclass
var a = A.new()
a.v1[0] = 6 # OK
a.v1->add(3) # OK
a.v1 = [3, 4] # Error
<
*E1408*
final 変数はインターフェイスではサポートされていない。クラスまたはオブジェクト
のメソッドを final にすることはできない。
*object-const-variable*
|:const| キーワードを使用すると、クラス変数またはオブジェクト変数を作成し、そ
の値を定数にすることができる。例: >
class A
const v1 = [1, 2] # const オブジェクト変数
public const v2 = {x: 1} # const オブジェクト変数
static const v3 = 'abc' # const クラス変数
public static const v4 = 0z10 # const クラス変数
endclass
<
const 変数はコンストラクタ関数からのみ変更できる。例: >
class A
const v1: list<number>
def new()
this.v1 = [1, 2]
enddef
endclass
var a = A.new()
echo a.v1
<
const 変数およびその値は変更できない。例: >
class A
public const v1 = [1, 2]
endclass
var a = A.new()
a.v1[0] = 6 # Error
a.v1->add(3) # Error
a.v1 = [3, 4] # Error
<
*E1410*
const 変数はインターフェイスではサポートされていない。クラスまたはオブジェクト
のメソッドを const にすることはできない。
==============================================================================
4. 抽象クラスを使う *Vim9-abstract-class*
抽象クラスは、少なくとも 1 つのサブクラスのベースを形成する。クラスモデルでは、
いくつかのクラスが共有できる同じプロパティを持っていることがよくあるが、これら
のプロパティを持つクラスにはオブジェクトを作成するための十分な状態がない。サブ
クラスは、オブジェクトの作成に使用する前に、抽象クラスを拡張し、不足している状
態やメソッドを追加する必要がある。
例えば、Shape クラスには色と太さを格納できる。Shape オブジェクトを作成すること
はできない。形状の種類に関する情報が欠落している。Shape クラスは、オブジェクト
を作成できる Square クラスと Triangle クラスのベースとして機能する。例: >
abstract class Shape
var color = Color.Black
var thickness = 10
endclass
class Square extends Shape
var size: number
def new(this.size)
enddef
endclass
class Triangle extends Shape
var base: number
var height: number
def new(this.base, this.height)
enddef
endclass
<
抽象クラスは、new() メソッドがないことを除き、通常のクラスと同じ方法で定義され
る。 *E1359*
*abstract-method* *E1371* *E1372*
抽象メソッドは、抽象クラス内でメソッド定義時に "abstract" プリフィックスを使用
することで定義できる: >
abstract class Shape
abstract def Draw()
endclass
<
抽象クラスの静的メソッドを抽象メソッドにすることはできない。
*E1373*
抽象クラスを拡張する非抽象クラスは、すべての抽象メソッドを実装する必要がある。
シグネチャ (引数、引数の型、戻り値の型) はまったく同じである必要がある。メソッ
ドの戻り値の型がクラスの場合、そのクラスまたはそのサブクラスの 1 つを拡張メソッ
ドで使用できる。
==============================================================================
5. インターフェイスを使う *Vim9-using-interface*
Shape, Square および Triangle を使用した上記の例は、オブジェクトの表面積を計算
するメソッドを追加するとさらに便利になる。そのために、数値を返す 1 つのメソッ
ド Surface() を指定する HasSurface というインターフェイスを作成する。この例は
上記の例を拡張したものである: >
abstract class Shape
var color = Color.Black
var thickness = 10
endclass
interface HasSurface
def Surface(): number
endinterface
class Square extends Shape implements HasSurface
var size: number
def new(this.size)
enddef
def Surface(): number
return this.size * this.size
enddef
endclass
class Triangle extends Shape implements HasSurface
var base: number
var height: number
def new(this.base, this.height)
enddef
def Surface(): number
return this.base * this.height / 2
enddef
endclass
<
*E1348* *E1349* *E1367* *E1382* *E1383*
クラスがインターフェイスの実装を宣言した場合、インターフェイスで指定されたすべ
ての項目が同じ型でクラス内に出現する必要がある。
インターフェイス名は型として使用できる: >
var shapes: list<HasSurface> = [
Square.new(12),
Triangle.new(8, 15),
]
for shape in shapes
echo $'the surface is {shape.Surface()}'
endfor
<
*E1378* *E1379* *E1380* *E1387*
インターフェイスには、オブジェクトメソッドと読み取り専用のオブジェクト変数のみ
を含めることができる。インターフェイスには、読み書き可能または protected オブ
ジェクト変数、protected オブジェクトメソッド、クラス変数、およびクラスメソッド
を含めることはできまない。
インターフェイスは、"extends" を使用して別のインターフェイスを拡張できる。サブ
インターフェイスは、スーパーインターフェイスからすべてのインスタンス変数とメ
ソッドを継承する。
==============================================================================
6. さらなるクラスの詳細 *Vim9-class* *Class* *class*
クラスの定義 ~
*:class* *:endclass* *:abstract*
クラスは `:class` と `:endclass` の間で定義される。クラス全体は 1 つのスクリプ
トファイルで定義される。後からクラスに追加することはできない。
クラスは |Vim9| script ファイル内でのみ定義できる。 *E1316*
関数内でクラスを定義することはできない。 *E1429*
スクリプトファイル内に複数のクラスを定義することは可能である。しかし、通常はメ
インクラスを 1 つだけエクスポートする方が良い。型、列挙型、ヘルパークラスを定
義すると便利である。
`:abstract` キーワードをプリフィックスとして付けたり、`:export` を使用したりで
きる。これにより、次のようなバリエーションが得られる: >
class ClassName
endclass
export class ClassName
endclass
abstract class ClassName
endclass
export abstract class ClassName
endclass
<
*E1314*
クラス名は CamelCased にする必要がある。そして、大文字で始める必要がある。これ
により、組み込み型との衝突が回避される。
*E1315*
クラス名の後に、これらのオプションの項目を使用できる。それぞれ 1 回のみ出現で
きる。これらは任意の順序で出現できるが、この順序が推奨される: >
extends ClassName
implements InterfaceName, OtherInterface
specifies SomeInterface
< *E1355* *E1369*
各変数とメソッドの名前は 1 回だけ使用できる。同じ名前で異なる型の引数を持つメ
ソッドを定義することはできない。パブリックと protected のメンバー変数を同じ名
前で使用することはできない。スーパークラスで使用したオブジェクト変数名を子クラ
スで再利用することはできない。
オブジェクト変数の初期化 ~
変数の型がクラスで明示的に指定されていない場合、クラス定義時に "any" に設定さ
れる。オブジェクトがクラスからインスタンス化されると、変数の型が設定される。
次の予約キーワード名は、オブジェクトまたはクラス変数名として使用できない:
"super", "this", "true", "false", "null", "null_blob", "null_dict",
"null_function", "null_list", "null_partial", "null_string", "null_channel" お
よび "null_job"。
クラスを拡張する ~
*extends*
クラスは他のクラスを拡張できる。 *E1352* *E1353* *E1354*
基本的な考え方は、既存のクラスの上に構築し、それにプロパティを追加することだ。
拡張されたクラスは "base class" (基底クラス) または "super class" (スーパーク
ラス) と呼ばれる。新しいクラスは "child class" (子クラス) と呼ばれる。
基底クラスのオブジェクト変数はすべて子クラスに引き継がれる。(他の言語とは異な
り) それらをオーバーライドすることはできない。
*E1356* *E1357* *E1358*
基底クラスのオブジェクトメソッドは無効にすることができる。署名 (引数、引数の
型、戻り値の型) はまったく同じである必要がある。メソッドの戻り値の型がクラスの
場合、そのクラスまたはそのサブクラスの 1 つを拡張メソッドで使用できる。基底ク
ラスのメソッドは、先頭に "super." を付けることで呼び出すことができる。
*E1377*
子クラスのメソッド (パブリックまたは protected) のアクセスレベルは、スーパーク
ラスと同じである必要がある。
基底クラスの他のオブジェクトメソッドは、子クラスによって引き継がれる。
"new" で始まるメソッドを含むクラスメソッドは、オブジェクトメソッドと同様に無効
にすることができる。基底クラスのメソッドは、クラス名 (クラスメソッドの場合) ま
たは "super." のプリフィックスを付けることで呼び出すことができる。
他の言語とは異なり、基底クラスのコンストラクタを呼び出す必要はない。実際に呼び
出すことはできない。基底クラスからの初期化を子クラスでも行う必要がある場合は、
それをオブジェクトメソッドに入れて、すべての constructor() からそのメソッドを
呼び出す。
基底クラスで new() メソッドが指定されていない場合は、自動的に new() メソッドが
作成される。このメソッドは子クラスには引き継がれない。子クラスは独自の new()
メソッドを定義できるが、メソッドがなければ、new() メソッドが自動的に追加され
る。
インターフェイスを実装するクラス ~
*implements* *E1346* *E1347* *E1389*
クラスは 1 つ以上のインターフェイスを実装できる。"implements" キーワードは 1 回
のみ使用できる *E1350* 。複数のインターフェイスをコンマで区切って指定できる。
各インターフェイス名は 1 回だけ出現できる。 *E1351*
インターフェイスを定義するクラス ~
*specifies*
クラスは、名前付きインターフェイスを使用して、そのインターフェイス、オブジェク
ト変数およびメソッドを宣言できる。これにより、多くの言語、特に Java で頻繁に行
われる、インターフェイスを個別に指定する必要がなくなった。
クラス内の項目 ~
*E1318* *E1325* *E1388*
クラス内では、`:class` と `:endclass` の間に、次の項目を含めることができる:
- オブジェクト変数宣言: >
var _protectedVariableName: memberType
var readonlyVariableName: memberType
public var readwriteVariableName: memberType
- クラス変数宣言: >
static var _protectedClassVariableName: memberType
static var readonlyClassVariableName: memberType
public static var readwriteClassVariableName: memberType
- コンストラクタメソッド: >
def new(arguments)
def newName(arguments)
- クラスメソッド: >
static def SomeMethod(arguments)
static def _ProtectedMethod(arguments)
- オブジェクトメソッド: >
def SomeMethod(arguments)
def _ProtectedMethod(arguments)
オブジェクト変数の場合は、型を指定する必要がある。最善の方法は、": {type}" を
使用してこれを明示的に行うことである。単純な型の場合、"= 123" などの初期化子を
使用することもでき、Vim はその型が数値であると認識する。より複雑な型や、型が不
完全になる場合には、これを行わないこと。
例: >
var nameList = []
これはリストを指定するが、項目タイプは不明である。より良い使い方: >
var nameList: list<string>
初期化は必要ない。デフォルトではリストは空である。
*E1330*
"void", "null" および "v:none" 等、一部の型は使用できない。
組み込みオブジェクトメソッド ~
*builtin-object-methods*
|empty()|、|len()| および |string()| などの一部の組み込み関数はオブジェクトで
使用できる。オブジェクトは、これらの組み込み関数と同じ名前のメソッドを実装し
て、オブジェクト固有の値を返すことができる。
*E1412*
以下の組み込みメソッドがサポートされている:
*object-empty()*
empty() |empty()| 関数によって呼び出され、オブジェクトが空かどうかを確認
する。このメソッドが存在しない場合は、true が返される。このメソッ
ドは引数を受け入れず、真偽値を返す必要がある。
*object-len()*
len() |len()| 関数によって呼び出され、オブジェクトの長さを返す。このメ
ソッドがクラスにない場合はエラーが発生し、ゼロが返される。このメ
ソッドは引数を受け入れず、数値を返す必要がある。
*object-string()*
string() |string()| 関数によって呼び出され、オブジェクトのテキスト表現を取
得する。オブジェクトに対する |:echo| コマンドでも使用される。この
メソッドがクラスにない場合は、組み込みのデフォルトのテキスト表現
が使用される。このメソッドは引数を受け入れず、文字列を返す必要が
ある。
*E1413*
クラスメソッドを組み込みメソッドとして使用することはできない。
インターフェイスの定義 ~
*Interface* *:interface* *:endinterface*
インターフェイスは `:interface` と `:endinterface` の間で定義される。プリフィッ
クスとして `:export` を付けることができる: >
interface InterfaceName
endinterface
export interface InterfaceName
endinterface
< *E1344*
インターフェイスは、クラスと同じようにオブジェクト変数を宣言できるが、初期化子
は必要ない。
*E1345*
インターフェイスは、引数と戻り値の型を含む `:def` を使用してメソッドを宣言でき
るが、本体や `:enddef` は使用しない。例: >
interface HasSurface
var size: number
def Surface(): number
endinterface
インターフェイス名は大文字で始めなければならない。*E1343*
"Has" プリフィックスを使うことで、インターフェイス名であることが推測しやすくな
り、それが何を提供するものであるかのヒントを与えることができる。
インターフェイスは |Vim9| script ファイルでのみ定義できる。 *E1342*
インターフェイスは他のインターフェイスを "implement" することはできないが、他
のインターフェイスを "extend" することはできる。*E1381*
null オブジェクト ~
変数がオブジェクトの型を持つように宣言されているが初期化されていない場合、値は
null になる。この null オブジェクトを使用しようとすると、Vim はどのクラスを使
用することになっていたのかが分からないことがよくある。この場合、Vim は変数名が
正しいかどうかをチェックできず、変数名が無効な場合でも "Using a null object"
エラーが発生する。 *E1360* *E1362*
デフォルトコンストラクタ ~
*default-constructor*
new() メソッドを使用せずにクラスを定義した場合は、自動的に new() メソッドが定
義される。このデフォルトコンストラクタには、指定された順序ですべてのオブジェク
ト変数の引数が含まれる。したがって、クラスが次のような場合: >
class AutoNew
var name: string
var age: number
var gender: Gender
endclass
デフォルトコンストラクタは次のようになる: >
def new(this.name = v:none, this.age = v:none, this.gender = v:none)
enddef
"= v:none" のデフォルト値では、引数はオプションとなる。したがって、引数なしで
`new()` を呼び出すこともできる。割り当ては行われず、オブジェクト変数のデフォル
ト値が使用される。これは、デフォルト値を使用した、より便利な例である: >
class TextPosition
var lnum: number = 1
var col: number = 1
endclass
コンストラクタに必須の引数を持たせたい場合は、それを自分で記述する必要がああ
る。例えば、上記の AutoNew クラスで名前を取得する必要がある場合は、次のように
コンストラクタを定義できる: >
def new(this.name, this.age = v:none, this.gender = v:none)
enddef
<
デフォルトの new() メソッドを使用する場合、クラス内のオブジェクト変数の順序を
後で変更すると、デフォルトの new() メソッドの呼び出し元もすべて変更する必要が
ある。これを回避するために、new() メソッドを引数なしで明示的に定義することがで
きる。
*E1328*
Note ここでは "v:none" 以外のデフォルト値を使用できないことに注意。オブジェク
ト変数を初期化したい場合は、それらが宣言されている場所で実行すること。この方法
では、デフォルト値を 1 箇所で確認するだけで済む。
すべてのオブジェクト変数は、アクセス保護されたものを含め、デフォルトのコンスト
ラクタで使用されます。
クラスが別のクラスを拡張する場合、そのクラスのオブジェクト変数が最初に来る。
複数のコンストラクタ ~
*multiple-constructors*
通常、クラスには new() コンストラクタが 1 つだけある。コンストラクタが同じ引数
を使用して呼び出されることが多い場合は、それらの引数を 2 番目のコンストラクタ
メソッドに入れることでコードを簡素化できる。例えば、黒という色をよく使う場合
は、次のようにする: >
def new(this.garment, this.color, this.size)
enddef
...
var pants = new(Garment.pants, Color.black, "XL")
var shirt = new(Garment.shirt, Color.black, "XL")
var shoes = new(Garment.shoes, Color.black, "45")
毎回色を繰り返す代わりに、それを含むコンストラクタを追加できる: >
def newBlack(this.garment, this.size)
this.color = Color.black
enddef
...
var pants = newBlack(Garment.pants, "XL")
var shirt = newBlack(Garment.shirt, "XL")
var shoes = newBlack(Garment.shoes, "9.5")
Note メソッド名は "new" で始まる必要があることに注意。"new()" というメソッドが
ない場合は、他のコンストラクタメソッドがあっても、デフォルトコンストラクタが追
加される。
クラス内のメソッドをコンパイルする ~
*class-compile*
|:defcompile| コマンドを使用すると、クラスで定義されているすべてのクラスメソッ
ドおよびオブジェクトメソッドをコンパイルできる: >
defcompile MyClass # クラス "MyClass" をコンパイルする
defcompile # 現在のスクリプト内のクラス群をコンパイルする
<
==============================================================================
7. 型定義 *typealias* *Vim9-type* *:type*
*E1393* *E1395* *E1396* *E1397* *E1398*
型定義は、型指定に名前をつけることである。これは "型エイリアス" とも呼ばれる。
型エイリアスは、組み込み型が使える場所であればどこでも使うことができる。例: >
type ListOfStrings = list<string>
var s: ListOfStrings = ['a', 'b']
def ProcessStr(str: ListOfStrings): ListOfStrings
return str
enddef
echo ProcessStr(s)
<
*E1394*
型エイリアスは大文字で始める必要がある。既存の型のみエイリアスできる。
*E1399*
型エイリアスはスクリプトレベルでのみ作成でき、関数内では作成できない。型エイリ
アスはエクスポートし、スクリプト間で使用できる。
*E1400* *E1401* *E1402* *E1403* *E1407*
型エイリアスを式として使用することはできない。型エイリアスは代入の左辺では使用
できない。
型エイリアスの名前について、|typename()| 関数はエイリアスされた型を返す: >
type ListOfStudents = list<dict<any>>
echo typename(ListOfStudents)
typealias<list<dict<any>>>
<
==============================================================================
8. 列挙型 *Vim9-enum* *:enum* *:endenum*
*enum* *E1418* *E1419* *E1420*
列挙型は、値のリストの 1 つを持つことができる型である。例: >
:enum Color
White,
Red,
Green, Blue, Black
:endenum
<
*enumvalue* *E1422*
列挙値はコンマで区切られる。複数の列挙値を 1 行にリストできる。最後の列挙値の
後にコンマを付けてはならない。
列挙値には、列挙名に続いて値の名前を使用してアクセスする: >
var a: Color = Color.Blue
<
列挙型はクラスとして扱われ、各列挙値は本質的にそのクラスのインスタンスである。
|new()| メソッドを使用した一般的なオブジェクトのインスタンス化とは異なり、この
方法では列挙型インスタンスを作成できない。
列挙型は |Vim9| script ファイルでのみ定義できる。 *E1414*
列挙型は関数内で定義できない。
*E1415*
列挙名は大文字で始めなければならない。列挙型内の列挙値の名前は、大文字または小
文字で始めることができる。
*E1416*
列挙型はインターフェイスを実装できるが、クラスを拡張することはできない: >
enum MyEnum implements MyIntf
Value1,
Value2
def SomeMethod()
enddef
endenum
<
*enum-constructor*
列挙型内の列挙値値オブジェクトは、|new()| メソッドを使用する他のオブジェクトと
同じように構築される。関数を呼び出すのと同じように、引数を列挙値名の後に指定す
ることで、列挙型コンストラクタに引数を渡すことができる。デフォルトのコンストラ
クタには引数がない。
*E1417*
列挙型には、クラス変数、クラスメソッド、オブジェクト変数、およびオブジェクトメ
ソッドを含めることができる。列挙型内のメソッドを |:abstract| メソッドにするこ
とはできない。
次の例は、オブジェクト変数とオブジェクトメソッドを含む列挙型を示している: >
vim9script
enum Planet
Earth(1, false),
Jupiter(95, true),
Saturn(146, true)
var moons: number
var has_rings: bool
def GetMoons(): number
return this.moons
enddef
endenum
echo Planet.Jupiter.GetMoons()
echo Planet.Earth.has_rings
<
*E1421* *E1423* *E1424* *E1425*
列挙型とその値は不変である。数値型または文字列型として使用することはできない。
列挙値は変更可能なインスタンス変数を宣言できる。
*enum-name*
各列挙値オブジェクトには、列挙値の名前を含む "name" インスタンス変数がある。こ
れは読み取り専用の変数である。
*enum-ordinal* *E1426*
各列挙値には、0 から始まる序数が関連付けられている。列挙値の序数には、インスタ
ンス変数 "ordinal" を使用してアクセスできる。これは読み取り専用の変数である。
Note 列挙型内の列挙値の順序が変更されると、その序数の値も変更されることに注意。
*enum-values*
列挙型内のすべての値には、列挙型オブジェクトのリストである "values" クラス変数
を使用してアクセスできる。これは読み取り専用の変数である。
例: >
enum Planet
Mercury,
Venus,
Earth