Skip to content

Commit

Permalink
Update type-safe
Browse files Browse the repository at this point in the history
Строки 246-254: переведены непереведённые строки.
  • Loading branch information
Temon137 authored and Temon137 committed Jun 20, 2017
1 parent 0b2d4ce commit 5bbfb94
Showing 1 changed file with 26 additions and 18 deletions.
44 changes: 26 additions & 18 deletions type-safe-builders.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ Builders allow for defining data in a semi-declarative way. Builders are good fo
[laying out UI components](http://www.groovy-lang.org/swing.html), [laying out UI components](http://www.groovy-lang.org/swing.html),
[describing 3D scenes](http://www.artima.com/weblogs/viewpost.jsp?thread=296081) and more...--> [describing 3D scenes](http://www.artima.com/weblogs/viewpost.jsp?thread=296081) and more...-->
Идея строителей ([builders](http://www.groovy-lang.org/dsls.html#_nodebuilder)) довольна популярна в сообществе *Groovy*. Идея строителей ([builders](http://www.groovy-lang.org/dsls.html#_nodebuilder)) довольна популярна в сообществе *Groovy*.
Строители позволяют объявлять данные в полу-декларативном виде. Строители хороши для [генерации XML](http://www.groovy-lang.org/processing-xml.html#_creating_xml), Строители позволяют объявлять данные в полудекларативном виде. Строители хороши для [генерации XML](http://www.groovy-lang.org/processing-xml.html#_creating_xml),
[вёрстки компонентов UI](http://www.groovy-lang.org/swing.html), [описания 3D сцен](http://www.artima.com/weblogs/viewpost.jsp?thread=296081) и многого другого... [вёрстки компонентов UI](http://www.groovy-lang.org/swing.html), [описания 3D сцен](http://www.artima.com/weblogs/viewpost.jsp?thread=296081) и многого другого...


<!--For many use cases, Kotlin allows to *type-check* builders, which makes them even more attractive than the <!--For many use cases, Kotlin allows to *type-check* builders, which makes them even more attractive than the
dynamically-typed implementation made in Groovy itself.--> dynamically-typed implementation made in Groovy itself.-->
В отличае от Groovy, Kotlin проверяет типы строителей, что делает их более приятными в использовании в большинстве юзкейсов. В отличие от Groovy, Kotlin проверяет типы строителей, что делает их более приятными в использовании в большинстве юзкейсов.


<!--For the rest of the cases, Kotlin supports Dynamic types builders.--> <!--For the rest of the cases, Kotlin supports Dynamic types builders.-->
Для прочих случаев Kotlin поддерживает Динамически типизированные строители (Dynamic types builders). Для прочих случаев Kotlin поддерживает Динамически типизированные строители (Dynamic types builders).
Expand All @@ -40,8 +40,8 @@ fun result(args: Array<String>) =
h1 {+"XML кодирование с Kotlin"} h1 {+"XML кодирование с Kotlin"}
p {+"этот формат может быть использован как альтернатва XML"} p {+"этот формат может быть использован как альтернатва XML"}


// элемент с аттрибутом и текстовым содержанием // элемент с атрибутом и текстовым содержанием
a(href = "http://kotlinlang.org") {+"Kotlin"} a(href = "http://kotlinlang.ru") {+"Kotlin"}


// смешанный контент // смешанный контент
p { p {
Expand Down Expand Up @@ -77,9 +77,9 @@ It is easily done with a bunch of classes.
For example, `HTML` is a class that describes the `<html>` tag, i.e. it defines children like `<head>` and `<body>`. For example, `HTML` is a class that describes the `<html>` tag, i.e. it defines children like `<head>` and `<body>`.
(See its declaration [below](#full-definition-of-the-comexamplehtml-package).) --> (See its declaration [below](#full-definition-of-the-comexamplehtml-package).) -->
Давайте рассмотрим механизм реализации типобезопасных строителей в Kotlin. Давайте рассмотрим механизм реализации типобезопасных строителей в Kotlin.
Прежде всего, нам нужно определить модель, которую мы собираемся строить. В данном случае, это HTML-тэги. Прежде всего, нам нужно определить модель, которую мы собираемся строить. В данном случае это HTML-тэги.
Мы можем сделать это без труда с помощью нескольких классов. Мы можем сделать это без труда с помощью нескольких классов.
К примеру, `HTML` — это класс, который описывает тэг `<html>`, т.е. он определяет потомков таких как `<head>` и `<body>`. К примеру, `HTML` — это класс, который описывает тэг `<html>`, т.е. он определяет потомков, таких как `<head>` и `<body>`.
(См. его объявление [ниже](#full-definition-of-the-comexamplehtml-package).) (См. его объявление [ниже](#full-definition-of-the-comexamplehtml-package).)


<!--Now, let's recall why we can say something like this in the code:--> <!--Now, let's recall why we can say something like this in the code:-->
Expand Down Expand Up @@ -109,11 +109,11 @@ The type of the function is `HTML.() -> Unit`, which is a _function type with re
This means that we need to pass an instance of type `HTML` (a _receiver_) to the function, This means that we need to pass an instance of type `HTML` (a _receiver_) to the function,
and we can call members of that instance inside the function. and we can call members of that instance inside the function.
The receiver can be accessed through the *this*{: .keyword } keyword:--> The receiver can be accessed through the *this*{: .keyword } keyword:-->
Эта функция принимает один параметр-функциию под названием `init`. Эта функция принимает один параметр-функцию под названием `init`.
Тип этой функции: `HTML.() -> Unit`_функциональный тип с объектом-приёмником_. Тип этой функции: `HTML.() -> Unit`_функциональный тип с объектом-приёмником_.
Это значит, что нам нужно передать экземпляр класса `HTML` (_приёмник_) в функцию, Это значит, что нам нужно передать экземпляр класса `HTML` (_приёмник_) в функцию,
и мы сможем обращаться к членам объекта в теле этой функции. Обращение происходит через и мы сможем обращаться к членам объекта в теле этой функции. Обращение происходит через
ключевое слово <b class="keyword">this</b>. ключевое слово <b class="keyword">this</b>:


``` kotlin ``` kotlin
html { html {
Expand All @@ -126,7 +126,7 @@ html {
(`head` и `body` — члены класса `HTML`) (`head` и `body` — члены класса `HTML`)


<!--Now, *this*{: .keyword } can be omitted, as usual, and we get something that looks very much like a builder already:--> <!--Now, *this*{: .keyword } can be omitted, as usual, and we get something that looks very much like a builder already:-->
Теперь, <b class="keyword">this</b> может быть опущено, и мы получим что-то, что уже очень похоже на строителя: Теперь <b class="keyword">this</b> может быть опущено, и мы получим что-то, что уже очень похоже на строителя:


``` kotlin ``` kotlin
html { html {
Expand Down Expand Up @@ -166,7 +166,7 @@ fun body(init: Body.() -> Unit) : Body {
``` ```


<!--Actually these two functions do just the same thing, so we can have a generic version, `initTag`:--> <!--Actually these two functions do just the same thing, so we can have a generic version, `initTag`:-->
На самом деле, эти две функции делают одно и тоже, поэтому мы можем использовать обощённую версию, `initTag`: На самом деле эти две функции делают одно и тоже, поэтому мы можем использовать обобщённую версию, `initTag`:


``` kotlin ``` kotlin
protected fun <T : Element> initTag(tag: T, init: T.() -> Unit): T { protected fun <T : Element> initTag(tag: T, init: T.() -> Unit): T {
Expand Down Expand Up @@ -204,8 +204,8 @@ html {
<!--So basically, we just put a string inside a tag body, but there is this little `+` in front of it, <!--So basically, we just put a string inside a tag body, but there is this little `+` in front of it,
so it is a function call that invokes a prefix `unaryPlus()` operation. so it is a function call that invokes a prefix `unaryPlus()` operation.
That operation is actually defined by an extension function `unaryPlus()` that is a member of the `TagWithText` abstract class (a parent of `Title`):--> That operation is actually defined by an extension function `unaryPlus()` that is a member of the `TagWithText` abstract class (a parent of `Title`):-->
Итак, мы просто добавляем строку в тела тэга, приписав `+` перед текстом, что ведёт к вызову префиксной операции `unaryPlus()`. Итак, мы просто добавляем строку в тело тэга, приписав `+` перед текстом, что ведёт к вызову префиксной операции `unaryPlus()`.
Это операция определена с помощью (функции-расширения)[extensions.html] `unaryPlus()`, Эта операция определена с помощью [функции-расширения](extensions.html) `unaryPlus()`,
которая является членом абстрактного класса `TagWithText` (родителя `Title`). которая является членом абстрактного класса `TagWithText` (родителя `Title`).


``` kotlin ``` kotlin
Expand All @@ -229,7 +229,7 @@ In the last section you can read through the full definition of this package.-->
We can call methods of every available implicit receiver inside a lambda and therefore get an inconsistent result, like the tag `head` inside another `head`: --> We can call methods of every available implicit receiver inside a lambda and therefore get an inconsistent result, like the tag `head` inside another `head`: -->
При использовании [DSL](https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B5%D0%B4%D0%BC%D0%B5%D1%82%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9_%D1%8F%D0%B7%D1%8B%D0%BA) При использовании [DSL](https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B5%D0%B4%D0%BC%D0%B5%D1%82%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9_%D1%8F%D0%B7%D1%8B%D0%BA)
может возникнуть проблема, когда слишком много функций могут быть вызваны в определённом контексте. может возникнуть проблема, когда слишком много функций могут быть вызваны в определённом контексте.
Мы можем вызывать методы каждого неявного приёмника внутри лямбды и, из-за этого, может возникать противоречивый результат, как, например, тэг `head` внутри другого тэга `head`: Мы можем вызывать методы каждого неявного приёмника внутри лямбды, и из-за этого может возникать противоречивый результат, как, например, тэг `head` внутри другого тэга `head`:


``` kotlin ``` kotlin
html { html {
Expand All @@ -241,20 +241,25 @@ html {
``` ```


<!--In this example only members of the nearest implicit receiver `this@head` must be available; `head()` is a member of the outer receiver `this@html`, so it must be illegal to call it.--> <!--In this example only members of the nearest implicit receiver `this@head` must be available; `head()` is a member of the outer receiver `this@html`, so it must be illegal to call it.-->
В этом примере должны быть доступны только члены ближайшего неявного приёмника `this@head`; `head()` является членом другого приёмника — `this@html`, поэтому его вызов в другом контексте должен быть запрещён В этом примере должны быть доступны только члены ближайшего неявного приёмника `this@head`; `head()` является членом другого приёмника — `this@html`, поэтому его вызов в другом контексте должен быть запрещён.


To address this problem, in Kotlin 1.1 a special mechanism to control receiver scope was introduced. <!--To address this problem, in Kotlin 1.1 a special mechanism to control receiver scope was introduced.
To make the compiler start controlling scopes we only have to annotate the types of all receivers used in the DSL with the same marker annotation. To make the compiler start controlling scopes we only have to annotate the types of all receivers used in the DSL with the same marker annotation.
For instance, for HTML Builders we declare an annotation `@HTMLTagMarker`: For instance, for HTML Builders we declare an annotation `@HTMLTagMarker`:-->

Для решения этой проблемы в Kotlin 1.1 был введен специальный механизм для управления областью приёмника.

Чтобы заставить компилятор запускать контрольные области, нам нужно только аннотировать типы всех получателей, используемых в DSL, той же маркерной аннотацией.
Например, для HTML Builders мы объявляем аннотацию `@HTMLTagMarker`:


``` kotlin ``` kotlin
@DslMarker @DslMarker
annotation class HtmlTagMarker annotation class HtmlTagMarker
``` ```


<!--An annotation class is called a DSL marker if it is annotated with the `@DslMarker` annotation.--> <!--An annotation class is called a DSL marker if it is annotated with the `@DslMarker` annotation.-->
Аннотированный класс называется DSL-маркер если он помечен аннотацией `@DslMarker`. Аннотированный класс называется DSL-маркером, если он помечен аннотацией `@DslMarker`.


<!--In our DSL all the tag classes extend the same superclass `Tag`. <!--In our DSL all the tag classes extend the same superclass `Tag`.
It's enough to annotate only the superclass with `@HtmlTagMarker` and after that the Kotlin compiler will treat all the inherited classes as annotated:--> It's enough to annotate only the superclass with `@HtmlTagMarker` and after that the Kotlin compiler will treat all the inherited classes as annotated:-->
Expand All @@ -274,7 +279,7 @@ class Head() : Tag("head") { ... }
``` ```


<!--After we've added this annotation, the Kotlin compiler knows which implicit receivers are part of the same DSL and allows to call members of the nearest receivers only: --> <!--After we've added this annotation, the Kotlin compiler knows which implicit receivers are part of the same DSL and allows to call members of the nearest receivers only: -->
После добавления этой аннотации, компилятор Kotlin знает какие неявные приёмники являются частью того же DSL и разрешает обращаться только к членам ближайших приёмников: После добавления этой аннотации, компилятор Kotlin знает, какие неявные приёмники являются частью того же DSL, и разрешает обращаться только к членам ближайших приёмников:


``` kotlin ``` kotlin
html { html {
Expand Down Expand Up @@ -306,9 +311,12 @@ It builds an HTML tree. It makes heavy use of [extension functions](extensions.h
[lambdas with receiver](lambdas.html#function-literals-with-receiver). [lambdas with receiver](lambdas.html#function-literals-with-receiver).
Note that the `@DslMarker` annotation is available only since Kotlin 1.1.--> Note that the `@DslMarker` annotation is available only since Kotlin 1.1.-->

Перед вами содержание пакета `com.example.html` (представлены только элементы, использованные в примере выше). Перед вами содержание пакета `com.example.html` (представлены только элементы, использованные в примере выше).
Он строит HTML дерево и активно использует [расширения](extensions.html) и [лямбды с приёмниками](lambdas.html#function-literals-with-receiver). Он строит HTML дерево и активно использует [расширения](extensions.html) и [лямбды с приёмниками](lambdas.html#function-literals-with-receiver).


_Примечание: Аннотация @DslMarker доступна в Kotlin начиная с версии 1.1_

<a name='declarations'></a> <a name='declarations'></a>


``` kotlin ``` kotlin
Expand Down

0 comments on commit 5bbfb94

Please sign in to comment.