Permalink
Browse files

Update type-safe

Строки 246-254: переведены непереведённые строки.
  • Loading branch information...
Temon137 committed Jun 20, 2017
1 parent 0b2d4ce commit 5bbfb94d5718b88e3882935e31fe01d80b1a3fb5
Showing with 26 additions and 18 deletions.
  1. +26 −18 type-safe-builders.md
View
@@ -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),
[describing 3D scenes](http://www.artima.com/weblogs/viewpost.jsp?thread=296081) and more...-->
Идея строителей ([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) и многого другого...
<!--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.-->
В отличае от Groovy, Kotlin проверяет типы строителей, что делает их более приятными в использовании в большинстве юзкейсов.
В отличие от Groovy, Kotlin проверяет типы строителей, что делает их более приятными в использовании в большинстве юзкейсов.
<!--For the rest of the cases, Kotlin supports Dynamic types builders.-->
Для прочих случаев Kotlin поддерживает Динамически типизированные строители (Dynamic types builders).
@@ -40,8 +40,8 @@ fun result(args: Array<String>) =
h1 {+"XML кодирование с Kotlin"}
p {+"этот формат может быть использован как альтернатва XML"}
// элемент с аттрибутом и текстовым содержанием
a(href = "http://kotlinlang.org") {+"Kotlin"}
// элемент с атрибутом и текстовым содержанием
a(href = "http://kotlinlang.ru") {+"Kotlin"}
// смешанный контент
p {
@@ -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>`.
(See its declaration [below](#full-definition-of-the-comexamplehtml-package).) -->
Давайте рассмотрим механизм реализации типобезопасных строителей в Kotlin.
Прежде всего, нам нужно определить модель, которую мы собираемся строить. В данном случае, это HTML-тэги.
Прежде всего, нам нужно определить модель, которую мы собираемся строить. В данном случае это HTML-тэги.
Мы можем сделать это без труда с помощью нескольких классов.
К примеру, `HTML` — это класс, который описывает тэг `<html>`, т.е. он определяет потомков таких как `<head>` и `<body>`.
К примеру, `HTML` — это класс, который описывает тэг `<html>`, т.е. он определяет потомков, таких как `<head>` и `<body>`.
(См. его объявление [ниже](#full-definition-of-the-comexamplehtml-package).)
<!--Now, let's recall why we can say something like this in the code:-->
@@ -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,
and we can call members of that instance inside the function.
The receiver can be accessed through the *this*{: .keyword } keyword:-->
Эта функция принимает один параметр-функциию под названием `init`.
Эта функция принимает один параметр-функцию под названием `init`.
Тип этой функции: `HTML.() -> Unit`_функциональный тип с объектом-приёмником_.
Это значит, что нам нужно передать экземпляр класса `HTML` (_приёмник_) в функцию,
и мы сможем обращаться к членам объекта в теле этой функции. Обращение происходит через
ключевое слово <b class="keyword">this</b>.
ключевое слово <b class="keyword">this</b>:
``` kotlin
html {
@@ -126,7 +126,7 @@ html {
(`head` и `body` — члены класса `HTML`)
<!--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
html {
@@ -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`:-->
На самом деле, эти две функции делают одно и тоже, поэтому мы можем использовать обощённую версию, `initTag`:
На самом деле эти две функции делают одно и тоже, поэтому мы можем использовать обобщённую версию, `initTag`:
``` kotlin
protected fun <T : Element> initTag(tag: T, init: T.() -> Unit): T {
@@ -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 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`):-->
Итак, мы просто добавляем строку в тела тэга, приписав `+` перед текстом, что ведёт к вызову префиксной операции `unaryPlus()`.
Это операция определена с помощью (функции-расширения)[extensions.html] `unaryPlus()`,
Итак, мы просто добавляем строку в тело тэга, приписав `+` перед текстом, что ведёт к вызову префиксной операции `unaryPlus()`.
Эта операция определена с помощью [функции-расширения](extensions.html) `unaryPlus()`,
которая является членом абстрактного класса `TagWithText` (родителя `Title`).
``` kotlin
@@ -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`: -->
При использовании [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
html {
@@ -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.-->
В этом примере должны быть доступны только члены ближайшего неявного приёмника `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.
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
@DslMarker
annotation class HtmlTagMarker
```
<!--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`.
It's enough to annotate only the superclass with `@HtmlTagMarker` and after that the Kotlin compiler will treat all the inherited classes as annotated:-->
@@ -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: -->
После добавления этой аннотации, компилятор Kotlin знает какие неявные приёмники являются частью того же DSL и разрешает обращаться только к членам ближайших приёмников:
После добавления этой аннотации, компилятор Kotlin знает, какие неявные приёмники являются частью того же DSL, и разрешает обращаться только к членам ближайших приёмников:
``` kotlin
html {
@@ -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).
Note that the `@DslMarker` annotation is available only since Kotlin 1.1.-->
Перед вами содержание пакета `com.example.html` (представлены только элементы, использованные в примере выше).
Он строит HTML дерево и активно использует [расширения](extensions.html) и [лямбды с приёмниками](lambdas.html#function-literals-with-receiver).
_Примечание: Аннотация @DslMarker доступна в Kotlin начиная с версии 1.1_
<a name='declarations'></a>
``` kotlin

0 comments on commit 5bbfb94

Please sign in to comment.