-
Notifications
You must be signed in to change notification settings - Fork 0
/
l2.bak
1811 lines (1374 loc) · 111 KB
/
l2.bak
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
<!--# Classes and Inheritance-->
# Классы и наследование
<!--## Classes-->
## Классы
<!--Classes in Kotlin are declared using the keyword **class**:-->
Классы в <b>Kotlin</b> объявляются с помощью использования ключевого слова **class**:
``` kotlin
class Invoice {
}
```
<!--The class declaration consists of the class name, the class header (specifying its type parameters, the primary
constructor etc.) and the class body, surrounded by curly braces. Both the header and the body are optional;
if the class has no body, curly braces can be omitted.-->
Объявление класса состоит из имени класса, заголовка (указания типов его параметров, первичного конструктора и т.п) и тела класса,
заключённого в фигурные скобки. И заголовок, и тело класса являются необязательными составляющими: если у класса нет тела, фигурные скобки могут быть опущены.
``` kotlin
class Empty
```
<a name="constructors"></a>
<!--### Constructors-->
### Конструкторы
<!--A class in Kotlin can have a **primary constructor** and one or more **secondary constructors**. The primary
constructor is part of the class header: it goes after the class name (and optional type parameters).-->
Класс в <b>Kotlin</b> может иметь первичный конструктор (**primary constructor**) и один или более вторичных конструкторов (**secondary constructors**). Первичный конструктор является частью заголовка класса, его объявление идёт сразу после имени класса (и необязательных параметров):
``` kotlin
class Person constructor(firstName: String)
```
<!--If the primary constructor does not have any annotations or visibility modifiers, the **constructor**
keyword can be omitted:-->
Если у конструктора нет аннотаций и модификаторов видимости, ключевое слово **constructor** может быть опущено:
``` kotlin
class Person(firstName: String)
```
<!--The primary constructor cannot contain any code. Initialization code can be placed
in **initializer blocks**, which are prefixed with the **init**keyword:-->
Первичный конструктор не может содержать в себе исполняемого кода. Инициализирующий код может быть помещён в соответствующий блок (**initializers blocks**), который помечается словом **init**:
``` kotlin
class Customer(name: String) {
init {
logger.info("Customer initialized with value ${name}")
}
}
```
<!--Note that parameters of the primary constructor can be used in the initializer blocks. They can also be used in
property initializers declared in the class body:-->
Обратите внимание, что параметры первичного конструктора могут быть использованы в инициализирующем блоке. Они также могут быть использованы при инициализации свойств в теле класса:
``` kotlin
class Customer(name: String) {
val customerKey = name.toUpperCase()
}
```
<!--In fact, for declaring properties and initializing them from the primary constructor, Kotlin has a concise syntax:-->
В действительности, для объявления и инициализации свойств первичного конструктора в <b>Kotlin</b> есть лаконичное синтаксическое решение:
``` kotlin
class Person(val firstName: String, val lastName: String, var age: Int) {
// ...
}
```
<!--Much the same way as regular properties, the properties declared in the primary constructor can be
mutable (**var**) or read-only (**val**).-->
Свойства, объявленные в первичном конструкторе, могут быть изменяемые (**var**) и неизменяемые (**val**).
<!--If the constructor has annotations or visibility modifiers, the **constructor** keyword is required, and
the modifiers go before it:-->
Если у конструктора есть аннотации или модификаторы видимости, ключевое слово **constructor** обязательно, и модификаторы используются перед ним:
``` kotlin
class Customer public @Inject constructor(name: String) { ... }
```
<!--For more details, see [Visibility Modifiers](visibility-modifiers.html#constructors).-->
Для более подробной информации по данному вопросу см. ["Модификаторы доступа"](visibility-modifiers.html#constructors).
<!--#### Secondary Constructors-->
#### Второстепенные конструкторы
<!--The class can also declare **secondary constructors**, which are prefixed with **constructor**:-->
В классах также могут быть объявлены дополнительные конструкторы (**secondary constructors**), перед которыми используется ключевое слово **constructor**:
``` kotlin
class Person {
constructor(parent: Person) {
parent.children.add(this)
}
}
```
<!--If the class has a primary constructor, each secondary constructor needs to delegate to the primary constructor, either
directly or indirectly through another secondary constructor(s). Delegation to another constructor of the same class
is done using the **this** keyword:-->
Если у класса есть главный (первичный) конструктор, каждый последующий конструктор должен прямо или косвенно ссылаться (через другой(_ие_) конструктор(_ы_)) на первичный:
``` kotlin
class Person(val name: String) {
constructor(name: String, parent: Person) : this(name) {
parent.children.add(this)
}
}
```
<!--If a non-abstract class does not declare any constructors (primary or secondary), it will have a generated primary
constructor with no arguments. The visibility of the constructor will be public. If you do not want your class
to have a public constructor, you need to declare an empty primary constructor with non-default visibility:-->
Если в абстрактном классе не объявлено никаких конструкторов (первичных или второстепенных), у этого класса автоматически сгенерируется пустой конструктор без параметров. Видимость этого конструктора будет **public**. Если вы не желаете иметь класс с открытым **public** конструктором, вам необходимо объявить пустой конструктор с соответствующим модификатором видимости:
``` kotlin
class DontCreateMe private constructor () {
}
```
>
**Примечание**: В виртуальной машине JVM компилятор генерирует дополнительный конструктор без параметров в случае, если все параметры первичного конструктора имеют значения по умолчанию. Это делает использование таких библиотек, как <b>Jackson</b> и <b>JPA</b>, более простым в языке <b>Kotlin</b>, так как они используют пустые конструкторы при создании экземпляров классов.
``` kotlin
class Customer(val customerName: String = "")
```
<!--### Creating instances of classes-->
### Создание экземпляров классов
<!--To create an instance of a class, we call the constructor as if it were a regular function:-->
Для создания экземпляра класса конструктор вызывается так, как если бы он был обычной функцией:
``` kotlin
val invoice = Invoice()
val customer = Customer("Joe Smith")
```
<!--Note that Kotlin does not have a **new** keyword.-->
Обращаем ваше внимание на то, что в <b>Kotlin</b> не используется ключевое слово **new**.
<!--### Class Members-->
### Члены класса
<!--Classes can contain-->
Классы могут содержать в себе:
<!--* Constructors and initializer blocks
* [Functions](functions.html)
* [Properties](properties.html)
* [Nested and Inner Classes](nested-classes.html)
* [Object Declarations](object-declarations.html)-->
* Конструкторы и инициализирующие блоки
* [Функции](functions.html)
* [Свойства](properties.html)
* [Вложенные классы](nested-classes.html)
* [Объявления объектов](object-declarations.html)
<a name="inheritance"></a>
<!--## Inheritance-->
## Наследование
<!--All classes in Kotlin have a common superclass `Any`, that is a default super for a class with no supertypes declared:-->
Для всех классов в языке <b>Koltin</b> родительским суперклассом является класс `Any`. Он также является родительским классом для любого класса, в котором не указан какой-либо другой родительский класс:
``` kotlin
class Example // Implicitly inherits from Any
```
<!--`Any` is not `java.lang.Object`; in particular, it does not have any members other than `equals()`, `hashCode()` and `toString()`.
Please consult the [Java interoperability](java-interop.html#object-methods) section for more details.-->
Класс `Any` не является аналогом `java.lang.Object`. В частности, у него нет никаких членов кроме методов: `equals()`, `hashCode()`, и `toString()`. Пожалуйста, ознакомьтесь с [совместимостью c Java](http://kotlinlang.org/docs/reference/java-interop.html#object-methods) для более подробной информации.
<!--To declare an explicit supertype, we place the type after a colon in the class header:-->
Для явного объявления суперкласса мы помещаем его имя за знаком двоеточия в оглавлении класса:
``` kotlin
open class Base(p: Int)
class Derived(p: Int) : Base(p)
```
<!--If the class has a primary constructor, the base type can (and must) be initialized right there,
using the parameters of the primary constructor.-->
Если у класса есть основной конструктор, базовый тип может (и должен) быть проинициализирован там же, с использованием параметров первичного конструктора.
<!--If the class has no primary constructor, then each secondary constructor has to initialize the base type
using the **super** keyword, or to delegate to another constructor which does that.
Note that in this case different secondary constructors can call different constructors of the base type:-->
Если у класса нет первичного конструктора, тогда каждый последующий второстепенный конструктор должен включать в себя инициализацию базового типа с помощью ключевого слова **super** или давать отсылку на другой конструктор, который это делает.
Примечательно, что любые вторичные конструкторы могут ссылаться на разные конструкторы базового типа:
``` kotlin
class MyView : View {
constructor(ctx: Context) : super(ctx) {
}
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) {
}
}
```
<!--The **open** annotation on a class is the opposite of Java's **final**: it allows others
to inherit from this class. By default, all classes in Kotlin are final, which
corresponds to [Effective Java](http://www.oracle.com/technetwork/java/effectivejava-136174.html),
Item 17: *Design and document for inheritance or else prohibit it*.-->
Ключевое слово **open** является противоположностью слову **final** в <b>Java</b>: оно позволяет другим классам наследоваться от данного. По умолчанию, все классы в <b>Kotlin</b> имеют статус **final**, что отвечает [Effective Java](http://www.oracle.com/technetwork/java/effectivejava-136174.html), Item 17: *Design and document for inheritance or else prohibit it*.
<!--### Overriding Members-->
<a name="overriding-properties"></a>
### Переопределение членов класса
<!--As we mentioned before, we stick to making things explicit in Kotlin. And unlike Java, Kotlin requires explicit
annotations for overridable members (we call them *open*) and for overrides:-->
Как упоминалось ранее, мы придерживаемся идеи определённости и ясности в языке <b>Kotlin</b>. И, в отличие от <b>Java</b>, <b>Kotlin</b>
требует чёткой аннотации и для членов, которые могут быть переопределены, и для самого переопределения:
``` kotlin
open class Base {
open fun v() {}
fun nv() {}
}
class Derived() : Base() {
override fun v() {}
}
```
<!--The **override** annotation is required for `Derived.v()`. If it were missing, the compiler would complain.
If there is no **open** annotation on a function, like `Base.nv()`, declaring a method with the same signature in a subclass is illegal,
either with **override** or without it. In a final class (e.g. a class with no **open** annotation), open members are prohibited.-->
Для `Derived.v()` необходима аннотация **override**. В случае её отсутствия компилятор выдаст ошибку. Если у функции типа `Base.nv()` нет аннотации **open**, объявление метода с такой же сигнатурой в производном классе невозможно, с **override** или без. В **final** классе (классе без аннотации **open**), запрещено использование аннотации **open** для его членов.
<!--A member marked **override** is itself open, i.e. it may be overridden in subclasses. If you want to prohibit re-overriding, use **final**:-->
Член класса, помеченный **override**, является сам по себе **open**, т.е. он может быть переопределён в производных классах. Если вы хотите запретить возможность переопределения такого члена, используйте **final**:
``` kotlin
open class AnotherDerived() : Base() {
final override fun v() {}
}
```
<!--#### Wait! How will I hack my libraries now?!-->
#### Стойте! Как мне теперь хакнуть свои библиотеки?
<!--One issue with our approach to overriding (classes and members final by default) is that it would be difficult to subclass something inside the libraries you use to override some method that was not intended for overriding by the library designer, and introduce some nasty hack there.-->
При нашем подходе к переопределению классов и их членов (которые по дефолту **final**) будет сложно унаследоваться от чего-нибудь внутри используемых вами библиотек для того, чтобы переопределить не предназначенный для этого метод и внедрить туда свой гнусный хак.
<!--We think that this is not a disadvantage, for the following reasons:-->
Мы думаем, что это не является недостатком по следующим причинам:
<!--* Best practices say that you should not allow these hacks anyway
* People successfully use other languages (C++, C#) that have similar approach
* If people really want to hack, there still are ways: you can always write your hack in Java and call it from Kotlin (*see [Java Interop](java-interop.html)*), and Aspect frameworks always work for these purposes-->
* Опыт поколений говорит о том, что, в любом случае, лучше не позволять внедрять такие хаки
* Люди успешно используют другие языки (<b>C++</b>, <b>C#</b>), которые имеют аналогичный подход к этому вопросу
* Если кто-то действительно хочет хакнуть, пусть напишет свой код на <b>Java</b> и вызовет его в <b>Kotlin</b> _(см. [Java-совместимость](http://kotlinlang.org/docs/reference/java-interop.html))_
<!--### Overriding Rules-->
### Правила переопределения
<!--In Kotlin, implementation inheritance is regulated by the following rule: if a class inherits many implementations of the same member from its immediate superclasses,
it must override this member and provide its own implementation (perhaps, using one of the inherited ones).
To denote the supertype from which the inherited implementation is taken, we use **super** qualified by the supertype name in angle brackets, e.g. `super<Base>`:-->
В <b>Kotlin</b> правила наследования имплементации определены следующим образом: если класс перенимает большое количество имплементаций одного и того члена от ближайших родительских классов, он должен переопределить этот член и обеспечить свою собственную имплементацию (возможно, используя одну из унаследованных). Для того, чтобы отметить супертип (родительский класс), от которого мы унаследовали данную имплементацию, мы используем ключевое слово **super**. Для уточнения имя родительского супертипа используются треугольные скобки, например `super<Base>`:
``` kotlin
open class A {
open fun f() { print("A") }
fun a() { print("a") }
}
interface B {
fun f() { print("B") } // interface members are 'open' by default
fun b() { print("b") }
}
class C() : A(), B {
// The compiler requires f() to be overridden:
override fun f() {
super<A>.f() // call to A.f()
super<B>.f() // call to B.f()
}
}
```
<!---It's fine to inherit from both `A` and `B`, and we have no problems with `a()` and `b()` since `C` inherits only one implementation of each of these functions.
But for `f()` we have two implementations inherited by `C`, and thus we have to override `f()` in `C`
and provide our own implementation that eliminates the ambiguity.-->
Нормально наследоваться одновременно от `A` и `B`. У нас не возникнет никаких проблем с `a()` и `b()` в том случае, если `C` унаследует только одну имплементацию этих функций.
Но для `f()` у нас есть две имплементации, унаследованные классом `C`, поэтому необходимо переопределить `f()` в `C` и обеспечить нашу собственную реализацию этого метода для устранения получившейся неоднозначности.
<!--## Abstract Classes-->
## Абстрактные классы
<!--A class and some of its members may be declared **abstract**
An abstract member does not have an implementation in its class.
Note that we do not need to annotate an abstract class or function with open – it goes without saying.-->
Класс и некоторые его члены могут быть объявлены как **abstract**. Абстрактный член не имеет реализации в его классе.
Обратите внимание, что нам не надо аннотировать абстрактный класс или функцию словом **open** - это подразумевается и так.
<!--We can override a non-abstract open member with an abstract one-->
Можно переопределить не-абстрактный **open** член абстрактным
``` kotlin
open class Base {
open fun f() {}
}
abstract class Derived : Base() {
override abstract fun f()
}
```
<!--## Companion Objects-->
## Объекты-помощники
<!--In Kotlin, unlike Java or C#, classes do not have static methods. In most cases, it's recommended to simply use
package-level functions instead.-->
В <b>Kotlin</b>, в отличие от <b>Java</b> или <b>C#</b>, в классах не бывает статических методов. В большинстве случаев рекомендуется использовать функции на уровне пакета (ориг.: _"package-level functions"_).
<!--If you need to write a function that can be called without having a class instance but needs access to the internals
of a class (for example, a factory method), you can write it as a member of an [object declaration](object-declarations.html)
inside that class.-->
Если вам нужно написать функцию, которая может быть использована без создания экземпляра класса, но имела бы доступ к данным внутри этого класса (к примеру, фабричный метод), вы можете написать её как член [объявления объекта](object-declarations.html) внутри этого класса.
<!--Even more specifically, if you declare a [companion object](object-declarations.html#companion-objects) inside your class,
you'll be able to call its members with the same syntax as calling static methods in Java/C#, using only the class name
as a qualifier.-->
В частности, если вы объявляете [объект-помощник](object-declarations.html#companion-objects) в своём классе, у вас появляется возможность обращаться к его членам, используя тот же синтаксис, как при использовании статических методов в <b>Java</b>/<b>C#</b> (указав название класса для доступа).
--------------------------------------------------------------------------------
<!--# Data Classes-->
# Классы данных
<!--We frequently create classes that do nothing but hold data. In such classes some functionality is often mechanically
derivable from the data they hold. In Kotlin a class can be marked as `data`:-->
Нередко мы создаём классы, единственным назначением которых является хранение данных. Функционал таких классов зависит от самих данных, которые в них хранятся. В <b>Kotlin</b> класс может быть отмечен словом `data`:
``` kotlin
data class User(val name: String, val age: Int)
```
<!--This is called a _data class_. The compiler automatically derives the following members from all properties declared in
the primary constructor:-->
Такой класс называется _классом данных_. Компилятор автоматически извлекает все члены данного класса из свойств, объявленных в первичном конструкторе:
* пара функций `equals()`/`hashCode()`,
* `toString()` в форме `"User(name=John, age=42)"`,
* функции [componentN()](multi-declarations.html), которые соответствуют свойствам, в зависимости от их порядка либо объявления,
* функция `copy()` (см. ниже)
<!--If any of these functions is explicitly defined in the class body or inherited from the base types, it will not be generated.-->
Если какая-либо из этих функций явно определена в теле класса (или унаследована от родительского класса), то генерироваться она не будет.
<!--To ensure consistency and meaningful behavior of the generated code, data classes have to fulfil the following requirements:-->
Для того, чтобы поведение генерируемого кода соответствовало здравому смыслу, классы данных должны быть оформлены с соблюдением некоторых требований:
* Первичный конструктор должен иметь как минимум один параметр;
* Все параметры первичного конструктора должны быть отмечены, как `val` или `var`;
* Классы данных не могут быть абстрактными, open, sealed или inner;
* Дата-классы не могут наследоваться от других классов (но могут реализовывать интерфейсы).
<!-- Since 1.1, data classes may extend other classes (see Sealed classes for examples). -->
Начиная с версии 1.1, классы данных могут расширять другие классы (см. примеры в [Sealed classes](sealed-classes.html#sealed-classes-and-data-classes))
> Для того, чтобы у сгенерированного в JVM класса был конструктор без параметров, значения всех свойств должны быть заданы по умолчанию
> (см. [Конструкторы](classes.html#constructors))
``` kotlin
data class User(val name: String = "", val age: Int = 0)
```
<!--## Copying-->
## Копирование
<!--It's often the case that we need to copy an object altering _some_ of its properties, but keeping the rest unchanged.
This is what `copy()` function is generated for. For the `User` class above, its implementation would be as follows:-->
Довольно часто нам приходится копировать объект с изменением только _некоторых_ его свойств. Для этой задачи генерируется функция `copy()`. Для написанного выше класса `User` такая реализация будет выглядеть следующим образом:
``` kotlin
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
```
<!--This allows us to write-->
Это позволяет нам писать
``` kotlin
val jack = User(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)
```
<!--## Data Classes and Destructuring Declarations-->
## Классы данных и мульти-декларации
<!--_Component functions_ generated for data classes enable their use in [destructuring declarations](multi-declarations.html):-->
Сгенерированные для классов данных _составные функции_ позволяют использовать их в [мульти-декларациях](multi-declarations.html):
``` kotlin
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") // выводит "Jane, 35 years of age"
```
<!--## Standard Data Classes-->
## Стандартные классы данных
<!--The standard library provides `Pair` and `Triple`. In most cases, though, named data classes are a better design choice,
because they make the code more readable by providing meaningful names for properties.-->
Стандартная библиотека предоставляет `Pair` и `Triple`. Однако, в большинстве случаев, проименованные классы данных являются лучшим решением, потому что делают код более читаемым, избегая малосодержательные имена для свойств.
> [Статья на эту тему на Хабре](https://habrahabr.ru/company/JetBrains/blog/152126/)
--------------------------------------------------------------------------------
<!--# Delegated Properties-->
<!--https://habrahabr.ru/company/JetBrains/blog/183444/-->
# Делегированные свойства
_За помощь в переводе спасибо [официальному блогу JetBrains на Хабрахабре](https://habrahabr.ru/company/JetBrains/blog/183444/)_
<!--There are certain common kinds of properties, that, though we can implement them manually every time we need them,
would be very nice to implement once and for all, and put into a library. Examples include-->
Существует несколько основных видов свойств, которые мы реализовываем каждый раз вручную в случае их надобности. Однако намного удобнее было бы реализовать их раз и навсегда и положить в какую-нибудь библиотеку. Примеры таких свойств:
<!--* lazy properties: the value gets computed only upon first access,
* observable properties: listeners get notified about changes to this property,
* storing properties in a map, not in separate field each.-->
* ленивые свойства (lazy properties): значение вычисляется один раз, при первом обращении
* свойства, на события об изменении которых можно подписаться (observable properties)
* свойства, хранимые в ассоциативном списке, а не в отдельных полях
<!--To cover these (and other) cases, Kotlin supports _delegated properties_:-->
Для таких случаев, Kotlin поддерживает _делегированные свойства_:
``` kotlin
class Example {
var p: String by Delegate()
}
```
<!--The syntax is: `val/var <property name>: <Type> by <expression>`. The expression after *by*{:.keyword} is the _delegate_,
because `get()` (and `set()`) corresponding to the property will be delegated to its `getValue()` and `setValue()` methods.
Property delegates don’t have to implement any interface, but they have to provide a `getValue()` function (and `setValue()` - for *var*{:.keyword}'s).
For example: -->
Их синтаксис выглядит следующим образом: `val/var <имя свойства>: <Тип> by <выражение>`. Выражение после *by* — _делегат_: обращения (`get()`, `set()`) к свойству будут обрабатываться этим выражением.
Делегат не обязан реализовывать какой-то интерфейс, достаточно, чтобы у него были методы `getValue()` и `setValue()` с определённой сигнатурой:
``` kotlin
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, спасибо за делегирование мне '${property.name}'!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value было присвоено значению '${property.name} в $thisRef.'")
}
}
```
<!--When we read from `p` that delegates to an instance of `Delegate`, the `getValue()` function from `Delegate` is called,
so that its first parameter is the object we read `p` from and the second parameter holds a description of `p` itself
(e.g. you can take its name). For example: -->
Когда мы читаем значение свойства `p`, вызывается метод `getValue()` класса `Delegate`, причем первым параметром ей передается тот объект, у которого запрашивается свойство `p`, а вторым — объект-описание самого свойства p (у него можно, в частности, узнать имя свойства). Например:
``` kotlin
val e = Example()
println(e.p)
```
<!--This prints -->
Этот код выведет
``` kotlin
Example@33a17727, спасибо за делегирование мне ‘p’!
```
<!--Similarly, when we assign to `p`, the `setValue()` function is called. The first two parameters are the same, and the third holds the value being assigned:-->
Похожим образом, когда мы обращаемся к `p`, вызывается метод `setValue()`. Два первых параметра — такие же, как у get(), а третий — присваиваемое значение свойства:
``` kotlin
e.p = "NEW"
```
<!--This prints-->
Этот код выведет
``` kotlin
NEW было присвоено значению ‘p’ в Example@33a17727.
```
<!--The specification of the requirements to the delegated object can be found [below](delegated-properties.html#property-delegate-requirements).-->
Спецификация требований к делегированным свойствам может быть найдена [ниже](delegated-properties.html#property-delegate-requirements).
<!--Note that since Kotlin 1.1 you can declare a delegated property inside a function or code block, it shouldn't necessarily be a member of a class.
Below you can find [the example](delegated-properties.html#local-delegated-properties-since-11).-->
Заметьте, что начиная с версии Kotlin 1.1, вы можете объявлять делегированные свойства внутри функций или блоков кода, а не только внутри классов. Снизу вы можете найти пример.
<!--## Standard Delegates-->
## Стандартные делегаты
<!--The Kotlin standard library provides factory methods for several useful kinds of delegates.-->
Стандартная библиотека Kotlin предоставляет несколько полезных видов делегатов:
### Ленивые свойства (lazy properties)
<!--`lazy()` is a function that takes a lambda and returns an instance of `Lazy<T>` which can serve as a delegate for implementing a lazy property:
the first call to `get()` executes the lambda passed to `lazy()` and remembers the result,
subsequent calls to `get()` simply return the remembered result. -->
`lazy()` это функция, которая принимает лямбду и возвращает экземпляр класса `Lazy<T>`, который служит делегатом для реализации ленивого свойства: первый вызов `get()` запускает лямбда-выражение, переданное `lazy()` в качестве аргумента, и запоминает полученное значение, а последующие вызовы просто возвращают вычисленное значение.
``` kotlin
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
fun main(args: Array<String>) {
println(lazyValue)
println(lazyValue)
}
```
Этот код выведет:
```
computed!
Hello
Hello
```
<!--By default, the evaluation of lazy properties is **synchronized**: the value is computed only in one thread, and all threads
will see the same value. If the synchronization of initialization delegate is not required, so that multiple threads
can execute it simultaneously, pass `LazyThreadSafetyMode.PUBLICATION` as a parameter to the `lazy()` function.
And if you're sure that the initialization will always happen on a single thread, you can use `LazyThreadSafetyMode.NONE` mode,
which doesn't incur any thread-safety guarantees and the related overhead.-->
По умолчанию вычисление ленивых свойств **синхронизировано**: значение вычисляется только в одном потоке выполнения, и все остальные потоки могут видеть одно и то же значение. Если синхронизация не требуется, передайте `LazyThreadSafetyMode.PUBLICATION` в качестве параметра в функцию `lazy()`, тогда несколько потоков смогут исполнять вычисление одновременно. Или если вы уверены, что инициализация всегда будет происходить в одном потоке исполнения, вы можете использовать режим `LazyThreadSafetyMode.NONE`, который не гарантирует никакой потокобезопасности.
### Observable свойства
<!--`Delegates.observable()` takes two arguments: the initial value and a handler for modifications.
The handler gets called every time we assign to the property (_after_ the assignment has been performed). It has three
parameters: a property being assigned to, the old value and the new one:-->
Функция `Delegates.observable()` принимает два аргумента: начальное значение свойства и обработчик (лямбда), который вызывается при изменении свойства. У обработчика три параметра: описание свойства, которое изменяется, старое значение и новое значение.
``` kotlin
import kotlin.properties.Delegates
class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
}
fun main(args: Array<String>) {
val user = User()
user.name = "first"
user.name = "second"
}
```
<!--This example prints:-->
Этот код выведет:
```
<no name> -> first
first -> second
```
Если Вам нужно иметь возможность запретить присваивание некоторых значений, используйте функцию `vetoable()` вместо `observable()`.
<!--## Storing Properties in a Map-->
## Хранение свойств в ассоциативном списке
<!--One common use case is storing the values of properties in a map.
This comes up often in applications like parsing JSON or doing other “dynamic” things.
In this case, you can use the map instance itself as the delegate for a delegated property.-->
Один из самых частых сценариев использования делегированных свойств заключается в хранении свойств в ассоциативном списке. Это полезно в "динамическом" коде, например, при работе с JSON:
``` kotlin
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
```
<!--In this example, the constructor takes a map:-->
В этом примере конструктор принимает ассоциативный список
``` kotlin
val user = User(mapOf(
"name" to "John Doe",
"age" to 25
))
```
<!--Delegated properties take values from this map (by the string keys – names of properties):-->
Делегированные свойства берут значения из этого ассоциативного списка (по строковым ключам)
``` kotlin
println(user.name) // Prints "John Doe"
println(user.age) // Prints 25
```
<!--This works also for *var*{:.keyword}’s properties if you use a `MutableMap` instead of read-only `Map`:-->
Также, если вы используете `MutableMap` вместо `Map`, поддерживаются изменяемые свойства (var):
``` kotlin
class MutableUser(val map: MutableMap<String, Any?>) {
var name: String by map
var age: Int by map
}
```
<!--## Local Delegated Properties (since 1.1)-->
## Локальные делегированные свойства (с версии 1.1)
<!--You can declare local variables as delegated properties.
For instance, you can make a local variable lazy:-->
Вы можете объявить локальные переменные как делегированные свойства. Например, вы можете сделать локальную переменную ленивой:
``` kotlin
fun example(computeFoo: () -> Foo) {
val memoizedFoo by lazy(computeFoo)
if (someCondition && memoizedFoo.isValid()) {
memoizedFoo.doSomething()
}
}
```
<!--The `memoizedFoo` variable will be computed on the first access only.
If `someCondition` fails, the variable won't be computed at all.-->
Переменная `memoizedFoo` будет вычислена только при первом обращении к ней.
Если условие `someCondition` будет ложно, значение переменной не будет вычислено вовсе.
<a name="property-delegate-requirements"></a>
<!--## Property Delegate Requirements-->
## Требования к делегированным свойствам
<!--Here we summarize requirements to delegate objects. -->
Здесь приведены требования к объектам-делегатам.
<!--For a **read-only** property (i.e. a *val*{:.keyword}), a delegate has to provide a function named `getValue` that takes the following parameters:-->
Для **read-only** свойства (например *val*), делегат должен предоставлять функцию `getValue`, которая принимает следующие параметры:
<!--* `thisRef` - must be the same or a supertype of the _property owner_ (for extension properties - the type being extended),
* `property` - must be of type `KProperty<*>` or its supertype, this function must return the same type as property (or its subtype).-->
* `thisRef` — должен иметь такой же тип или быть наследником типа _хозяина свойства_ (для [расширений](extensions.html) — тип, который расширяется)
* `property` — должен быть типа `KProperty<*>` или его родительского типа. Эта функция должна возвращать значение того же типа, что и свойство (или его родительского типа).
<!--For a **mutable** property (a *var*{:.keyword}), a delegate has to _additionally_ provide a function named `setValue` that takes the following parameters:-->
Для **изменяемого** свойства (*var*) делегат должен _дополнительно_ предоставлять функцию `setValue`, которая принимает следующие параметры:
<!--* `thisRef` — same as for `getValue()`,
* `property` — same as for `getValue()`,
* new value — must be of the same type as a property or its supertype.-->
* `thisRef` — то же что и у `getValue()`,
* `property` — то же что и у `getValue()`,
* new value — должен быть того же типа, что и свойство (или его родительского типа).
<!--`getValue()` and/or `setValue()` functions may be provided either as member functions of the delegate class or extension functions.
The latter is handy when you need to delegate property to an object which doesn't originally provide these functions.
Both of the functions need to be marked with the `operator` keyword.-->
Функции `getValue()` и/или `setValue()` могут быть предоставлены либо как члены класса-делегата, либо как его [расширения](extensions.html). Последнее полезно когда вам нужно делегировать свойство объекту, который изначально не имеет этих функций. Обе эти функции должны быть отмечены с помощью ключевого слова `operator`.
<!--The delegate class may implement one of the interfaces `ReadOnlyProperty` and `ReadWriteProperty` containing the required `operator` methods.
These interfaces are declared in the Kotlin standard library:-->
Эти интерфейсы объявлены в стандартной библиотеке Kotlin:
``` kotlin
interface ReadOnlyProperty<in R, out T> {
operator fun getValue(thisRef: R, property: KProperty<*>): T
}
interface ReadWriteProperty<in R, T> {
operator fun getValue(thisRef: R, property: KProperty<*>): T
operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}
```
<!--### Translation Rules-->
### Translation Rules
<!--Under the hood for every delegated property the Kotlin compiler generates an auxiliary property and delegates to it.
For instance, for the property `prop` the hidden property `prop$delegate` is generated, and the code of the accessors simply delegates to this additional property:-->
Для каждого делегированного свойства компилятор Kotlin "за кулисами" генерирует вспомогательное свойство и делегирует его. Например, для свойства `prop` генерируется скрытое свойство `prop$delegate`, и исполнение геттеров и сеттеров просто делегируется этому дополнительному свойству:
``` kotlin
class C {
var prop: Type by MyDelegate()
}
// этот код генерируется компилятором:
class C {
private val prop$delegate = MyDelegate()
var prop: Type
get() = prop$delegate.getValue(this, this::prop)
set(value: Type) = prop$delegate.setValue(this, this::prop, value)
}
```
<!--The Kotlin compiler provides all the necessary information about `prop` in the arguments: the first argument `this` refers to an instance of the outer class `C` and `this::prop` is a reflection object of the `KProperty` type describing `prop` itself.-->
Компилятор Kotlin предоставляет всю необходимую информацию о `prop` в аргументах: первый аргумент `this` ссылается на экземпляр внешнего класса `C` и `this::prop` reflection-объект типа `KProperty`, описывающий сам `prop`.
<!--Note that the syntax `this::prop` to refer a [bound callable reference](reflection.html#bound-function-and-property-references-since-11) in the code directly is available only since Kotlin 1.1.-->
Заметьте, что синтаксис `this::prop` для обращения к [bound callable reference](http://kotlinlang.org/docs/reference/reflection.html#bound-function-and-property-references-since-11) напрямую в коде программы доступен только с Kotlin версии 1.1
<!--### Providing a delegate (since 1.1)-->
### Предоставление делегата
_Примечание: Предоставление делегата доступно в Kotlin начиная с версии 1.1_
<!--By defining the `provideDelegate` operator you can extend the logic of creating the object to which the property implementation is delegated.
If the object used on the right hand side of `by` defines `provideDelegate` as a member or extension function, that function will be
called to create the property delegate instance.-->
С помощью определения оператора `provideDelegate` вы можете расширить логику создания объекта, которому будет делегировано свойство. Если объект, который используется справа от `by`, определяет `provideDelegate` как член или как [расширение](extensions.html), эта функция будет вызвана для создания экземпляра делегата.
<!--One of the possible use cases of `provideDelegate` is to check property consistency when the property is created, not only in its getter or setter.-->
Один из возможных юзкейсов `provideDelegate` — это проверка состояния свойства при его создании.
<!--For example, if you want to check the property name before binding, you can write something like this:-->
Например, если вы хотите проверить имя свойства перед связыванием, вы можете написать что-то вроде:
``` kotlin
class ResourceLoader<T>(id: ResourceID<T>) {
operator fun provideDelegate(
thisRef: MyUI,
prop: KProperty<*>
): ReadOnlyProperty<MyUI, T> {
checkProperty(thisRef, prop.name)
// создание делегата
}
private fun checkProperty(thisRef: MyUI, name: String) { ... }
}
fun <T> bindResource(id: ResourceID<T>): ResourceLoader<T> { ... }
class MyUI {
val image by bindResource(ResourceID.image_id)
val text by bindResource(ResourceID.text_id)
}
```
<!--The parameters of `provideDelegate` are the same as for `getValue`:-->
`provideDelegate` имеет те же параметры, что и `getValue`:
<!--* `thisRef` - must be the same or a supertype of the _property owner_ (for extension properties - the type being extended),
* `property` - must be of type `KProperty<*>` or its supertype.-->
* `thisRef` — должен иметь такой же тип, или быть наследником типа _хозяина свойства_ (для [расширений](extensions.html) — тип, который расширяется)
* `property` — должен быть типа `KProperty<*>` или его родительского типа. Эта функция должна возвращать значение того же типа, что и свойство (или его родительского типа)
<!--The `provideDelegate` method is called for each property during the creation of the `MyUI` instance, and it performs the necessary validation right away.-->
Метод `provideDelegate` вызывается для каждого свойства во время создания экземпляра `MyUI`, и сразу совершает необходимые проверки.
<!--Without this ability to intercept the binding between the property and its delegate, to achieve the same functionality
you'd have to pass the property name explicitly, which isn't very convenient:-->
Не будь этой возможности внедрения между свойством и делегатом, для достижения той же функциональности вам бы пришлось передавать имя свойства явно, что не очень удобно:
``` kotlin
// Проверяем имя свойства без "provideDelegate"
class MyUI {
val image by bindResource(ResourceID.image_id, "image")
val text by bindResource(ResourceID.text_id, "text")
}
fun <T> MyUI.bindResource(
id: ResourceID<T>,
propertyName: String
): ReadOnlyProperty<MyUI, T> {
checkProperty(this, propertyName)
// создание делегата
}
```
<!--In the generated code, the `provideDelegate` method is called to initialize the auxiliary `prop$delegate` property.
Compare the generated code for the property declaration `val prop: Type by MyDelegate()` with the generated code
[above](delegated-properties.html#translation-rules) (when the `provideDelegate` method is not present):-->
В сгенерированном коде метод `provideDelegate` вызывается для инициализации вспомогательного свойства `prop$delegate`.
Сравните сгенерированный для объявления свойства код `val prop: Type by MyDelegate()` со сгенерированным кодом из Transaction Rules (когда `provideDelegate` не представлен):
``` kotlin
class C {
var prop: Type by MyDelegate()
}
// этот код будет сгенерирован компилятором
// когда функция 'provideDelegate' доступна:
class C {
// вызываем "provideDelegate" для создания вспомогательного свойства "delegate"
private val prop$delegate = MyDelegate().provideDelegate(this, this::prop)
val prop: Type
get() = prop$delegate.getValue(this, this::prop)
}
```
<!--Note that the `provideDelegate` method affects only the creation of the auxiliary property and doesn't affect the code generated for getter or setter.-->
Заметьте, что метод `provideDelegate` влияет только на создание вспомогательного свойства и не влияет на код, генерируемый геттером или сеттером.
--------------------------------------------------------------------------------
<!--# Delegation-->
# Делегирование
<!--## Class Delegation-->
## Делегирование класса
<!--The [Delegation pattern](https://en.wikipedia.org/wiki/Delegation_pattern) has proven to be a good alternative to implementation inheritance,
and Kotlin supports it natively requiring zero boilerplate code.
A class `Derived` can inherit from an interface `Base` and delegate all of its public methods to a specified object:-->
[Шаблон делегирования](https://ru.wikipedia.org/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%B4%D0%B5%D0%BB%D0%B5%D0%B3%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)
является хорошей альтернативой наследованию, и Kotlin поддерживает его нативно, освобождая вас от необходимости написания шаблонного кода.
``` kotlin
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main(args: Array<String>) {
val b = BaseImpl(10)
Derived(b).print() // prints 10
}
```
<!--The *by*{: .keyword }-clause in the supertype list for `Derived` indicates that `b` will be stored internally in objects of `Derived`
and the compiler will generate all the methods of `Base` that forward to `b`.-->
Ключевое слово `by` в оглавлении `Derived`, находящееся после типа делегируемого класса, говорит о том, что объект `b` типа `Base` будет храниться внутри экземпляра `Derived`, и компилятор сгенерирует у `Derived` соответствующие методы из `Base`, которые при вызове будут переданы объекту `b`
--------------------------------------------------------------------------------
<!--# Enum Classes-->
# Перечисляемые типы
<!--The most basic usage of enum classes is implementing type-safe enums-->
Наиболее базовый пример использования enum — это реализация типобезопасных перечислений
``` kotlin
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
```
<!--Each enum constant is an object. Enum constants are separated with commas.-->
Каждая enum-константа является объектом. При объявлении константы разделяются запятыми.
<!--## Initialization-->
## Инициализация
<!--Since each enum is an instance of the enum class, they can be initialized-->
Так как константы являются экземплярами enum-класса, они могут быть инициализированы
``` kotlin
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF)
}
```
<!--## Anonymous Classes-->
## Анонимные классы
<!--Enum constants can also declare their own anonymous classes-->
Enum-константы также могут объявлять свои собственные анонимные классы
``` kotlin
enum class ProtocolState {
WAITING {
override fun signal() = TALKING
},
TALKING {
override fun signal() = WAITING
};
abstract fun signal(): ProtocolState
}
```
<!--with their corresponding methods, as well as overriding base methods. Note that if the enum class defines any
members, you need to separate the enum constant definitions from the member definitions with a semicolon, just like
in Java.-->
как с их собственными методами, так и с перегруженными методами базового класса. Следует заметить, что при объявлении
в enum-классе каких-либо членов, необходимо отделять их от списка констант точкой с запятой, так же как и в Java.
<!--## Working with Enum Constants-->
## Работа с enum-константами
<!--Just like in Java, enum classes in Kotlin have synthetic methods allowing to list
the defined enum constants and to get an enum constant by its name. The signatures
of these methods are as follows (assuming the name of the enum class is `EnumClass`):-->
Так же как и в Java, enum-классы в Kotlin имеют стандартные методы для вывода списка объявленных констант и для получения enum-константы по её имени.
Ниже приведены сигнатуры этих методов:
``` kotlin
EnumClass.valueOf(value: String): EnumClass
EnumClass.values(): Array<EnumClass>
```
<!--The `valueOf()` method throws an `IllegalArgumentException` if the specified name does
not match any of the enum constants defined in the class.-->
Метод `valueOf()` выбрасывает исключение `IllegalArgumentException`, если указанное имя не соответствует ни одной константе, объявленной в классе.
<!--Every enum constant has properties to obtain its name and position in the enum class declaration:-->
Каждая enum-константа имеет поля, в которых содержатся её имя и порядковый номер в enum-классе:
``` kotlin
val name: String
val ordinal: Int
```
<!--The enum constants also implement the [Comparable](/api/latest/jvm/stdlib/kotlin/-comparable/index.html) interface, with the natural order being the order in which they are defined in the enum class.-->
Также enum-константы реализуют интерфейс [Comparable](http://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-comparable/index.html). Порядок сортировки соответствует порядку объявления.
--------------------------------------------------------------------------------
<!--# Interfaces-->
# Интерфейсы
<!--Interfaces in Kotlin are very similar to Java 8. They can contain declarations of abstract methods, as well as method
implementations. What makes them different from abstract classes is that interfaces cannot store state. They can have
properties but these need to be abstract or to provide accessor implementations.-->
Интерфейсы в <b>Kotlin</b> очень похожи на интерфейсы в <b>Java 8</b>. Они могут содержать абстрактные методы, методы с реализацией. Главное отличие интерфейсов от абстрактных классов заключается в невозможности хранения переменных экземпляров. Они могут иметь свойства, но те должны быть либо абстрактными, либо предоставлять реализацию методов доступа.
<!--An interface is defined using the keyword *interface*{: .keyword }-->
Интерфейс определяется ключевым словом **interface**:
``` kotlin
interface MyInterface {
fun bar()
fun foo() {
// необязательное тело
}
}
```
<!--## Implementing Interfaces-->
## Реализация интерфейсов
<!--A class or object can implement one or more interfaces-->
Класс или объект могут реализовать любое количество интерфейсов:
``` kotlin
class Child : MyInterface {
override fun bar() {
// тело
}
}
```
<!--## Properties in Interfaces-->
## Свойства в интерфейсах
<!--You can declare properties in interfaces. A property declared in an interface can either be abstract, or it can provide
implementations for accessors. Properties declared in interfaces can't have backing fields, and therefore accessors
declared in interfaces can't reference them.-->
Вы можете объявлять свойства в интерфейсах. Свойство, объявленное в интерфейсе, может быть либо абстрактным, либо иметь свою реализацию методов доступа. Свойства в интерфейсах не могут иметь _backing fields_, соответственно, методы доступа к таким свойствам не могут обращаться к _backing fields_.
``` kotlin
interface MyInterface {
val prop: Int // абстрактное свойство
val propertyWithImplementation: String
get() = "foo"
fun foo() {
print(prop)
}
}
class Child : MyInterface {
override val prop: Int = 29
}
```