mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-27 01:03:19 +03:00
commit
92fe4d2579
@ -416,3 +416,6 @@ Clojuredocs.org has documentation with examples for most core functions:
|
||||
|
||||
Clojure-doc.org (yes, really) has a number of getting started articles:
|
||||
[http://clojure-doc.org/](http://clojure-doc.org/)
|
||||
|
||||
Clojure for the Brave and True has a great introduction to Clojure and a free online version:
|
||||
[https://www.braveclojure.com/clojure-for-the-brave-and-true/](https://www.braveclojure.com/clojure-for-the-brave-and-true/)
|
||||
|
@ -8,11 +8,11 @@ translators:
|
||||
lang: de-de
|
||||
---
|
||||
|
||||
Nix ist eine simple funktionale Programmiersprache, die für den
|
||||
Nix ist eine simple funktionale Programmiersprache, die für den
|
||||
[Nix package manager](https://nixos.org/nix/) und
|
||||
[NixOS](https://nixos.org/) entwickelt wurde.
|
||||
|
||||
Du kannst Nix Ausdrücke evaluieren mithilfe von
|
||||
Du kannst Nix Ausdrücke evaluieren mithilfe von
|
||||
[nix-instantiate](https://nixos.org/nix/manual/#sec-nix-instantiate)
|
||||
oder [`nix-repl`](https://github.com/edolstra/nix-repl).
|
||||
|
||||
@ -24,7 +24,7 @@ with builtins; [
|
||||
|
||||
# Inline Kommentare sehen so aus.
|
||||
|
||||
/* Multizeilen Kommentare
|
||||
/* Multizeilen Kommentare
|
||||
sehen so aus. */
|
||||
|
||||
|
||||
@ -61,7 +61,7 @@ with builtins; [
|
||||
"String Literale sind in Anführungszeichen."
|
||||
|
||||
"
|
||||
String Literale können mehrere
|
||||
String Literale können mehrere
|
||||
Zeilen umspannen.
|
||||
"
|
||||
|
||||
@ -95,7 +95,7 @@ with builtins; [
|
||||
tutorials/learn.nix
|
||||
#=> /the-base-path/tutorials/learn.nix
|
||||
|
||||
# Ein Pfad muss mindestens einen Schrägstrich enthalten. Ein Pfad für eine
|
||||
# Ein Pfad muss mindestens einen Schrägstrich enthalten. Ein Pfad für eine
|
||||
# Datei im selben Verzeichnis benötigt ein ./ Präfix.
|
||||
./learn.nix
|
||||
#=> /the-base-path/learn.nix
|
||||
@ -238,7 +238,7 @@ with builtins; [
|
||||
#=> { d = 2; e = 3; }
|
||||
|
||||
# Die Nachkommen eines Attributs können in diesem Feld nicht zugeordnet werden, wenn
|
||||
# das Attribut selbst nicht zugewiesen wurde.
|
||||
# das Attribut selbst nicht zugewiesen wurde.
|
||||
{
|
||||
a = { b = 1; };
|
||||
a.c = 2;
|
||||
@ -261,9 +261,9 @@ with builtins; [
|
||||
#=> 7
|
||||
|
||||
# Die erste Linie diese Tutorials startet mit "with builtins;",
|
||||
# weil builtins ein Set mit allen eingebauten
|
||||
# weil builtins ein Set mit allen eingebauten
|
||||
# Funktionen (length, head, tail, filter, etc.) umfasst.
|
||||
# Das erspart uns beispielsweise "builtins.length" zu schreiben,
|
||||
# Das erspart uns beispielsweise "builtins.length" zu schreiben,
|
||||
# anstatt nur "length".
|
||||
|
||||
|
||||
@ -305,7 +305,7 @@ with builtins; [
|
||||
(tryEval (abort "foo"))
|
||||
#=> error: evaluation aborted with the following error message: ‘foo’
|
||||
|
||||
# `assert` evaluiert zu dem gegebenen Wert, wenn die Bedingung wahr ist, sonst
|
||||
# `assert` evaluiert zu dem gegebenen Wert, wenn die Bedingung wahr ist, sonst
|
||||
# löst es eine abfangbare Exception aus.
|
||||
(assert 1 < 2; 42)
|
||||
#=> 42
|
||||
@ -319,7 +319,7 @@ with builtins; [
|
||||
#=========================================
|
||||
|
||||
# Da die Wiederholbarkeit von Builds für den Nix Packetmanager entscheidend ist,
|
||||
# werden in der Nix Sprache reine funktionale Elemente betont. Es gibt aber ein paar
|
||||
# werden in der Nix Sprache reine funktionale Elemente betont. Es gibt aber ein paar
|
||||
# unreine Elemente.
|
||||
# Du kannst auf Umgebungsvariablen verweisen.
|
||||
(getEnv "HOME")
|
||||
@ -355,4 +355,4 @@ with builtins; [
|
||||
(https://medium.com/@MrJamesFisher/nix-by-example-a0063a1a4c55)
|
||||
|
||||
* [Susan Potter - Nix Cookbook - Nix By Example]
|
||||
(http://funops.co/nix-cookbook/nix-by-example/)
|
||||
(https://ops.functionalalgebra.com/nix-by-example/)
|
||||
|
@ -382,3 +382,6 @@ Clojuredocs.org tem documentação com exemplos para quase todas as funções pr
|
||||
|
||||
Clojure-doc.org tem um bom número de artigos para iniciantes:
|
||||
[http://clojure-doc.org/](http://clojure-doc.org/)
|
||||
|
||||
Clojure for the Brave and True é um livro de introdução ao Clojure e possui uma versão gratuita online:
|
||||
[https://www.braveclojure.com/clojure-for-the-brave-and-true/](https://www.braveclojure.com/clojure-for-the-brave-and-true/)
|
||||
|
@ -4,6 +4,7 @@ contributors:
|
||||
- ["Dan Turkel", "http://danturkel.com/"]
|
||||
translators:
|
||||
- ["Miguel Araújo", "https://github.com/miguelarauj1o"]
|
||||
- ["Monique Baptista", "https://github.com/bfmonique"]
|
||||
lang: pt-br
|
||||
filename: learnmarkdown-pt.md
|
||||
---
|
||||
@ -15,19 +16,19 @@ Dê-me feedback tanto quanto você quiser! / Sinta-se livre para a garfar (fork)
|
||||
puxar o projeto (pull request)
|
||||
|
||||
```md
|
||||
<!-- Markdown é um superconjunto do HTML, de modo que qualquer arvquivo HTML é
|
||||
um arquivo Markdown válido, isso significa que nós podemos usar elementos HTML
|
||||
<!-- Markdown é um superconjunto do HTML, de modo que qualquer arquivo HTML é
|
||||
um arquivo Markdown válido. Isso significa que nós podemos usar elementos HTML
|
||||
em Markdown, como o elemento de comentário, e eles não serão afetados pelo analisador
|
||||
de remarcação. No entanto, se você criar um elemento HTML em seu arquivo Markdown, você
|
||||
não pode usar sintaxe remarcação dentro desse conteúdo do elemento.-->
|
||||
não pode usar sintaxe de remarcação dentro desse conteúdo do elemento.-->
|
||||
|
||||
<!--Markdown também varia de implementação de um analisador para uma próxima.
|
||||
<!--A maneira como o Markdown é analisado varia de software para software.
|
||||
Este guia vai tentar esclarecer quando as características são universais, ou quando eles são
|
||||
específico para um determinado parser -->
|
||||
específico para um determinado interpretador -->
|
||||
|
||||
<!-- Cabeçalhos -->
|
||||
<!-- Você pode criar elementos HTML <h1> até <h6> facilmente antecedendo o texto
|
||||
que deseja estar nesse elemento por um número de hashes (#) -->
|
||||
que deseja estar nesse elemento por um número de cerquilhas (#) -->
|
||||
# Isto é um cabeçalho <h1>
|
||||
## Isto é um cabeçalho <h2>
|
||||
### Isto é um cabeçalho <h3>
|
||||
@ -65,7 +66,7 @@ uma ou múltiplas linhas em branco. -->
|
||||
|
||||
Este é um parágrafo. Eu estou digitando em um parágrafo, não é legal?
|
||||
|
||||
Agora, eu estou no parágrado 2.
|
||||
Agora, eu estou no parágrafo 2.
|
||||
... Ainda continuo no parágrafo 2! :)
|
||||
|
||||
Eu estou no parágrafo três.
|
||||
@ -111,7 +112,7 @@ ou
|
||||
|
||||
1. Item um
|
||||
2. Item dois
|
||||
3. Tem três
|
||||
3. Item três
|
||||
|
||||
<!-- Você não tem poder para rotular os itens corretamente e a remarcação será ainda
|
||||
tornar os números em ordem, mas isso pode não ser uma boa idéia -->
|
||||
|
@ -7,15 +7,16 @@ contributors:
|
||||
- ["Zachary Ferguson", "http://github.com/zfergus2"]
|
||||
translators:
|
||||
- ["Paulo Henrique Rodrigues Pinheiro", "http://www.sysincloud.it"]
|
||||
- ["Monique Baptista", "https://github.com/bfmonique"]
|
||||
lang: pt-br
|
||||
filename: learnpython3-pt.py
|
||||
---
|
||||
|
||||
Python foi criado por Guido Van Rossum nos anos 1990. Ele é atualmente uma
|
||||
das mais populares linguagens em existência. Eu fiquei morrendo de amor
|
||||
pelo Python por sua clareza sintática. É praticamente pseudocódigo executável.
|
||||
Python foi criada por Guido Van Rossum nos anos 1990. Ela é atualmente uma
|
||||
das linguagens mais populares existentes. Eu me apaixonei por
|
||||
Python por sua clareza sintática. É praticamente pseudocódigo executável.
|
||||
|
||||
Suas opiniões são grandemente apreciadas. Você pode encontrar-me em
|
||||
Opniões são muito bem vindas. Você pode encontrar-me em
|
||||
[@louiedinh](http://twitter.com/louiedinh) ou louiedinh [em]
|
||||
[serviço de e-mail do google].
|
||||
|
||||
@ -44,7 +45,7 @@ aprender o velho Python 2.7.
|
||||
8 - 1 # => 7
|
||||
10 * 2 # => 20
|
||||
|
||||
# Números inteiros por padrão, exceto na divisão, que retorna número
|
||||
# Números são inteiros por padrão, exceto na divisão, que retorna número
|
||||
# de ponto flutuante (float).
|
||||
35 / 5 # => 7.0
|
||||
|
||||
@ -64,7 +65,7 @@ aprender o velho Python 2.7.
|
||||
# Exponenciação (x**y, x elevado à potência y)
|
||||
2**4 # => 16
|
||||
|
||||
# Determine a precedência usando parêntesis
|
||||
# Determine a precedência usando parênteses
|
||||
(1 + 3) * 2 # => 8
|
||||
|
||||
# Valores lógicos são primitivos (Atenção à primeira letra maiúscula)
|
||||
@ -105,9 +106,8 @@ False or True # => True
|
||||
1 < 2 < 3 # => True
|
||||
2 < 3 < 2 # => False
|
||||
|
||||
# (operador 'is' e operador '==') is verifica se duas variáveis
|
||||
# referenciam um mesmo objeto, mas == verifica se as variáveis
|
||||
# apontam para o mesmo valor.
|
||||
# 'is' verifica se duas variáveis representam o mesmo endereço
|
||||
# na memória; '==' verifica se duas variáveis têm o mesmo valor
|
||||
a = [1, 2, 3, 4] # Referência a uma nova lista, [1, 2, 3, 4]
|
||||
b = a # b referencia o que está referenciado por a
|
||||
b is a # => True, a e b referenciam o mesmo objeto
|
||||
@ -174,7 +174,7 @@ input_string_var = input("Digite alguma coisa: ") # Retorna o que foi digitado e
|
||||
# Observação: Em versões antigas do Python, o método input() era chamado raw_input()
|
||||
|
||||
# Não é necessário declarar variáveis antes de iniciá-las
|
||||
# È uma convenção usar letras_minúsculas_com_sublinhados
|
||||
# É uma convenção usar letras_minúsculas_com_sublinhados
|
||||
alguma_variavel = 5
|
||||
alguma_variavel # => 5
|
||||
|
||||
@ -182,31 +182,31 @@ alguma_variavel # => 5
|
||||
# Veja Controle de Fluxo para aprender mais sobre tratamento de exceções.
|
||||
alguma_variavel_nao_inicializada # Gera a exceção NameError
|
||||
|
||||
# Listas armazenam sequencias
|
||||
# Listas armazenam sequências
|
||||
li = []
|
||||
# Você pode iniciar com uma lista com alguns valores
|
||||
# Você pode iniciar uma lista com valores
|
||||
outra_li = [4, 5, 6]
|
||||
|
||||
# Adicionar conteúdo ao fim da lista com append
|
||||
# Adicione conteúdo ao fim da lista com append
|
||||
li.append(1) # li agora é [1]
|
||||
li.append(2) # li agora é [1, 2]
|
||||
li.append(4) # li agora é [1, 2, 4]
|
||||
li.append(3) # li agora é [1, 2, 4, 3]
|
||||
# Remover do final da lista com pop
|
||||
# Remova do final da lista com pop
|
||||
li.pop() # => 3 e agora li é [1, 2, 4]
|
||||
# Vamos colocá-lo lá novamente!
|
||||
li.append(3) # li agora é [1, 2, 4, 3] novamente.
|
||||
|
||||
# Acessar uma lista da mesma forma que você faz com um array
|
||||
# Acesse uma lista da mesma forma que você faz com um array
|
||||
li[0] # => 1
|
||||
# Acessa o último elemento
|
||||
# Acessando o último elemento
|
||||
li[-1] # => 3
|
||||
|
||||
# Acessando além dos limites gera um IndexError
|
||||
# Acessar além dos limites gera um IndexError
|
||||
li[4] # Gera o IndexError
|
||||
|
||||
# Você pode acessar vários elementos com a sintaxe de limites
|
||||
# (É um limite fechado, aberto pra você que gosta de matemática.)
|
||||
# Inclusivo para o primeiro termo, exclusivo para o segundo
|
||||
li[1:3] # => [2, 4]
|
||||
# Omitindo o final
|
||||
li[2:] # => [4, 3]
|
||||
|
@ -550,8 +550,14 @@ next(our_iterator) # => "three"
|
||||
# After the iterator has returned all of its data, it raises a StopIteration exception
|
||||
next(our_iterator) # Raises StopIteration
|
||||
|
||||
# You can grab all the elements of an iterator by calling list() on it.
|
||||
list(filled_dict.keys()) # => Returns ["one", "two", "three"]
|
||||
# We can also loop over it, in fact, "for" does this implicitly!
|
||||
our_iterator = iter(our_iterable)
|
||||
for i in our_iterator:
|
||||
print(i) # Prints one, two, three
|
||||
|
||||
# You can grab all the elements of an iterable or iterator by calling list() on it.
|
||||
list(our_iterable) # => Returns ["one", "two", "three"]
|
||||
list(our_iterator) # => Returns [] because state is saved
|
||||
|
||||
|
||||
####################################################
|
||||
|
@ -91,7 +91,7 @@ let multiLineString = """
|
||||
This is a multi-line string.
|
||||
It's called that because it takes up multiple lines (wow!)
|
||||
Any indentation beyond the closing quotation marks is kept, the rest is discarded.
|
||||
You can include " or "" in multi-line strings because the delimeter is three "s.
|
||||
You can include " or "" in multi-line strings because the delimiter is three "s.
|
||||
"""
|
||||
|
||||
// Arrays
|
||||
@ -159,12 +159,12 @@ let `class` = "keyword"
|
||||
or contains nil (no value) to indicate that a value is missing.
|
||||
Nil is roughly equivalent to `null` in other languages.
|
||||
A question mark (?) after the type marks the value as optional of that type.
|
||||
|
||||
|
||||
If a type is not optional, it is guaranteed to have a value.
|
||||
|
||||
|
||||
Because Swift requires every property to have a type, even nil must be
|
||||
explicitly stored as an Optional value.
|
||||
|
||||
|
||||
Optional<T> is an enum, with the cases .none (nil) and .some(T) (the value)
|
||||
*/
|
||||
|
||||
@ -178,7 +178,7 @@ let someOptionalString4 = String?.none //nil
|
||||
To access the value of an optional that has a value, use the postfix
|
||||
operator !, which force-unwraps it. Force-unwrapping is like saying, "I
|
||||
know that this optional definitely has a value, please give it to me."
|
||||
|
||||
|
||||
Trying to use ! to access a non-existent optional value triggers a
|
||||
runtime error. Always make sure that an optional contains a non-nil
|
||||
value before using ! to force-unwrap its value.
|
||||
@ -194,7 +194,7 @@ if someOptionalString != nil {
|
||||
// Swift supports "optional chaining," which means that you can call functions
|
||||
// or get properties of optional values and they are optionals of the appropriate type.
|
||||
// You can even do this multiple times, hence the name "chaining."
|
||||
|
||||
|
||||
let empty = someOptionalString?.isEmpty // Bool?
|
||||
|
||||
// if-let structure -
|
||||
@ -370,7 +370,7 @@ func say(_ message: String) {
|
||||
}
|
||||
say("Hello")
|
||||
|
||||
// Default parameters can be ommitted when calling the function.
|
||||
// Default parameters can be omitted when calling the function.
|
||||
func printParameters(requiredParameter r: Int, optionalParameter o: Int = 10) {
|
||||
print("The required parameter was \(r) and the optional parameter was \(o)")
|
||||
}
|
||||
@ -443,7 +443,7 @@ func testGuard() {
|
||||
return // guard statements MUST exit the scope that they are in.
|
||||
// They generally use `return` or `throw`.
|
||||
}
|
||||
|
||||
|
||||
print("number is \(aNumber)")
|
||||
}
|
||||
testGuard()
|
||||
@ -564,7 +564,7 @@ enum Furniture {
|
||||
case desk(height: Int)
|
||||
// Associate with String and Int
|
||||
case chair(String, Int)
|
||||
|
||||
|
||||
func description() -> String {
|
||||
//either placement of let is acceptable
|
||||
switch self {
|
||||
@ -591,15 +591,15 @@ print(chair.description()) // "Chair of Foo with 40 cm"
|
||||
- Define initializers to set up their initial state
|
||||
- Be extended to expand their functionality beyond a default implementation
|
||||
- Conform to protocols to provide standard functionality of a certain kind
|
||||
|
||||
|
||||
Classes have additional capabilities that structures don't have:
|
||||
- Inheritance enables one class to inherit the characteristics of another.
|
||||
- Type casting enables you to check and interpret the type of a class instance at runtime.
|
||||
- Deinitializers enable an instance of a class to free up any resources it has assigned.
|
||||
- Reference counting allows more than one reference to a class instance.
|
||||
|
||||
|
||||
Unless you need to use a class for one of these reasons, use a struct.
|
||||
|
||||
|
||||
Structures are value types, while classes are reference types.
|
||||
*/
|
||||
|
||||
@ -607,7 +607,7 @@ print(chair.description()) // "Chair of Foo with 40 cm"
|
||||
|
||||
struct NamesTable {
|
||||
let names: [String]
|
||||
|
||||
|
||||
// Custom subscript
|
||||
subscript(index: Int) -> String {
|
||||
return names[index]
|
||||
@ -629,7 +629,7 @@ class Shape {
|
||||
|
||||
class Rect: Shape {
|
||||
var sideLength: Int = 1
|
||||
|
||||
|
||||
// Custom getter and setter property
|
||||
var perimeter: Int {
|
||||
get {
|
||||
@ -640,16 +640,16 @@ class Rect: Shape {
|
||||
sideLength = newValue / 4
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Computed properties must be declared as `var`, you know, cause' they can change
|
||||
var smallestSideLength: Int {
|
||||
return self.sideLength - 1
|
||||
}
|
||||
|
||||
|
||||
// Lazily load a property
|
||||
// subShape remains nil (uninitialized) until getter called
|
||||
lazy var subShape = Rect(sideLength: 4)
|
||||
|
||||
|
||||
// If you don't need a custom getter and setter,
|
||||
// but still want to run code before and after getting or setting
|
||||
// a property, you can use `willSet` and `didSet`
|
||||
@ -659,19 +659,19 @@ class Rect: Shape {
|
||||
print(someIdentifier)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
init(sideLength: Int) {
|
||||
self.sideLength = sideLength
|
||||
// always super.init last when init custom properties
|
||||
super.init()
|
||||
}
|
||||
|
||||
|
||||
func shrink() {
|
||||
if sideLength > 0 {
|
||||
sideLength -= 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func getArea() -> Int {
|
||||
return sideLength * sideLength
|
||||
}
|
||||
@ -703,13 +703,13 @@ class Circle: Shape {
|
||||
override func getArea() -> Int {
|
||||
return 3 * radius * radius
|
||||
}
|
||||
|
||||
|
||||
// Place a question mark postfix after `init` is an optional init
|
||||
// which can return nil
|
||||
init?(radius: Int) {
|
||||
self.radius = radius
|
||||
super.init()
|
||||
|
||||
|
||||
if radius <= 0 {
|
||||
return nil
|
||||
}
|
||||
@ -813,7 +813,7 @@ for _ in 0..<10 {
|
||||
- Internal: Accessible and subclassible in the module it is declared in.
|
||||
- Fileprivate: Accessible and subclassible in the file it is declared in.
|
||||
- Private: Accessible and subclassible in the enclosing declaration (think inner classes/structs/enums)
|
||||
|
||||
|
||||
See more here: https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html
|
||||
*/
|
||||
|
||||
@ -878,11 +878,11 @@ extension Int {
|
||||
var doubled: Int {
|
||||
return self * 2
|
||||
}
|
||||
|
||||
|
||||
func multipliedBy(num: Int) -> Int {
|
||||
return num * self
|
||||
}
|
||||
|
||||
|
||||
mutating func multiplyBy(num: Int) {
|
||||
self *= num
|
||||
}
|
||||
@ -965,18 +965,18 @@ func fakeFetch(value: Int) throws -> String {
|
||||
guard 7 == value else {
|
||||
throw MyError.reallyBadValue(msg: "Some really bad value")
|
||||
}
|
||||
|
||||
|
||||
return "test"
|
||||
}
|
||||
|
||||
func testTryStuff() {
|
||||
// assumes there will be no error thrown, otherwise a runtime exception is raised
|
||||
let _ = try! fakeFetch(value: 7)
|
||||
|
||||
|
||||
// if an error is thrown, then it proceeds, but if the value is nil
|
||||
// it also wraps every return value in an optional, even if its already optional
|
||||
let _ = try? fakeFetch(value: 7)
|
||||
|
||||
|
||||
do {
|
||||
// normal try operation that provides error handling via `catch` block
|
||||
try fakeFetch(value: 1)
|
||||
|
@ -190,7 +190,7 @@ interface Person {
|
||||
}
|
||||
|
||||
var p1: Person = { name: "Tyrone", age: 42 };
|
||||
p1.age = 25; // Error แน่นอน เพราะ p1.x ถูกกำหนดเป็น read-only
|
||||
p1.age = 25; // Error แน่นอน เพราะ p1.age ถูกกำหนดเป็น read-only
|
||||
|
||||
var p2 = { name: "John", age: 60 }; // สังเกตว่า p2 ไม่ได้กำหนดเป็น Person
|
||||
var p3: Person = p2; // ทำได้ เป็น read-only alias ของ p2 และกำหนดเป็น Person
|
||||
|
@ -199,7 +199,7 @@ interface Person {
|
||||
}
|
||||
|
||||
var p1: Person = { name: "Tyrone", age: 42 };
|
||||
p1.age = 25; // Error, p1.x is read-only
|
||||
p1.age = 25; // Error, p1.age is read-only
|
||||
|
||||
var p2 = { name: "John", age: 60 };
|
||||
var p3: Person = p2; // Ok, read-only alias for p2
|
||||
|
254
uk-ua/cypher-ua.html.markdown
Normal file
254
uk-ua/cypher-ua.html.markdown
Normal file
@ -0,0 +1,254 @@
|
||||
---
|
||||
language: cypher
|
||||
filename: LearnCypher.cql
|
||||
contributors:
|
||||
- ["Théo Gauchoux", "https://github.com/TheoGauchoux"]
|
||||
translators:
|
||||
- ["AstiaSun", "https://github.com/AstiaSun"]
|
||||
lang: uk-ua
|
||||
---
|
||||
|
||||
Cypher - це мова запитів Neo4j для спрощення роботи з графами. Вона повторює синтаксис SQL та перемішує його з таким собі ascii стилем для відображення структури графа.
|
||||
Цей навчальний матеріал передбачає, що ви вже знайомі із концепцією графів, зобрема що таке вершини та зв'язки між ними.
|
||||
|
||||
[Деталі тут](https://neo4j.com/developer/cypher-query-language/)
|
||||
|
||||
|
||||
Вершини
|
||||
---
|
||||
|
||||
**Відображує запис у графі.**
|
||||
|
||||
`()`
|
||||
Таким чином у запиті позначається пуста *вершина*. Використовується зазвичай для того, щоб позначити, що вона є, проте це не так вже й важливо для запиту.
|
||||
|
||||
`(n)`
|
||||
Це вершина, яка має назву **n**, до неї можна повторно звертатись у запиті. Звернення до вершини **n** починається з нижнього підкреслення та використовує camelCase (верблюжий регіст).
|
||||
|
||||
`(p:Person)`
|
||||
Можна також додати *ярлик* до вершини, в данному випадку - **Person**. Це як тип / клас / категорія. Назва *ярлика* починається з великої літери та використовує верблюжу нотацію.
|
||||
|
||||
`(p:Person:Manager)`
|
||||
Вершина може мати кілька *ярликів*.
|
||||
|
||||
`(p:Person {name : 'Théo Gauchoux', age : 22})`
|
||||
Вершина також може мати різні *властивості*, в данному випадку - **name** та **age**. Також мають починатися з великої літери та використовувати верблюжу нотацію.
|
||||
|
||||
Наступні типи дозволяється використовувати у властивостях:
|
||||
|
||||
- Чиселиний
|
||||
- Булевий
|
||||
- Рядок
|
||||
- Списки попередніх примітивних типів
|
||||
|
||||
*Увага! В Cypher не існує типу, що відображає час. Замість нього можна використовувати рядок із визначеним шаблоном або чисельне відображення певної дати.*
|
||||
|
||||
`p.name`
|
||||
За допомогою крапки можна звернутись до властивості вершини.
|
||||
|
||||
|
||||
Зв'язки (або ребра)
|
||||
---
|
||||
|
||||
**Сполучають дві вершини**
|
||||
|
||||
`[:KNOWS]`
|
||||
Це *зв'язок* з *ярликом* **KNOWS**. Це такий же самий *ярлик* як і у вершини. Починається з великої літери та використовує ВЕРХНІЙ\_РЕГІСТР\_ІЗ\_ЗМІЇНОЮ\_НОТАЦІЄЮ.
|
||||
|
||||
`[k:KNOWS]`
|
||||
Це той же самий *зв'язок*, до якого можна звертатись через змінну **k**. Можна подалі використовувати у запиті, хоч це і не обов'язково.
|
||||
|
||||
`[k:KNOWS {since:2017}]`
|
||||
Той же *зв'язок*, але вже із *властивостями* (як у *вершини*), в данному випадку властивість - це **since**.
|
||||
|
||||
`[k:KNOWS*..4]`
|
||||
Це структурна інформація, яку використовують *шляхи*, які розглянуті нижче. В данному випадку, **\*..4** говорить: "Сумістити шаблон із зв'язком **k**, що повторюватиметься від одного до чотирьох разів."
|
||||
|
||||
|
||||
Шляхи
|
||||
---
|
||||
|
||||
**Спосіб поєднувати вершини та зв'язки.**
|
||||
|
||||
`(a:Person)-[:KNOWS]-(b:Person)`
|
||||
Шлях описує, що вершини **a** та **b** знають (knows) один одного.
|
||||
|
||||
`(a:Person)-[:MANAGES]->(b:Person)`
|
||||
Шлях може бути направленим. Цей описує, що **а** є менеджером **b**.
|
||||
|
||||
`(a:Person)-[:KNOWS]-(b:Person)-[:KNOWS]-(c:Person)`
|
||||
Можна створювати ланцюги зі зв'язків. Цей шлях описує друга друга (**a** знає **b**, який в свою чергу знає **c**).
|
||||
|
||||
`(a:Person)-[:MANAGES]->(b:Person)-[:MANAGES]->(c:Person)`
|
||||
Ланцюг, аналогічно, також може бути направленим. Шлях описує, що **a** - бос **b** і супер бос для **c**.
|
||||
|
||||
Шаблони, які часто використовуються (з документації Neo4j):
|
||||
|
||||
```
|
||||
// Друг-мого-друга
|
||||
(user)-[:KNOWS]-(friend)-[:KNOWS]-(foaf)
|
||||
|
||||
// Найкоротший шлях
|
||||
path = shortestPath( (user)-[:KNOWS*..5]-(other) )
|
||||
|
||||
// Спільна фільтрація
|
||||
(user)-[:PURCHASED]->(product)<-[:PURCHASED]-()-[:PURCHASED]->(otherProduct)
|
||||
|
||||
// Навігація по дереву
|
||||
(root)<-[:PARENT*]-(leaf:Category)-[:ITEM]->(data:Product)
|
||||
|
||||
```
|
||||
|
||||
|
||||
Запити на створення
|
||||
---
|
||||
|
||||
Створити нову вершину:
|
||||
```
|
||||
CREATE (a:Person {name:"Théo Gauchoux"})
|
||||
RETURN a
|
||||
```
|
||||
*`RETURN` дозволяє повернути результат після виконання запиту. Можна повертати кілька значень, наприклад, `RETURN a, b`.*
|
||||
|
||||
Створити новий зв'язок (із двома вершинами):
|
||||
```
|
||||
CREATE (a:Person)-[k:KNOWS]-(b:Person)
|
||||
RETURN a,k,b
|
||||
```
|
||||
|
||||
Запити на знаходження
|
||||
---
|
||||
|
||||
Знайти всі вершини:
|
||||
```
|
||||
MATCH (n)
|
||||
RETURN n
|
||||
```
|
||||
|
||||
Знайти вершини за ярликом:
|
||||
```
|
||||
MATCH (a:Person)
|
||||
RETURN a
|
||||
```
|
||||
|
||||
Знайти вершини за ярликом та властивістю:
|
||||
```
|
||||
MATCH (a:Person {name:"Théo Gauchoux"})
|
||||
RETURN a
|
||||
```
|
||||
|
||||
Знайти вершини відповідно до зв'язків (ненаправлених):
|
||||
```
|
||||
MATCH (a)-[:KNOWS]-(b)
|
||||
RETURN a,b
|
||||
```
|
||||
|
||||
Знайти вершини відповідно до зв'язків (направлених):
|
||||
```
|
||||
MATCH (a)-[:MANAGES]->(b)
|
||||
RETURN a,b
|
||||
```
|
||||
|
||||
Знайти вершини за допомогою `WHERE`:
|
||||
```
|
||||
MATCH (p:Person {name:"Théo Gauchoux"})-[s:LIVES_IN]->(city:City)
|
||||
WHERE s.since = 2015
|
||||
RETURN p,state
|
||||
```
|
||||
|
||||
Можна використовувати вираз `MATCH WHERE` разом із операцією `CREATE`:
|
||||
```
|
||||
MATCH (a), (b)
|
||||
WHERE a.name = "Jacquie" AND b.name = "Michel"
|
||||
CREATE (a)-[:KNOWS]-(b)
|
||||
```
|
||||
|
||||
|
||||
Запити на оновлення
|
||||
---
|
||||
|
||||
Оновити окрему властивість вершини:
|
||||
```
|
||||
MATCH (p:Person)
|
||||
WHERE p.name = "Théo Gauchoux"
|
||||
SET p.age = 23
|
||||
```
|
||||
|
||||
Оновити всі властивості вершини:
|
||||
```
|
||||
MATCH (p:Person)
|
||||
WHERE p.name = "Théo Gauchoux"
|
||||
SET p = {name: "Michel", age: 23}
|
||||
```
|
||||
|
||||
Додати нову властивіcть до вершини:
|
||||
```
|
||||
MATCH (p:Person)
|
||||
WHERE p.name = "Théo Gauchoux"
|
||||
SET p + = {studies: "IT Engineering"}
|
||||
```
|
||||
|
||||
Повісити ярлик на вершину:
|
||||
```
|
||||
MATCH (p:Person)
|
||||
WHERE p.name = "Théo Gauchoux"
|
||||
SET p:Internship
|
||||
```
|
||||
|
||||
|
||||
Запити на видалення
|
||||
---
|
||||
|
||||
Видалити окрему вершину (пов'язані ребра повинні бути видалені перед цим):
|
||||
```
|
||||
MATCH (p:Person)-[relationship]-()
|
||||
WHERE p.name = "Théo Gauchoux"
|
||||
DELETE relationship, p
|
||||
```
|
||||
|
||||
Видалити властивість певної вершини:
|
||||
```
|
||||
MATCH (p:Person)
|
||||
WHERE p.name = "Théo Gauchoux"
|
||||
REMOVE p.age
|
||||
```
|
||||
|
||||
*Зверніть увагу, що ключове слово `REMOVE` це не те саме, що й `DELETE`!*
|
||||
|
||||
Видалити ярлик певної вершини:
|
||||
```
|
||||
MATCH (p:Person)
|
||||
WHERE p.name = "Théo Gauchoux"
|
||||
DELETE p:Person
|
||||
```
|
||||
|
||||
Видалити всю базу даних:
|
||||
```
|
||||
MATCH (n)
|
||||
OPTIONAL MATCH (n)-[r]-()
|
||||
DELETE n, r
|
||||
```
|
||||
|
||||
*Так, це `rm -rf /` на мові Cypher !*
|
||||
|
||||
|
||||
Інші корисні запити
|
||||
---
|
||||
|
||||
`PROFILE`
|
||||
Перед виконанням, показати план виконання запитів.
|
||||
|
||||
`COUNT(e)`
|
||||
Порахувати елементи (вершини та зв'язки), що відповідають **e**.
|
||||
|
||||
`LIMIT x`
|
||||
Обмежити результат до x перших результатів.
|
||||
|
||||
|
||||
Особливі підказки
|
||||
---
|
||||
|
||||
- У мові Cypher існують лише однорядкові коментарі, що позначаються двійним слешем : // Коментар
|
||||
- Можна виконати скрипт Cypher, збережений у файлі **.cql** прямо в Neo4j (прямо як імпорт). Проте, не можна мати мати кілька виразів в цьому файлі (розділених **;**).
|
||||
- Використовуйте командний рядок Neo4j для написання запитів Cypher, це легко і швидко.
|
||||
- Cypher планує бути стандартною мовою запитів для всіх графових баз даних (більш відома як **OpenCypher**).
|
464
uk-ua/kotlin-ua.html.markdown
Normal file
464
uk-ua/kotlin-ua.html.markdown
Normal file
@ -0,0 +1,464 @@
|
||||
---
|
||||
language: kotlin
|
||||
filename: LearnKotlin-uk.kt
|
||||
lang: uk-ua
|
||||
contributors:
|
||||
- ["S Webber", "https://github.com/s-webber"]
|
||||
translators:
|
||||
- ["AstiaSun", "https://github.com/AstiaSun"]
|
||||
---
|
||||
|
||||
Kotlin - це мова програмування зі статичною типізацією для JVM, Android та браузера.
|
||||
Вона має 100% сумісність із Java.
|
||||
|
||||
[Детальніше](https://kotlinlang.org/)
|
||||
|
||||
```kotlin
|
||||
// Однорядкові коментарі починаються з //
|
||||
/*
|
||||
Такий вигляд мають багаторядкові коментарі
|
||||
*/
|
||||
|
||||
// Ключове слово package працює так само, як і в Java.
|
||||
package com.learnxinyminutes.kotlin
|
||||
|
||||
/*
|
||||
Точкою входу для програм на Kotlin є функція під назвою main.
|
||||
Вона приймає масив із аргументів, що були передані через командний рядок.
|
||||
Починаючи з Kotlin 1.3, функція main може бути оголошена без параметрів взагалі.
|
||||
*/
|
||||
fun main(args: Array<String>) {
|
||||
/*
|
||||
Оголошення змінних відбувається за допомогою ключових слів var або val.
|
||||
Відмінність між ними полягає в тому, що значення змінних, оголошених через
|
||||
val, не можна змінювати. Водночас, змінній "var" можна переприсвоїти нове
|
||||
значення в подальшому.
|
||||
*/
|
||||
val fooVal = 10 // більше ми не можемо змінити значення fooVal на інше
|
||||
var fooVar = 10
|
||||
fooVar = 20 // fooVar може змінювати значення
|
||||
|
||||
/*
|
||||
В більшості випадків Kotlin може визначати, якого типу змінна, тому не
|
||||
потрібно щоразу точно вказувати її тип.
|
||||
Тип змінної вказується наступним чином:
|
||||
*/
|
||||
val foo: Int = 7
|
||||
|
||||
/*
|
||||
Рядки мають аналогічне з Java представлення. Спеціальні символи
|
||||
позначаються за допомогою зворотнього слеша.
|
||||
*/
|
||||
val fooString = "My String Is Here!"
|
||||
val barString = "Printing on a new line?\nNo Problem!"
|
||||
val bazString = "Do you want to add a tab?\tNo Problem!"
|
||||
println(fooString)
|
||||
println(barString)
|
||||
println(bazString)
|
||||
|
||||
/*
|
||||
Необроблений рядок розмежовується за допомогою потрійних лапок (""").
|
||||
Необроблені рядки можуть містити переніс рядка (не спеціальний символ \n) та
|
||||
будь-які інші символи.
|
||||
*/
|
||||
val fooRawString = """
|
||||
fun helloWorld(val name : String) {
|
||||
println("Hello, world!")
|
||||
}
|
||||
"""
|
||||
println(fooRawString)
|
||||
|
||||
/*
|
||||
Рядки можуть містити шаблонні вирази.
|
||||
Шаблонний вираз починається із символа доллара "$".
|
||||
*/
|
||||
val fooTemplateString = "$fooString has ${fooString.length} characters"
|
||||
println(fooTemplateString) // => My String Is Here! has 18 characters
|
||||
|
||||
/*
|
||||
Щоб змінна могла мати значення null, потрібно це додатково вказати.
|
||||
Для цього після оголошеного типу змінної додається спеціальний символ "?".
|
||||
Отримати значення такої змінної можна використавши оператор "?.".
|
||||
Оператор "?:" застосовується, щоб оголосити альтернативне значення змінної
|
||||
у випадку, якщо вона буде рівна null.
|
||||
*/
|
||||
var fooNullable: String? = "abc"
|
||||
println(fooNullable?.length) // => 3
|
||||
println(fooNullable?.length ?: -1) // => 3
|
||||
fooNullable = null
|
||||
println(fooNullable?.length) // => null
|
||||
println(fooNullable?.length ?: -1) // => -1
|
||||
|
||||
/*
|
||||
Функції оголошуються з використанням ключового слова fun.
|
||||
Аргументи функції перелічуються у круглих дужках після назви функції.
|
||||
Аргументи можуть мати значення за замовчуванням. Тип значення, що повертатиметься
|
||||
функцією, вказується після оголошення аргументів за необхідністю.
|
||||
*/
|
||||
fun hello(name: String = "world"): String {
|
||||
return "Hello, $name!"
|
||||
}
|
||||
println(hello("foo")) // => Hello, foo!
|
||||
println(hello(name = "bar")) // => Hello, bar!
|
||||
println(hello()) // => Hello, world!
|
||||
|
||||
/*
|
||||
Аргументи функції можуть бути помічені ключовим словом vararg. Це дозволяє
|
||||
приймати довільну кількість аргументів функції зазначеного типу.
|
||||
*/
|
||||
fun varargExample(vararg names: Int) {
|
||||
println("Argument has ${names.size} elements")
|
||||
}
|
||||
varargExample() // => Argument has 0 elements
|
||||
varargExample(1) // => Argument has 1 elements
|
||||
varargExample(1, 2, 3) // => Argument has 3 elements
|
||||
|
||||
/*
|
||||
Коли функція складається з одного виразу, фігурні дужки не є обов'язковими.
|
||||
Тіло функції вказується після оператора "=".
|
||||
*/
|
||||
fun odd(x: Int): Boolean = x % 2 == 1
|
||||
println(odd(6)) // => false
|
||||
println(odd(7)) // => true
|
||||
|
||||
// Якщо тип значення, що повертається функцією, може бути однозначно визначено,
|
||||
// його непотрібно вказувати.
|
||||
fun even(x: Int) = x % 2 == 0
|
||||
println(even(6)) // => true
|
||||
println(even(7)) // => false
|
||||
|
||||
// Функції можуть приймати інші функції як аргументи, а також повертати інші функції.
|
||||
fun not(f: (Int) -> Boolean): (Int) -> Boolean {
|
||||
return {n -> !f.invoke(n)}
|
||||
}
|
||||
// Іменовані функції можуть бути вказані як аргументи за допомогою оператора "::".
|
||||
val notOdd = not(::odd)
|
||||
val notEven = not(::even)
|
||||
// Лямбда-вирази також можуть бути аргументами функції.
|
||||
val notZero = not {n -> n == 0}
|
||||
/*
|
||||
Якщо лямбда-вираз приймає лише один параметр, його оголошення може бути пропущене
|
||||
(разом із ->). Всередині виразу до цього параметра можна звернутись через
|
||||
змінну "it".
|
||||
*/
|
||||
val notPositive = not {it > 0}
|
||||
for (i in 0..4) {
|
||||
println("${notOdd(i)} ${notEven(i)} ${notZero(i)} ${notPositive(i)}")
|
||||
}
|
||||
|
||||
// Ключове слово class використовується для оголошення класів.
|
||||
class ExampleClass(val x: Int) {
|
||||
fun memberFunction(y: Int): Int {
|
||||
return x + y
|
||||
}
|
||||
|
||||
infix fun infixMemberFunction(y: Int): Int {
|
||||
return x * y
|
||||
}
|
||||
}
|
||||
/*
|
||||
Щоб створити новий об'єкт, потрібно викликати конструктор класу.
|
||||
Зазначте, що в Kotlin немає ключового слова new.
|
||||
*/
|
||||
val fooExampleClass = ExampleClass(7)
|
||||
// Методи класу викликаються через крапку.
|
||||
println(fooExampleClass.memberFunction(4)) // => 11
|
||||
/*
|
||||
Якщо функція була позначена ключовим словом infix, тоді її можна викликати через
|
||||
інфіксну нотацію.
|
||||
*/
|
||||
println(fooExampleClass infixMemberFunction 4) // => 28
|
||||
|
||||
/*
|
||||
Класи даних - це лаконічний спосіб створювати класи, що містимуть тільки дані.
|
||||
Методи "hashCode"/"equals" та "toString" автоматично генеруються.
|
||||
*/
|
||||
data class DataClassExample (val x: Int, val y: Int, val z: Int)
|
||||
val fooData = DataClassExample(1, 2, 4)
|
||||
println(fooData) // => DataClassExample(x=1, y=2, z=4)
|
||||
|
||||
// Класи даних також мають функцію "copy".
|
||||
val fooCopy = fooData.copy(y = 100)
|
||||
println(fooCopy) // => DataClassExample(x=1, y=100, z=4)
|
||||
|
||||
// Об'єкти можуть бути деструктурувані кількома способами.
|
||||
val (a, b, c) = fooCopy
|
||||
println("$a $b $c") // => 1 100 4
|
||||
|
||||
// деструктурування у циклі for
|
||||
for ((a, b, c) in listOf(fooData)) {
|
||||
println("$a $b $c") // => 1 100 4
|
||||
}
|
||||
|
||||
val mapData = mapOf("a" to 1, "b" to 2)
|
||||
// Map.Entry також деструктурувуються
|
||||
for ((key, value) in mapData) {
|
||||
println("$key -> $value")
|
||||
}
|
||||
|
||||
// Функція із "with" працює майже так само як це ж твердження у JavaScript.
|
||||
data class MutableDataClassExample (var x: Int, var y: Int, var z: Int)
|
||||
val fooMutableData = MutableDataClassExample(7, 4, 9)
|
||||
with (fooMutableData) {
|
||||
x -= 2
|
||||
y += 2
|
||||
z--
|
||||
}
|
||||
println(fooMutableData) // => MutableDataClassExample(x=5, y=6, z=8)
|
||||
|
||||
/*
|
||||
Список можна створити використовуючи функцію listOf.
|
||||
Список буде незмінним, тобто елементи не можна буде додавати або видаляти.
|
||||
*/
|
||||
val fooList = listOf("a", "b", "c")
|
||||
println(fooList.size) // => 3
|
||||
println(fooList.first()) // => a
|
||||
println(fooList.last()) // => c
|
||||
// доступ до елементів здійснюється через їхні порядковий номер.
|
||||
println(fooList[1]) // => b
|
||||
|
||||
// Змінні списки можна створити використовуючи функцію mutableListOf.
|
||||
val fooMutableList = mutableListOf("a", "b", "c")
|
||||
fooMutableList.add("d")
|
||||
println(fooMutableList.last()) // => d
|
||||
println(fooMutableList.size) // => 4
|
||||
|
||||
// Функція setOf створює об'єкт типу множина.
|
||||
val fooSet = setOf("a", "b", "c")
|
||||
println(fooSet.contains("a")) // => true
|
||||
println(fooSet.contains("z")) // => false
|
||||
|
||||
// mapOf створює асоціативний масив.
|
||||
val fooMap = mapOf("a" to 8, "b" to 7, "c" to 9)
|
||||
// Доступ до значень в асоціативних масивах здійснюється через їхні ключі.
|
||||
println(fooMap["a"]) // => 8
|
||||
|
||||
/*
|
||||
Послідовності представлені як колекції лінивих обчислень. Функція generateSequence
|
||||
створює послідовність.
|
||||
*/
|
||||
val fooSequence = generateSequence(1, { it + 1 })
|
||||
val x = fooSequence.take(10).toList()
|
||||
println(x) // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
|
||||
// Приклад використання послідовностей, генерація чисел Фібоначчі:
|
||||
fun fibonacciSequence(): Sequence<Long> {
|
||||
var a = 0L
|
||||
var b = 1L
|
||||
|
||||
fun next(): Long {
|
||||
val result = a + b
|
||||
a = b
|
||||
b = result
|
||||
return a
|
||||
}
|
||||
|
||||
return generateSequence(::next)
|
||||
}
|
||||
val y = fibonacciSequence().take(10).toList()
|
||||
println(y) // => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
|
||||
|
||||
// Kotlin має функції вищого порядку для роботи з колекціями.
|
||||
val z = (1..9).map {it * 3}
|
||||
.filter {it < 20}
|
||||
.groupBy {it % 2 == 0}
|
||||
.mapKeys {if (it.key) "even" else "odd"}
|
||||
println(z) // => {odd=[3, 9, 15], even=[6, 12, 18]}
|
||||
|
||||
// Цикл for може використовуватись з будь-чим, що має ітератор.
|
||||
for (c in "hello") {
|
||||
println(c)
|
||||
}
|
||||
|
||||
// Принцип роботи циклів "while" не відрізняється від інших мов програмування.
|
||||
var ctr = 0
|
||||
while (ctr < 5) {
|
||||
println(ctr)
|
||||
ctr++
|
||||
}
|
||||
do {
|
||||
println(ctr)
|
||||
ctr++
|
||||
} while (ctr < 10)
|
||||
|
||||
/*
|
||||
if може бути використаний як вираз, що повертає значення. Тому тернарний
|
||||
оператор ?: не потрібний в Kotlin.
|
||||
*/
|
||||
val num = 5
|
||||
val message = if (num % 2 == 0) "even" else "odd"
|
||||
println("$num is $message") // => 5 is odd
|
||||
|
||||
// "when" використовується як альтернатива ланцюгам "if-else if".
|
||||
val i = 10
|
||||
when {
|
||||
i < 7 -> println("first block")
|
||||
fooString.startsWith("hello") -> println("second block")
|
||||
else -> println("else block")
|
||||
}
|
||||
|
||||
// "when" може приймати аргумент.
|
||||
when (i) {
|
||||
0, 21 -> println("0 or 21")
|
||||
in 1..20 -> println("in the range 1 to 20")
|
||||
else -> println("none of the above")
|
||||
}
|
||||
|
||||
// "when" також може використовуватись як функція, що повертає значення.
|
||||
var result = when (i) {
|
||||
0, 21 -> "0 or 21"
|
||||
in 1..20 -> "in the range 1 to 20"
|
||||
else -> "none of the above"
|
||||
}
|
||||
println(result)
|
||||
|
||||
/*
|
||||
Тип об'єкта можна перевірити використавши оператор is. Якщо перевірка проходить
|
||||
успішно, тоді можна використовувати об'єкт як данний тип не приводячи до нього
|
||||
додатково.
|
||||
*/
|
||||
fun smartCastExample(x: Any) : Boolean {
|
||||
if (x is Boolean) {
|
||||
// x тепер має тип Boolean
|
||||
return x
|
||||
} else if (x is Int) {
|
||||
// x тепер має тип Int
|
||||
return x > 0
|
||||
} else if (x is String) {
|
||||
// x тепер має тип String
|
||||
return x.isNotEmpty()
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
println(smartCastExample("Hello, world!")) // => true
|
||||
println(smartCastExample("")) // => false
|
||||
println(smartCastExample(5)) // => true
|
||||
println(smartCastExample(0)) // => false
|
||||
println(smartCastExample(true)) // => true
|
||||
|
||||
// Smartcast (розумне приведення) також працює з блоком when
|
||||
fun smartCastWhenExample(x: Any) = when (x) {
|
||||
is Boolean -> x
|
||||
is Int -> x > 0
|
||||
is String -> x.isNotEmpty()
|
||||
else -> false
|
||||
}
|
||||
|
||||
/*
|
||||
Розширення - це ще один спосіб розширити функціонал класу.
|
||||
Подібні методи розширення реалізовані у С#.
|
||||
*/
|
||||
fun String.remove(c: Char): String {
|
||||
return this.filter {it != c}
|
||||
}
|
||||
println("Hello, world!".remove('l')) // => Heo, word!
|
||||
}
|
||||
|
||||
// Класи перелічення також подібні до тих типів, що і в Java.
|
||||
enum class EnumExample {
|
||||
A, B, C // Константи перелічення розділені комами.
|
||||
}
|
||||
fun printEnum() = println(EnumExample.A) // => A
|
||||
|
||||
// Оскільки кожне перелічення - це об'єкт класу enum, воно може бути
|
||||
// проініціалізоване наступним чином:
|
||||
enum class EnumExample(val value: Int) {
|
||||
A(value = 1),
|
||||
B(value = 2),
|
||||
C(value = 3)
|
||||
}
|
||||
fun printProperty() = println(EnumExample.A.value) // => 1
|
||||
|
||||
// Кожне перелічення має властивості, які дозволяють отримати його ім'я
|
||||
// та порядок (позицію) в класі enum:
|
||||
fun printName() = println(EnumExample.A.name) // => A
|
||||
fun printPosition() = println(EnumExample.A.ordinal) // => 0
|
||||
|
||||
/*
|
||||
Ключове слово object можна використати для створення об'єкту сінглтону. Об'єкт не
|
||||
можна інстанціювати, проте на його унікальний екземпляр можна посилатись за іменем.
|
||||
Подібна можливість є в сінглтон об'єктах у Scala.
|
||||
*/
|
||||
object ObjectExample {
|
||||
fun hello(): String {
|
||||
return "hello"
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Hello, it's me, ${ObjectExample::class.simpleName}"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun useSingletonObject() {
|
||||
println(ObjectExample.hello()) // => hello
|
||||
// В Kotlin, "Any" - це корінь ієрархії класів, так само, як і "Object" у Java.
|
||||
val someRef: Any = ObjectExample
|
||||
println(someRef) // => Hello, it's me, ObjectExample
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Оператор перевірки на те, що об'єкт не рівний null, (!!) перетворює будь-яке значення в ненульовий тип і кидає виняток, якщо значення рівне null.
|
||||
*/
|
||||
var b: String? = "abc"
|
||||
val l = b!!.length
|
||||
|
||||
// Далі - приклади перевизначення методів класу Any в класі-насліднику
|
||||
data class Counter(var value: Int) {
|
||||
// перевизначити Counter += Int
|
||||
operator fun plusAssign(increment: Int) {
|
||||
this.value += increment
|
||||
}
|
||||
|
||||
// перевизначити Counter++ та ++Counter
|
||||
operator fun inc() = Counter(value + 1)
|
||||
|
||||
// перевизначити Counter + Counter
|
||||
operator fun plus(other: Counter) = Counter(this.value + other.value)
|
||||
|
||||
// перевизначити Counter * Counter
|
||||
operator fun times(other: Counter) = Counter(this.value * other.value)
|
||||
|
||||
// перевизначити Counter * Int
|
||||
operator fun times(value: Int) = Counter(this.value * value)
|
||||
|
||||
// перевизначити Counter in Counter
|
||||
operator fun contains(other: Counter) = other.value == this.value
|
||||
|
||||
// перевизначити Counter[Int] = Int
|
||||
operator fun set(index: Int, value: Int) {
|
||||
this.value = index + value
|
||||
}
|
||||
|
||||
// перевизначити виклик екземпляру Counter
|
||||
operator fun invoke() = println("The value of the counter is $value")
|
||||
|
||||
}
|
||||
// Можна також перевизначити оператори через методи розширення.
|
||||
// перевизначити -Counter
|
||||
operator fun Counter.unaryMinus() = Counter(-this.value)
|
||||
|
||||
fun operatorOverloadingDemo() {
|
||||
var counter1 = Counter(0)
|
||||
var counter2 = Counter(5)
|
||||
counter1 += 7
|
||||
println(counter1) // => Counter(value=7)
|
||||
println(counter1 + counter2) // => Counter(value=12)
|
||||
println(counter1 * counter2) // => Counter(value=35)
|
||||
println(counter2 * 2) // => Counter(value=10)
|
||||
println(counter1 in Counter(5)) // => false
|
||||
println(counter1 in Counter(7)) // => true
|
||||
counter1[26] = 10
|
||||
println(counter1) // => Counter(value=36)
|
||||
counter1() // => The value of the counter is 36
|
||||
println(-counter2) // => Counter(value=-5)
|
||||
}
|
||||
```
|
||||
|
||||
### Подальше вивчення
|
||||
|
||||
* [Уроки Kotlin](https://kotlinlang.org/docs/tutorials/)
|
||||
* [Спробувати попрацювати з Kotlin в браузері](https://play.kotlinlang.org/)
|
||||
* [Список корисних посилань](http://kotlin.link/)
|
Loading…
Reference in New Issue
Block a user