,
@@ -1016,31 +1034,67 @@ gen_to_list = list(values)
print(gen_to_list) # => [-1, -2, -3, -4, -5]
-# Decorators
-# In this example `beg` wraps `say`. If say_please is True then it
-# will change the returned message.
-from functools import wraps
+# Decorators are a form of syntactic sugar.
+# They make code easier to read while accomplishing clunky syntax.
+# Wrappers are one type of decorator.
+# They're really useful for adding logging to existing functions without needing to modify them.
-def beg(target_function):
- @wraps(target_function)
+def log_function(func):
def wrapper(*args, **kwargs):
- msg, say_please = target_function(*args, **kwargs)
- if say_please:
- return "{} {}".format(msg, "Please! I am poor :(")
- return msg
-
+ print("Entering function", func.__name__)
+ result = func(*args, **kwargs)
+ print("Exiting function", func.__name__)
+ return result
return wrapper
+@log_function # equivalent:
+def my_function(x,y): # def my_function(x,y):
+ return x+y # return x+y
+ # my_function = log_function(my_function)
+# The decorator @log_function tells us as we begin reading the function definition
+# for my_function that this function will be wrapped with log_function.
+# When function definitions are long, it can be hard to parse the non-decorated
+# assignment at the end of the definition.
-@beg
-def say(say_please=False):
- msg = "Can you buy me a beer?"
- return msg, say_please
+my_function(1,2) # => "Entering function my_function"
+ # => "3"
+ # => "Exiting function my_function"
+# But there's a problem.
+# What happens if we try to get some information about my_function?
+
+print(my_function.__name__) # => 'wrapper'
+print(my_function.__code__.co_argcount) # => 0. The argcount is 0 because both arguments in wrapper()'s signature are optional.
+
+# Because our decorator is equivalent to my_function = log_function(my_function)
+# we've replaced information about my_function with information from wrapper
+
+# Fix this using functools
+
+from functools import wraps
+
+def log_function(func):
+ @wraps(func) # this ensures docstring, function name, arguments list, etc. are all copied
+ # to the wrapped function - instead of being replaced with wrapper's info
+ def wrapper(*args, **kwargs):
+ print("Entering function", func.__name__)
+ result = func(*args, **kwargs)
+ print("Exiting function", func.__name__)
+ return result
+ return wrapper
+
+@log_function
+def my_function(x,y):
+ return x+y
+
+my_function(1,2) # => "Entering function my_function"
+ # => "3"
+ # => "Exiting function my_function"
+
+print(my_function.__name__) # => 'my_function'
+print(my_function.__code__.co_argcount) # => 2
-print(say()) # Can you buy me a beer?
-print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :(
```
### Free Online
diff --git a/rst.html.markdown b/rst.html.markdown
index c177fdb4..8a730c7a 100644
--- a/rst.html.markdown
+++ b/rst.html.markdown
@@ -8,7 +8,7 @@ filename: restructuredtext.rst
RST, Restructured Text, is a file format created by the Python community to write documentation. It is part of [Docutils](https://docutils.sourceforge.io/rst.html).
-RST is a markdown language like HTML but is much more lightweight and easier to read.
+RST is a markup language like HTML but is much more lightweight and easier to read.
## Installation
diff --git a/ru-ru/asymptotic-notation-ru.html.markdown b/ru-ru/asymptotic-notation-ru.html.markdown
index 7fd02c47..cb276ec1 100644
--- a/ru-ru/asymptotic-notation-ru.html.markdown
+++ b/ru-ru/asymptotic-notation-ru.html.markdown
@@ -48,7 +48,7 @@ f(n) — время выполнения. Тогда для данного ал
С помощью О-символики можно оценить функцию или алгоритм
несколькими различными способами. Например, можно оценить алгоритм исходя
из нижней оценки, верхней оценки, тождественной оценки. Чаще всего встречается
-анализ на основе верхней оценки. Как правило не используется нижняя оценка,
+анализ на основе верхней оценки. Как правило, не используется нижняя оценка,
потому что она не подходит под планируемые условия. Отличный пример — алгоритмы
сортировки, особенно добавление элементов в древовидную структуру. Нижняя оценка
большинства таких алгоритмов может быть дана как одна операция. В то время как в
@@ -155,8 +155,8 @@ c (c > 0) и n0 (n0 > 0), такие, что `f(n)` >= `c
### Примечание
-Асимптотические оценки, сделаные при помощи О Большого и Омега Большого, могут
-как являться, так и не являться точными. Для того, чтобы обозначить, что границы не
+Асимптотические оценки, сделанные при помощи О Большого и Омега Большого, могут
+как являться, так и не являться точными. Для того чтобы обозначить, что границы не
являются асимптотически точными, используются записи О Малое и Омега Малое.
### О Малое
diff --git a/ru-ru/binary-search-ru.html.markdown b/ru-ru/binary-search-ru.html.markdown
index 9ed62cb8..ab1a1585 100644
--- a/ru-ru/binary-search-ru.html.markdown
+++ b/ru-ru/binary-search-ru.html.markdown
@@ -55,7 +55,7 @@ def search(arr, x):
### На заметку
-Существует и другая форма двоичного поиска, которая можеть быть полезна.
+Существует и другая форма двоичного поиска, которая может быть полезна.
## На почитать
diff --git a/ru-ru/c++-ru.html.markdown b/ru-ru/c++-ru.html.markdown
index fad1b434..43e9e6a3 100644
--- a/ru-ru/c++-ru.html.markdown
+++ b/ru-ru/c++-ru.html.markdown
@@ -17,7 +17,7 @@ C++ - компилируемый, статически типизированн
- "лучшая замена C"
- язык с поддержкой абстракции данных
-- язык с поддержкой объектно-ориентированого программирования
+- язык с поддержкой объектно-ориентированного программирования
- язык с поддержкой обобщенного программирования
Хотя его синтаксис может показаться более трудным или сложным для понимания, чем в более современных языках,
diff --git a/ru-ru/c-ru.html.markdown b/ru-ru/c-ru.html.markdown
index eb5de011..a146a76b 100644
--- a/ru-ru/c-ru.html.markdown
+++ b/ru-ru/c-ru.html.markdown
@@ -476,7 +476,7 @@ void str_reverse_through_pointer(char *str_in) {
Если у вас появился вопрос, почитайте [compl.lang.c Frequently Asked Questions](http://c-faq.com).
Очень важно использовать правильные отступы и ставить пробелы в нужных местах.
-Читаемый код лучше чем красивый или быстрый код.
+Читаемый код лучше, чем красивый или быстрый код.
Чтобы научиться писать хороший код, почитайте [Linux kernel coding style](https://www.kernel.org/doc/Documentation/CodingStyle).
Также не забывайте, что [Google](http://google.com) и [Яндекс](http://yandex.ru) – ваши хорошие друзья.
diff --git a/ru-ru/common-lisp-ru.html.markdown b/ru-ru/common-lisp-ru.html.markdown
index d5f9bf0e..0490ee30 100644
--- a/ru-ru/common-lisp-ru.html.markdown
+++ b/ru-ru/common-lisp-ru.html.markdown
@@ -14,7 +14,8 @@ Common Lisp - мультипарадигменный язык программи
спектра задач.
Его частенько называют программируемым языком программирования.
-Идеальная отправная точка - книга [Common Lisp на практике (перевод)](http://lisper.ru/pcl/).
+Идеальная отправная точка - книга
+[Common Lisp на практике (перевод)](https://github.com/pcl-ru/pcl-ru/releases/download/v1.1/pcl-ru.pdf).
Ещё одна популярная книга [Land of Lisp](http://landoflisp.com/).
И одна из последних книг [Common Lisp Recipes](http://weitz.de/cl-recipes/) вобрала в себя лучшие
архитектурные решения на основе опыта коммерческой работки автора.
@@ -674,7 +675,7 @@ nil ; ложь; а ещё пустой список () тож
## Для чтения
На русском
-- [Practical Common Lisp](http://www.gigamonkeys.com/book/)
+- [Practical Common Lisp](https://github.com/pcl-ru/pcl-ru/releases/download/v1.1/pcl-ru.pdf)
На английском
- [Practical Common Lisp](http://www.gigamonkeys.com/book/)
@@ -685,7 +686,7 @@ nil ; ложь; а ещё пустой список () тож
На русском
-- [Lisper.ru](http://lisper.ru/)
+- [Сообщество в Telegram](https://t.me/lisp_forever)
На английском
diff --git a/ru-ru/css-ru.html.markdown b/ru-ru/css-ru.html.markdown
index e0e5e30b..b543bfeb 100644
--- a/ru-ru/css-ru.html.markdown
+++ b/ru-ru/css-ru.html.markdown
@@ -20,12 +20,12 @@ HTML элементы и определять их внешний вид.
**ВАЖНО:** Так как результатом применения CSS является изменение внешнего вида
элементов, постарайтесь использовать CSS-песочницы при изучении языка.
-Например [dabblet](http://dabblet.com/).
+Например, [dabblet](http://dabblet.com/).
В данной статье рассматриваются в первую очередь синтаксис и общие рекомендации.
```css
-/* Для комментариев используется слеш-астериск, как на этой строчке.
+/* Для комментариев используется слэш-астериск, как на этой строчке.
В CSS нет однострочных комментариев; все комментарии записываются таким способом */
/* ####################
@@ -104,7 +104,7 @@ div.some-parent.class-name {}
.i-am-any-before ~ .this-element {}
-/* Существуют псевдо-классы, позволяющие изменять внешний вид элемента
+/* Существуют псевдоклассы, позволяющие изменять внешний вид элемента
в зависимости от событий, произошедших с элементом */
/* например, когда курсор наведен на элемент */
diff --git a/ru-ru/forth-ru.html.markdown b/ru-ru/forth-ru.html.markdown
index 2fc4ad7c..90936b19 100644
--- a/ru-ru/forth-ru.html.markdown
+++ b/ru-ru/forth-ru.html.markdown
@@ -10,7 +10,7 @@ lang: ru-ru
Форт создан Чарлзом Муром в 70-е годы. Это императивный, стековый язык программирования и среда исполнения программ. Использовался в таких проектах как Open Firmware. Продолжает применятся в проектах. Применяется в НАСА.
-Внимание: эта материал использует реализацию Форта - Gforth, но большая часть написанного будет работать в других средах.
+Внимание: этот материал использует реализацию Форта - Gforth, но большая часть написанного будет работать в других средах.
```
diff --git a/ru-ru/go-ru.html.markdown b/ru-ru/go-ru.html.markdown
index 8d2eac90..22249a6e 100644
--- a/ru-ru/go-ru.html.markdown
+++ b/ru-ru/go-ru.html.markdown
@@ -82,7 +82,7 @@ func learnTypes() {
// Символ не из ASCII. Исходный код Go в кодировке UTF-8.
g := 'Σ' // тип rune, это алиас для типа int32, содержит символ юникода.
- f := 3.14195 // float64, 64-х битное число с плавающей точкой (IEEE-754).
+ f := 3.14159 // float64, 64-х битное число с плавающей точкой (IEEE-754).
c := 3 + 4i // complex128, внутри себя содержит два float64.
// Синтаксис var с инициализациями.
@@ -334,12 +334,12 @@ func requestServer() {
## Что дальше
-Основа всех основ в Go это [официальный веб сайт](http://golang.org/).
+Основа всех основ в Go это [официальный веб сайт](https://go.dev/).
Там можно пройти туториал, поиграться с интерактивной средой Go и почитать
объёмную документацию.
Для живого ознакомления рекомендуется почитать исходные коды [стандартной
-библиотеки Go](http://golang.org/src/pkg/). Отлично задокументированная, она
+библиотеки Go](https://go.dev/src/). Отлично задокументированная, она
является лучшим источником для чтения и понимания Go, его стиля и идиом. Либо
-можно, кликнув на имени функции в [документации](http://golang.org/pkg/),
+можно, кликнув на имени функции в [документации](https://go.dev/pkg/),
перейти к ее исходным кодам.
diff --git a/ru-ru/haml-ru.html.markdown b/ru-ru/haml-ru.html.markdown
index c2f8852e..ed823496 100644
--- a/ru-ru/haml-ru.html.markdown
+++ b/ru-ru/haml-ru.html.markdown
@@ -39,7 +39,7 @@ $ haml input_file.haml output_file.html
/ Комментарии
/ -------------------------------------------
-/ Комментари начинается с символа косой черты.
+/ Комментарии начинается с символа косой черты.
/
Для написания многострочного комментария расположите ваш комментарий
@@ -94,7 +94,7 @@ $ haml input_file.haml output_file.html
/ выведет 'Да & да'
/
- Чтобы выполнять Ruby-код без экранрования, можно использовать
+ Чтобы выполнять Ruby-код без экранирования, можно использовать
"восклицательный знак" и "равно" (!=)
%p
@@ -196,13 +196,13 @@ $ haml input_file.haml output_file.html
/ -------------------------------------------
/
- Фильтры передают связанный блок текста в соотвествующую
+ Фильтры передают связанный блок текста в соответствующую
фильтрующую программу и возвращают результат в Haml
Фильтр обозначается двоеточием и названием фильтра:
/ Markdown filter
:markdown
- # Заголовк
+ # Заголовок
Текст **внутри** *блока*
@@ -221,7 +221,7 @@ $ haml input_file.haml output_file.html
/
- Существует множество типов фильров (:markdown, :javascript, :coffee,
+ Существует множество типов фильтров (:markdown, :javascript, :coffee,
:css, :ruby и так далее). Вы можете определить собственный фильтр c
помощью Haml::Filters.
diff --git a/ru-ru/haskell-ru.html.markdown b/ru-ru/haskell-ru.html.markdown
index b1b8eb79..aada30c1 100644
--- a/ru-ru/haskell-ru.html.markdown
+++ b/ru-ru/haskell-ru.html.markdown
@@ -8,7 +8,7 @@ translators:
lang: ru-ru
---
-Haskell разрабатывался, как чистый функциональный язык программирования, применимый на практике. Язык известен благодаря своей системе типов, и "знаменит" благодаря монадам. [Меня][autor] же Haskell заставляет возвращаться к себе снова и снова именно своей элегантностью и [я][autor] получаю истинное удовольствие, программируя на Haskell.
+Haskell разрабатывался, как чистый функциональный язык программирования, применимый на практике. Язык известен благодаря своей системе типов, и "знаменит" благодаря монадам. [Меня][author] же Haskell заставляет возвращаться к себе снова и снова именно своей элегантностью и [я][author] получаю истинное удовольствие, программируя на Haskell.
```haskell
-- Однострочные комментарии начинаются с двух дефисов
@@ -172,7 +172,7 @@ fib x
первое определение, к образцу которого
"подойдет" набор аргументов -}
fib 1 = 1
-fib 2 = 2
+fib 2 = 1
fib x = fib (x - 1) + fib (x - 2)
-- Pattern matching для кортежей выглядит так
@@ -544,4 +544,4 @@ Haskell прост в установке, забирайте [здесь](http:/
[Learn you a Haskell](http://learnyouahaskell.com/) и
[Real World Haskell](http://book.realworldhaskell.org/).
-[autor]: http://adit.io имеется в виду автор оригинального текста Adit Bhargava *(примечание переводчика)*
+[author]: http://adit.io имеется в виду автор оригинального текста Adit Bhargava *(примечание переводчика)*
diff --git a/ru-ru/html-ru.html.markdown b/ru-ru/html-ru.html.markdown
index 120981b9..4220902e 100644
--- a/ru-ru/html-ru.html.markdown
+++ b/ru-ru/html-ru.html.markdown
@@ -25,7 +25,7 @@ HTML расшифровывается как Hypertext Markup Language(гипе
В данной статье рассматривается в основном HTML синтаксис и некоторые полезные советы.
```html
-
+
@@ -71,19 +71,19 @@ HTML расшифровывается как Hypertext Markup Language(гипе
Мой сайт
-
-
-
+
+
+
Hello, world!
Переходите сюда, чтоб посмотреть как это выглядит.
-
- Это параграф.
+
+ Это параграф.
Это другой параграф.
-
- Это элемент в не нумерованном списке (маркированный список)
- Это еще один элемент
@@ -124,6 +124,6 @@ HTML файлы имеют окончание(расширение) `.html`.
## Узнать больше
-* [википедиа](https://ru.wikipedia.org/wiki/HTML)
+* [википедия](https://ru.wikipedia.org/wiki/HTML)
* [HTML учебник](https://developer.mozilla.org/ru/docs/Web/HTML)
* [htmlbook](http://htmlbook.ru/)
diff --git a/ru-ru/javascript-ru.html.markdown b/ru-ru/javascript-ru.html.markdown
index 4556b425..4c4fa503 100644
--- a/ru-ru/javascript-ru.html.markdown
+++ b/ru-ru/javascript-ru.html.markdown
@@ -504,7 +504,7 @@ if (Object.create === undefined) { // не перезаписываем мето
[Mozilla Developer Network](https://developer.mozilla.org/ru/docs/Web/JavaScript) —
предоставляет отличную документацию для JavaScript, как он используется в браузерах.
-Кроме того, это вики, поэтому, если вы знаете больше, вы можете помочь другим,
+Кроме того, это вики. Поэтому, если вы знаете больше, вы можете помочь другим,
делясь своими знаниями.
[JavaScript Garden](http://bonsaiden.github.io/JavaScript-Garden/ru/) — это
diff --git a/ru-ru/linker-ru.html.markdown b/ru-ru/linker-ru.html.markdown
index 7df29c23..14cfd229 100644
--- a/ru-ru/linker-ru.html.markdown
+++ b/ru-ru/linker-ru.html.markdown
@@ -34,11 +34,11 @@ lang: ru-ru
# Определяем точку входа в программу
ENTRY(Reset_Handler)
-# Определяем перемнную которая содержит адрес вершины стека
+# Определяем переменную которая содержит адрес вершины стека
_estack = 0x20020000;
-# Определяем перемнную которая содержит значение размера кучи
+# Определяем переменную которая содержит значение размера кучи
_Min_Heap_Size = 0x200;
-# Определяем перемнную которая содержит значение размера стека
+# Определяем переменную которая содержит значение размера стека
_Min_Stack_Size = 0x400;
# Описание карты памяти доступной для данного процессора
@@ -50,7 +50,7 @@ _Min_Stack_Size = 0x400;
# RAM - начинается с адреса 0x20000000 и занимает 128 Кбайт;
# CCMRAM - начинается с адреса 0x10000000и занимает 64 Кбайт;
# FLASH - начинается с адреса 0x8000000 занимает 1024 Кбайт;
-# Причем RAM память доступка для чтения, записи и исполнения.
+# Причем RAM память доступна для чтения, записи и исполнения.
# CCMRAM память доступна только на чтение и запись.
# FLASH память доступна на чтение и исполнение.
MEMORY
@@ -70,7 +70,7 @@ SECTIONS
. = ALIGN(4);
# Существует опция --gc-sections, которая позволяет собирать мусор из неиспользуемых
- # входных разделов. И если есть разделы, которые сборщик муссора не должен трогать,
+ # входных разделов. И если есть разделы, которые сборщик мусора не должен трогать,
# то их необходимо указать в качестве аргумента функции KEEP() (аналог ключевого слова
# volatile).
# Запись (*(.isr_vector)) означает разделы .isr_vector во всех объектных файлах. Т.к.
@@ -80,8 +80,8 @@ SECTIONS
# Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4);
- # Выражение ">ОБЛАСТЬ_ПАМЯТИ" указывает в какую именно область памяти будет помещенна
- # данная секция. В нашем слущае секция .isr_vector будет размещена во FLASH памяти.
+ # Выражение ">ОБЛАСТЬ_ПАМЯТИ" указывает в какую именно область памяти будет помещена
+ # данная секция. В нашем случае секция .isr_vector будет размещена во FLASH памяти.
} >FLASH
# ИТОГО: Секция .isr_vector, которая содержит таблицу векторов прерываний выравнивается
@@ -125,7 +125,7 @@ SECTIONS
# Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4);
- # Указываем, что в данной секции будут хранится области .rodataвсех
+ # Указываем, что в данной секции будут хранится области .rodata всех
# объектных файлов
*(.rodata)
*(.rodata*)
@@ -158,13 +158,13 @@ SECTIONS
_edata = .;
# Функция AT указывает на то, что данный сектор хранится в одной области памяти
- # (в нашем случае FLASH), а исполняться будет из другой обасти памяти (в нашем случае RAM).
- # Есть два типа адрессов:
- # * VMA (Virtual memory address) - это run-time адрес по которому уомпилятор ожидает
+ # (в нашем случае FLASH), а исполняться будет из другой области памяти (в нашем случае RAM).
+ # Есть два типа адресов:
+ # * VMA (Virtual memory address) - это run-time адрес по которому компилятор ожидает
# видеть данные.
# * LMA (Load memory address) - это адрес по которому линкер хранит данные.
- #Startup должен код скопировать секцию .data из адрессов LMA в адресса VMA.
+ #Startup должен код скопировать секцию .data из адресов LMA в адреса VMA.
} >RAM AT> FLASH
diff --git a/ru-ru/markdown-ru.html.markdown b/ru-ru/markdown-ru.html.markdown
index 579a9a20..728741af 100644
--- a/ru-ru/markdown-ru.html.markdown
+++ b/ru-ru/markdown-ru.html.markdown
@@ -294,7 +294,7 @@ Markdown также позволяет размечать ссылку в вид
```md

```
-Изображения тоже могут быть оформлены, как сноски.
+Изображения тоже могут быть оформлены как сноски.
![Это альтернативный текст.][myimage]
diff --git a/ru-ru/nim-ru.html.markdown b/ru-ru/nim-ru.html.markdown
index 0e08f1bf..09784792 100644
--- a/ru-ru/nim-ru.html.markdown
+++ b/ru-ru/nim-ru.html.markdown
@@ -3,7 +3,7 @@ language: Nim
filename: learnNim-ru.nim
contributors:
- ["Jason J. Ayala P.", "http://JasonAyala.com"]
- - ["Dennis Felsing", "http://felsin9.de/nnis/"]
+ - ["Dennis Felsing", "https://dennis.felsing.org"]
translators:
- ["Nomadic", "https://github.com/n0madic"]
- ["dvska", "https://github.com/dvska"]
diff --git a/ru-ru/php-ru.html.markdown b/ru-ru/php-ru.html.markdown
index af77a9ca..4a508cfc 100644
--- a/ru-ru/php-ru.html.markdown
+++ b/ru-ru/php-ru.html.markdown
@@ -125,7 +125,7 @@ echo 'Multiple', 'Parameters', 'Valid'; // печатает 'MultipleParametersV
// и никогда не может быть изменена во время выполнения программы!
// Правильное имя константы начинается с буквы или символа подчеркивания
-// и содержит любое колличество букв, цифр или символов подчеркивания.
+// и содержит любое количество букв, цифр или символов подчеркивания.
define("FOO", "something");
// Доступ к константе возможен через прямое указание её имени без знака $
@@ -224,7 +224,7 @@ assert($c > $b); // больше
assert($a <= $b); // меньше или равно
assert($c >= $d); // больше или равно
-// Следующие утверждения истинны, если переменные имеют одинаковые тип.
+// Следующие утверждения истинны, если переменные имеют одинаковый тип.
assert($c === $d);
assert($a !== $d);
assert(1 == '1');
@@ -251,7 +251,7 @@ echo $string + $string; // => 2 (строка превращается в чис
$string = 'one';
echo $string + $string; // => 0
-// Приведение типов (type casting) может быть использовано для преобразование
+// Приведение типов (type casting) может быть использовано для преобразования
// переменной в другой тип
$boolean = (boolean) 1; // => true
@@ -458,7 +458,7 @@ include_once 'my-file.php';
require 'my-file.php';
require_once 'my-file.php';
-// Действует также как и include(), но если файл не удалось подключить,
+// Действует так же как и include(), но если файл не удалось подключить,
// функция выдает фатальную ошибку
// Содержимое файла my-include.php:
@@ -497,7 +497,7 @@ class MyClass
// Конструктор описывается с помощью __construct
public function __construct($instanceProp) {
- // Доступ к эземпляру класса с помощью $this
+ // Доступ к экземпляру класса с помощью $this
$this->instanceProp = $instanceProp;
}
@@ -661,7 +661,7 @@ $cls->myTraitMethod(); // Напечатает "I have MyTrait"
{1, 2, 3, 4}
-# Similar to keys of a dictionary, elements of a set have to be immutable.
# Как и ключи словаря, элементы множества должны быть неизменяемыми.
invalid_set = {[1], 1} # => Выбрасывает ошибку TypeError: unhashable type: 'list'
valid_set = {(1,), 1}
diff --git a/ru-ru/qt-ru.html.markdown b/ru-ru/qt-ru.html.markdown
index 5fbcc3b4..15e2c775 100644
--- a/ru-ru/qt-ru.html.markdown
+++ b/ru-ru/qt-ru.html.markdown
@@ -80,7 +80,7 @@ int main(int argc, char *argv[]) {
```
Обратите внимание на метод *QObject::connect*. Этот метод соединяет *СИГНАЛЫ* одного объекта со *СЛОТАМИ* другого.
-**Сигналы** отправляются когда с объектами происходят отпределённые события, например, сигнал *нажатие* отправляется когда пользователь нажимает на объект типа QPushButton.
+**Сигналы** отправляются когда с объектами происходят определённые события, например, сигнал *нажатие* отправляется, когда пользователь нажимает на объект типа QPushButton.
**Слоты** это *действия*, которые могут быть выполнены в ответ на полученные сигналы.
diff --git a/ru-ru/sql-ru.html.markdown b/ru-ru/sql-ru.html.markdown
index 7353a175..c7ba0edb 100644
--- a/ru-ru/sql-ru.html.markdown
+++ b/ru-ru/sql-ru.html.markdown
@@ -24,7 +24,7 @@ lang: ru-ru
Некоторые команды ниже предполагают использование
[демонстрационного образца базы данных сотрудников от MySQL](https://dev.mysql.com/doc/employee/en/), доступного на [Github](https://github.com/datacharmer/test_db).
Следовательно, для повторения команд в локальном окружении он должен быть загружен.
-Файлы на github — это скрипты с командами, которые схожи с командами ниже,
+Файлы на github — это скрипты с командами, схожие с командами ниже,
которые создают и манипулируют таблицами и данными о сотрудниках вымышленной
компании. Синтаксис для запуска этих скриптов будет зависеть от используемой
вами реализации SQL. Обычно используется утилита, запускаемая из командной
@@ -50,7 +50,7 @@ SHOW DATABASES;
USE employees;
-- Выбрать все строки и колонки из таблицы «departments» (отделы) текущей базы.
--- В интерактивном режиме обыч но результат будет выведен на экран.
+-- В интерактивном режиме обычно результат будет выведен на экран.
SELECT * FROM departments;
-- Тот же запрос, что и выше, но выбор только колонок «dept_no» и «dept_name».
diff --git a/ru-ru/tmux-ru.html.markdown b/ru-ru/tmux-ru.html.markdown
index aa7545cc..643c48b0 100644
--- a/ru-ru/tmux-ru.html.markdown
+++ b/ru-ru/tmux-ru.html.markdown
@@ -249,4 +249,4 @@ set -g status-right "#[fg=green] | #[fg=white]#(tmux-mem-cpu-load)#[fg=green] |
[Archlinux Wiki](https://wiki.archlinux.org/index.php/Tmux)
-[Отображение CPU/MEM % в статусбаре](https://stackoverflow.com/questions/11558907/is-there-a-better-way-to-display-cpu-usage-in-tmux)
+[Отображение CPU/MEM % в статус баре](https://stackoverflow.com/questions/11558907/is-there-a-better-way-to-display-cpu-usage-in-tmux)
diff --git a/ru-ru/typescript-ru.html.markdown b/ru-ru/typescript-ru.html.markdown
index 09bbb2d1..ad931599 100644
--- a/ru-ru/typescript-ru.html.markdown
+++ b/ru-ru/typescript-ru.html.markdown
@@ -9,8 +9,8 @@ translators:
filename: learntypescript-ru.ts
---
-TypeScript — это язык программирования, целью которого является лёгкая разработка широкомасштабируемых JavaScript-приложений.
-TypeScript добавляет в Javascript общие концепции, такие, как классы, модули, интерфейсы, обобщённое программирование и (опционально) статическую типизацию.
+TypeScript — это язык программирования, целью которого является лёгкая разработка широко масштабируемых JavaScript-приложений.
+TypeScript добавляет в Javascript общие концепции, такие как классы, модули, интерфейсы, обобщённое программирование и (опционально) статическую типизацию.
Это надмножество языка JavaScript: весь JavaScript-код является валидным TypeScript-кодом, следовательно, может быть добавлен бесшовно в любой проект.
Компилятор TypeScript генерирует JavaScript-код.
diff --git a/ru-ru/vim-ru.html.markdown b/ru-ru/vim-ru.html.markdown
index f43f99eb..60b381e7 100644
--- a/ru-ru/vim-ru.html.markdown
+++ b/ru-ru/vim-ru.html.markdown
@@ -10,7 +10,7 @@ lang: ru-ru
---
[Vim](http://www.vim.org)
-(Vi IMproved) это клон полулярного текстового редактора для Unix. Он разработан
+(Vi IMproved) это клон популярного текстового редактора для Unix. Он разработан
с целью повышения скорости и продуктивности и повсеместно используется в
большинство Юникс-подобных систем. В нем имеется множество клавиатурных
сочетаний для быстрой навигации к определенным точкам в файле и быстрого
@@ -167,8 +167,8 @@ Vim можно рассматривать как набор команд в фо
## Макросы
Макросы это просто записываемые действия.
-Во время записи макросы запоминают **все** действия и команды до тех пор пока
-запись не будет остановлена.При вызове макрос применяет ту же самую последовательность
+Во время записи макросы запоминают **все** действия и команды до тех пор, пока
+запись не будет остановлена. При вызове макрос применяет ту же самую последовательность
действий и команд на выделенном тексте.
```
diff --git a/ru-ru/xml-ru.html.markdown b/ru-ru/xml-ru.html.markdown
index bf3f22b0..34e17b9b 100644
--- a/ru-ru/xml-ru.html.markdown
+++ b/ru-ru/xml-ru.html.markdown
@@ -15,7 +15,7 @@ XML - это язык разметки, предназначенный для х
* XML-Синтаксис
```xml
-
+
diff --git a/ru-ru/yaml-ru.html.markdown b/ru-ru/yaml-ru.html.markdown
index ddaed2b6..693848fc 100644
--- a/ru-ru/yaml-ru.html.markdown
+++ b/ru-ru/yaml-ru.html.markdown
@@ -12,7 +12,7 @@ lang: ru-ru
YAML как язык сериализации данных предназначен прежде всего для использования людьми.
Это строгое надмножество JSON с добавлением синтаксически значимых переносов строк и
-отступов как в Python. Тем не менее, в отличие от Python, YAML запрещает
+отступов как в Python. Тем не менее в отличие от Python, YAML запрещает
использование табов для отступов.
```yaml
@@ -53,7 +53,7 @@ literal_block: |
Любые строки с большим отступом сохраняют остатки своего отступа -
эта строка будет содержать дополнительно 4 пробела.
folded_style: >
- Весь блок этого тектса будет значением 'folded_style', но в данном случае
+ Весь блок этого текста будет значением 'folded_style', но в данном случае
все символы новой строки будут заменены пробелами.
Пустые строки будут преобразованы в перенос строки.
@@ -76,7 +76,7 @@ a_nested_map:
0.25: a float key
# Ключи также могут быть сложными, например многострочными.
-# Мы используем ? с последующим пробелом чтобы обозначить начало сложного ключа.
+# Мы используем ? с последующим пробелом, чтобы обозначить начало сложного ключа.
? |
Этот ключ
который содержит несколько строк
@@ -124,7 +124,7 @@ base: &base
name: Каждый будет иметь одинаковое имя
# Регулярное выражение << называется ключом объединения независимо от типа языка.
-# Он используется чтобы показать что все ключи одного или более словарей должны быть
+# Он используется, чтобы показать что все ключи одного или более словарей должны быть
# добавлены в текущий словарь.
foo: &foo
@@ -185,5 +185,5 @@ set2:
### Больше информации
-+ [YAML оффициальный вебсайт](http://yaml.org/)
++ [YAML официальный вебсайт](http://yaml.org/)
+ [YAML онлайн валидатор](http://www.yamllint.com/)
diff --git a/ru-ru/zfs-ru.html.markdown b/ru-ru/zfs-ru.html.markdown
new file mode 100644
index 00000000..46a3fbb5
--- /dev/null
+++ b/ru-ru/zfs-ru.html.markdown
@@ -0,0 +1,406 @@
+---
+category: tool
+tool: zfs
+contributors:
+ - ["sarlalian", "http://github.com/sarlalian"]
+ - ["A1EF", "https://github.com/A1EF"]
+filename: LearnZfs-ru.txt
+translators:
+ - ["A1EF", "https://github.com/A1EF"]
+lang: ru-ru
+---
+
+
+[ZFS](http://open-zfs.org/wiki/Main_Page)
+представляет собой переосмысление системы хранения данных, комбинирующее в едином инструменте
+традиционные файловые системы и системы управления томами. ZFS обладает некоторой специфичной
+терминологией, которая отличает её от более традиционных систем хранения данных, однако имеет
+отличный набор возможностей, акцентированных на удобстве использования системными администраторами.
+
+
+## Концепции ZFS
+
+### Виртуальные устройства
+
+Виртуальное устройство (VDEV) подобно устройству RAID, представляемого RAID-контроллером.
+Есть несколько типов виртуальных устройств (VDEV), которые предлагают различные преимущества,
+включая отказоустойчивость и скорость доступа. В основном виртуальные устройства (VDEV)
+предоставляют лучшую отказоустойчивость и безопасность, нежели RAID-контроллеры. Не рекомендуется
+использовать установку RAID с ZFS, поскольку ZFS рассчитывает непосредственно управлять дисками.
+
+Типы виртуальных устройств (VDEV)
+
+* mirror (поддерживается n-кратное зеркалирование)
+* raidz
+ * raidz1 (1-диск четности, аналог RAID 5)
+ * raidz2 (2-диска четности, аналог RAID 6)
+ * raidz3 (3-диска четности, нет имеет аналогичного RAID-массива)
+* disk
+* file (не рекомендовано для промышленного применения из-за добавления нежелательного промежуточного слоя иной файловой системы)
+
+Ваши данные распределяются среди всех виртуальных устройств (VDEV), представленных в пуле хранения,
+так что увеличив число виртуальных устройств (VDEV), вы увеличите количество IOPS.
+
+### Пулы хранения
+
+ZFS использует пулы хранения как абстракцию над нижним уровнем провайдера хранения (VDEV), позволяя вам отделить видимые пользователю
+файловые системы от физического их размещения.
+
+### ZFS датасеты
+
+ZFS датасеты подобны традиционным файловым системам, но имеют гораздо больше возможностей, обеспечивающих обилие преимуществ ZFS.
+Датасеты поддерживают [Copy on Write](https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B8_%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D0%B8), снапшоты, квоты, сжатие и дедубликацию.
+
+
+### Ограничения
+
+Один каталог может содержать до 2^48 файлов, каждый до 16 эксабайт. Один пул хранения может содержать до 256 зеттабайт (2^78) данных
+и может быть распределён по 2^64 устройствам. А один хост может иметь 2^64 пула хранения. Лимиты огромны.
+
+
+## Команды
+
+### Пулы хранения
+
+Действия:
+
+* Просмотр
+* Статус
+* Удаление
+* Получение/установка свойств
+
+Просмотр пулов
+
+```bash
+# Создание пула типа raidz
+$ zpool create zroot raidz1 gpt/zfs0 gpt/zfs1 gpt/zfs2
+
+# Просмотр пулов
+$ zpool list
+NAME SIZE ALLOC FREE EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
+zroot 141G 106G 35.2G - 43% 75% 1.00x ONLINE -
+
+# Просмотр детализованной информации о конкретном пуле
+$ zpool list -v zroot
+NAME SIZE ALLOC FREE EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
+zroot 141G 106G 35.2G - 43% 75% 1.00x ONLINE -
+ gptid/c92a5ccf-a5bb-11e4-a77d-001b2172c655 141G 106G 35.2G - 43% 75%
+```
+
+Статус пулов
+
+```bash
+# Получение информации о статусе пулов
+$ zpool status
+ pool: zroot
+ state: ONLINE
+ scan: scrub repaired 0 in 2h51m with 0 errors on Thu Oct 1 07:08:31 2015
+config:
+
+ NAME STATE READ WRITE CKSUM
+ zroot ONLINE 0 0 0
+ gptid/c92a5ccf-a5bb-11e4-a77d-001b2172c655 ONLINE 0 0 0
+
+errors: No known data errors
+
+# Скрабинг пула для исправления любых ошибок
+$ zpool scrub zroot
+$ zpool status -v zroot
+ pool: zroot
+ state: ONLINE
+ scan: scrub in progress since Thu Oct 15 16:59:14 2015
+ 39.1M scanned out of 106G at 1.45M/s, 20h47m to go
+ 0 repaired, 0.04% done
+config:
+
+ NAME STATE READ WRITE CKSUM
+ zroot ONLINE 0 0 0
+ gptid/c92a5ccf-a5bb-11e4-a77d-001b2172c655 ONLINE 0 0 0
+
+errors: No known data errors
+```
+
+Свойства пулов
+
+```bash
+
+# Получение свойств пула, свойства могут быть заданы пользователем или системой.
+$ zpool get all zroot
+NAME PROPERTY VALUE SOURCE
+zroot size 141G -
+zroot capacity 75% -
+zroot altroot - default
+zroot health ONLINE -
+...
+
+# Установка значения свойства пула
+$ zpool set comment="Storage of mah stuff" zroot
+$ zpool get comment
+NAME PROPERTY VALUE SOURCE
+tank comment - default
+zroot comment Storage of mah stuff local
+```
+
+Удаление пула
+
+```bash
+$ zpool destroy test
+```
+
+
+### Датасеты
+
+Действия:
+
+* Создание
+* Просмотр
+* Переименование
+* Удаление
+* Получение/установка свойств
+
+Создание датасетов
+
+```bash
+# Создание датасета
+$ zfs create zroot/root/data
+$ mount | grep data
+zroot/root/data on /data (zfs, local, nfsv4acls)
+
+# Создание дочернего датасета
+$ zfs create zroot/root/data/stuff
+$ mount | grep data
+zroot/root/data on /data (zfs, local, nfsv4acls)
+zroot/root/data/stuff on /data/stuff (zfs, local, nfsv4acls)
+
+
+# Создание тома
+$ zfs create -V zroot/win_vm
+$ zfs list zroot/win_vm
+NAME USED AVAIL REFER MOUNTPOINT
+zroot/win_vm 4.13G 17.9G 64K -
+```
+
+Просмотр датасетов
+
+```bash
+# Просмотр всех датасетов
+$ zfs list
+NAME USED AVAIL REFER MOUNTPOINT
+zroot 106G 30.8G 144K none
+zroot/ROOT 18.5G 30.8G 144K none
+zroot/ROOT/10.1 8K 30.8G 9.63G /
+zroot/ROOT/default 18.5G 30.8G 11.2G /
+zroot/backup 5.23G 30.8G 144K none
+zroot/home 288K 30.8G 144K none
+...
+
+# Просмотр конкретного датасета
+$ zfs list zroot/home
+NAME USED AVAIL REFER MOUNTPOINT
+zroot/home 288K 30.8G 144K none
+
+# Просмотр снапшотов
+$ zfs list -t snapshot
+zroot@daily-2015-10-15 0 - 144K -
+zroot/ROOT@daily-2015-10-15 0 - 144K -
+zroot/ROOT/default@daily-2015-10-15 0 - 24.2G -
+zroot/tmp@daily-2015-10-15 124K - 708M -
+zroot/usr@daily-2015-10-15 0 - 144K -
+zroot/home@daily-2015-10-15 0 - 11.9G -
+zroot/var@daily-2015-10-15 704K - 1.42G -
+zroot/var/log@daily-2015-10-15 192K - 828K -
+zroot/var/tmp@daily-2015-10-15 0 - 152K -
+```
+
+Переименование датасетов
+
+```bash
+$ zfs rename zroot/root/home zroot/root/old_home
+$ zfs rename zroot/root/new_home zroot/root/home
+```
+
+Удаление датасета
+
+```bash
+# Датасеты не могут быть удалены, если у них имеются какие-то снапшоты
+$ zfs destroy zroot/root/home
+```
+
+Получение / установка свойств датасета
+
+```bash
+# Получение всех свойств
+$ zfs get all zroot/usr/home
+NAME PROPERTY VALUE SOURCE
+zroot/home type filesystem -
+zroot/home creation Mon Oct 20 14:44 2014 -
+zroot/home used 11.9G -
+zroot/home available 94.1G -
+zroot/home referenced 11.9G -
+zroot/home mounted yes -
+...
+
+# Получения свойства для датасета
+$ zfs get compression zroot/usr/home
+NAME PROPERTY VALUE SOURCE
+zroot/home compression off default
+
+# Установка значения свойства на датасете
+$ zfs set compression=lz4 zroot/lamb
+
+# Получение значений выбранных свойств всех датасетов
+$ zfs list -o name,quota,reservation
+NAME QUOTA RESERV
+zroot none none
+zroot/ROOT none none
+zroot/ROOT/default none none
+zroot/tmp none none
+zroot/usr none none
+zroot/home none none
+zroot/var none none
+...
+```
+
+
+### Снапшоты
+
+ZFS снапшоты -- одна из очень важных особенностей zfs
+
+* Место, которое они занимают, равно разнице данных между файловой системой и её снапшотом
+* Время создания занимает считанные секунды
+* Восстановление настолько быстро, насколько позволяет вам запись данных
+* Они очень просты в автоматизации
+
+Действия:
+
+* Создание
+* Удаление
+* Переименование
+* Получение доступа к снапшотам
+* Отправка / Получение
+* Клонирование
+
+
+Создание снапшотов
+
+```bash
+# Создание снапшота единственного датасета
+zfs snapshot zroot/home/sarlalian@now
+
+# Создание снапшота для родительского и дочерних датасетов
+$ zfs snapshot -r zroot/home@now
+$ zfs list -t snapshot
+NAME USED AVAIL REFER MOUNTPOINT
+zroot/home@now 0 - 26K -
+zroot/home/sarlalian@now 0 - 259M -
+zroot/home/alice@now 0 - 156M -
+zroot/home/bob@now 0 - 156M -
+...
+```
+
+Удаление снапшотов
+
+```bash
+# Как удалить снапшот
+$ zfs destroy zroot/home/sarlalian@now
+
+# Удаление снапшота в родительском и дочерних датасетах
+$ zfs destroy -r zroot/home/sarlalian@now
+
+```
+
+Переименование снапшотов
+
+```bash
+# Переименование снапшота
+$ zfs rename zroot/home/sarlalian@now zroot/home/sarlalian@today
+$ zfs rename zroot/home/sarlalian@now today
+
+$ zfs rename -r zroot/home@now @yesterday
+```
+
+Получение доступа к спапшотам
+
+```bash
+# CD в каталог снапшота
+$ cd /home/.zfs/snapshot/
+```
+
+Отправка и получение
+
+```bash
+# Сохранение снапшота в файл
+$ zfs send zroot/home/sarlalian@now | gzip > backup_file.gz
+
+# Отправка снапшота в другой датасет
+$ zfs send zroot/home/sarlalian@now | zfs recv backups/home/sarlalian
+
+# Отправка снапшота на удаленный хост
+$ zfs send zroot/home/sarlalian@now | ssh root@backup_server 'zfs recv zroot/home/sarlalian'
+
+# Отправка полного датасета со снапшотами на новый хост
+$ zfs send -v -R zroot/home@now | ssh root@backup_server 'zfs recv zroot/home'
+```
+
+Клонирование снапшотов
+
+```bash
+# Клонирование снапшота
+$ zfs clone zroot/home/sarlalian@now zroot/home/sarlalian_new
+
+# Повышение клона, чтобы он больше не зависел от снапшота
+$ zfs promote zroot/home/sarlalian_new
+```
+
+### Собираем всё вместе
+
+Нижеследующий скрипт использует FreeBSD, jails и ZFS для автоматизации
+подготовки чистой копии стейджинговой базы mysql с живой реплики слейв-ноды.
+
+```bash
+#!/bin/sh
+
+echo "==== Остановка стейджингового сервера баз данных ===="
+jail -r staging
+
+echo "==== Очистка существующих стейджингового сервера и снапшота ===="
+zfs destroy -r zroot/jails/staging
+zfs destroy zroot/jails/slave@staging
+
+echo "==== Фиксация базы на слейве ===="
+echo "FLUSH TABLES WITH READ LOCK;" | /usr/local/bin/mysql -u root -pmyrootpassword -h slave
+
+echo "==== Сохранение снапшота файлов базы слейва как zroot/jails/slave@staging ===="
+zfs snapshot zroot/jails/slave@staging
+
+echo "==== Запуск слейв-ноды сервера баз данных ===="
+jail -c slave
+
+echo "==== Клонирование снапшота слейва на стейджинговый сервер ===="
+zfs clone zroot/jails/slave@staging zroot/jails/staging
+
+echo "==== Установка конфига стейджингово mysql ===="
+mv /jails/staging/usr/local/etc/my.cnf /jails/staging/usr/local/etc/my.cnf.slave
+cp /jails/staging/usr/local/etc/my.cnf.staging /jails/staging/usr/local/etc/my.cnf
+
+echo "==== Настройка стейджингового файла rc.conf ===="
+mv /jails/staging/etc/rc.conf.local /jails/staging/etc/rc.conf.slave
+mv /jails/staging/etc/rc.conf.staging /jails/staging/etc/rc.conf.local
+
+echo "==== Запуск стейджингово сервера баз данных ===="
+jail -c staging
+
+echo "==== Отключение синхронизации стейджинговой базы с мастером ===="
+echo "STOP SLAVE;" | /usr/local/bin/mysql -u root -pmyrootpassword -h staging
+echo "RESET SLAVE;" | /usr/local/bin/mysql -u root -pmyrootpassword -h staging
+```
+
+
+### Почитать дополнительно
+
+* [BSDNow's Crash Course on ZFS](http://www.bsdnow.tv/tutorials/zfs)
+* [FreeBSD Handbook on ZFS](https://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/zfs.html)
+* [BSDNow's Crash Course on ZFS](http://www.bsdnow.tv/tutorials/zfs)
+* [Oracle's Tuning Guide](http://www.oracle.com/technetwork/articles/servers-storage-admin/sto-recommended-zfs-settings-1951715.html)
+* [OpenZFS Tuning Guide](http://open-zfs.org/wiki/Performance_tuning)
+* [FreeBSD ZFS Tuning Guide](https://wiki.freebsd.org/ZFSTuningGuide)
diff --git a/rust.html.markdown b/rust.html.markdown
index c677ed96..526d20d5 100644
--- a/rust.html.markdown
+++ b/rust.html.markdown
@@ -30,6 +30,9 @@ Rust not only fast, but also easy and efficient to code in.
// This is a comment. Line comments look like this...
// and extend multiple lines like this.
+/* Block comments
+ /* can be nested. */ */
+
/// Documentation comments look like this and support markdown notation.
/// # Examples
///
diff --git a/sed.html.markdown b/sed.html.markdown
new file mode 100644
index 00000000..3e6d8fc8
--- /dev/null
+++ b/sed.html.markdown
@@ -0,0 +1,285 @@
+---
+category: tool
+tool: sed
+filename: learnsed.sed
+contributors:
+ - ["Diomidis Spinellis", "https://www.spinellis.gr"]
+
+---
+
+__Sed__ is a standard tool on every POSIX-compliant UNIX system.
+It's like an editor, such as Vim, Visual Studio Code, Atom, or Sublime.
+However, rather than typing the commands interactively, you
+provide them on the command line or in a file.
+
+_Sed_'s advantages over an interactive editor is that it can be easily
+used to automate text processing tasks, and that it can process
+efficiently huge (terabyte-sized) files.
+It can perform more complex tasks than _grep_ and for many text
+processing tasks its commands are much shorter than what you would
+write in _awk_, _Perl_, or _Python_.
+
+_Sed_ works by reading a line of text (by default from its standard
+input, unless some files are specified as arguments), processing
+it with the specified commands, and then outputting the result
+on its standard output.
+You can suppress the default output by specifying the `-n` command-line
+argument.
+
+```perl
+#!/usr/bin/sed -f
+# Files that begin with the above line and are given execute permission
+# can be run as regular scripts.
+
+# Comments are like this.
+
+# Commands consist of a single letter and many can be preceded
+# by a specification of the lines to which they apply.
+
+# Delete the input's third line.
+3d
+
+# The same command specified the command line as an argument to sed:
+# sed 3d
+
+# For many commands the specification can consist of two addresses,
+# which select an inclusive range.
+# Addresses can be specified numerically ($ is the last line) or through
+# regular expressions delimited by /.
+
+# Delete lines 1-10
+1,10d
+
+# Lines can also be specified as regular expressions, delimited by /.
+
+# Delete empty lines.
+/^$/d
+
+# Delete blocks starting with SPOILER-BEGIN and ending with SPOILER-END.
+/SPOILER-BEGIN/,/SPOILER-END/d
+
+# A command without an address is applied to all lines.
+
+# List lines in in a visually unambiguous form (e.g. tab appears as \t).
+l
+
+# A command prefixed by ! will apply to non-matching lines.
+# Keep only lines starting with a #.
+/^#/!d
+
+# Below are examples of the most often-used commands.
+
+# Substitute the first occurence in a line of John with Mary.
+s/John/Mary/
+
+# Remove all underscore characters (global substitution).
+s/_//g
+
+# Remove all HTML tags.
+s/<[^>]*>//g
+
+# In the replacement string & is the regular expression matched.
+
+# Put each line inside double quotes.
+s/.*/"&"/
+
+# In the matched regular expression \(pattern\) is used to store
+# a pattern into a buffer.
+# In the replacement string \1 refers to the first pattern, \2 to the second
+# and so on. \u converts the following character to uppercase \l to lowercase.
+
+# Convert snake_case_identifiers into camelCaseIdentifiers.
+s/_\(.\)/\u\1/g
+
+
+# The p (print) command is typically used together with the -n
+# command-line option, which disables the print by default functionality.
+# Output all lines between ``` and ```.
+/```/,/```/p
+
+
+# The y command maps characters from one set to another.
+# Swap decimal and thousand separators (1,234,343.55 becomes 1.234.343,55).
+y/.,/,./
+
+# Quit after printing the line starting with END.
+/^END/q
+
+# You can stop reading here, and still get 80% of sed's benefits.
+# Below are examples of how you can specify multiple sed commands.
+
+# You can apply multiple commands by separating them with a newline or
+# a semicolon.
+
+# Delete the first and the last line.
+1d
+$d
+
+# Delete the first and the last line.
+1d;$d
+
+
+# You can group commands in { } blocks.
+
+# Convert first line to uppercase and print it.
+1 {
+ s/./\u&/g
+ p
+}
+
+# Convert first line to uppercase and print it (less readable one-liner).
+1{s/./\u&/g;p;}
+
+
+# You can also stop reading here, if you're not interested in creating
+# sed script files.
+
+# Below are more advanced commands. You typically put these in a file
+# rather than specify them on a command line. If you have to use
+# many of these commands in a script, consider using a general purpose
+# scripting language, such as Python or Perl.
+
+# Append a line containing "profile();" after each line ending with ";".
+/;$/a\
+profile();
+
+# Insert a line containing "profile();" before each line ending with ";".
+/;$/i\
+profile();
+
+# Change each line text inside REDACTED blocks into [REDACTED].
+/REDACTED-BEGIN/,/REDACTED-END/c\
+[REDACTED]
+
+# Replace the tag "" by reading and outputting the file style.css.
+// {
+ r style.css
+ d
+}
+
+# Change each line inside REDACTED blocks into [REDACTED].
+# Also write (append) a copy of the redacted text in the file redacted.txt.
+/REDACTED-BEGIN/,/REDACTED-END/ {
+ w redacted.txt
+ c\
+ [REDACTED]
+}
+
+# All operations described so far operate on a buffer called "pattern space".
+# In addition, sed offers another buffer called "hold space".
+# The following commands operate on the two, and can be used to keep
+# state or combine multiple lines.
+
+# Replace the contents of the pattern space with the contents of
+# the hold space.
+g
+
+# Append a newline character followed by the contents of the hold
+# space to the pattern space.
+G
+
+# Replace the contents of the hold space with the contents of the
+# pattern space.
+h
+
+# Append a newline character followed by the contents of the
+# pattern space to the hold space.
+H
+
+# Delete the initial segment of the pattern space through the first
+# newline character and start the next cycle.
+D
+
+# Replace the contents of the pattern space with the contents of
+# the hold space.
+g
+
+# Append a newline character followed by the contents of the hold
+# space to the pattern space.
+G
+
+# Replace the contents of the hold space with the contents of the
+# pattern space.
+h
+
+# Append a newline character followed by the contents of the
+# pattern space to the hold space.
+H
+
+# Write the pattern space to the standard output if the default
+# output has not been suppressed, and replace the pattern space
+# with the next line of input.
+n
+
+# Append the next line of input to the pattern space, using an
+# embedded newline character to separate the appended material from
+# the original contents. Note that the current line number
+# changes.
+N
+
+# Write the pattern space, up to the first newline character to the
+# standard output.
+P
+
+# Swap the contents of the pattern and hold spaces.
+x
+
+# Here is a complete example of some of the buffer commands.
+# Move the file's first line to its end.
+1 {
+ h
+ d
+}
+
+$ {
+ p
+ x
+}
+
+
+# Three sed commands influence a script's control flow
+
+# Name this script position "my_label", to which the "b" and
+# "t" commands may branch.
+:my_label
+
+# Continue executing commands from the position of my_label.
+b my_label
+
+# Branch to the end of the script.
+b
+
+# Branch to my_label if any substitutions have been made since the most
+# recent reading of an input line or execution of a "t" (test) function.
+t my_label
+
+# Here is a complete example of branching
+# Join lines that end with a backspace into a single space-separated one
+
+# Name this position "loop"
+: loop
+# On lines ending with a backslash
+/\\$/ {
+ # Read the next line and append it to the pattern space
+ N
+ # Substitute backslash newline with a space
+ s/\\\n/ /
+ # Branch to the top for testing this line's ending
+ b loop
+}
+```
+
+Further Reading:
+
+* [The Open Group: sed - stream editor](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html)
+ The POSIX standard regarding sed.
+ Follow this for maximum portability.
+* [FreeBSD sed -- stream editor](https://www.freebsd.org/cgi/man.cgi?query=sed&sektion=&n=1)
+ The BSD manual page.
+ This version of sed runs on BSD systems and macOS.
+* [Project GNU: sed, a stream editor](https://www.gnu.org/software/sed/manual/sed.html)
+ The GNU manual page. GNU sed is found on most Linux systems.
+* [Lee E. McMahon: SED -- A Non-interactive Text Editor](https://wolfram.schneider.org/bsd/7thEdManVol2/sed/sed.pdf)
+ The original sed documentation
+* [A collection of sed resources](http://sed.sourceforge.net/)
+* [The sed FAQ](http://sed.sourceforge.net/sedfaq.html)
diff --git a/set-theory.html.markdown b/set-theory.html.markdown
index f89345c0..144b4bbf 100644
--- a/set-theory.html.markdown
+++ b/set-theory.html.markdown
@@ -2,7 +2,9 @@
category: Algorithms & Data Structures
name: Set theory
contributors:
+ - ["Andrew Ryan Davis", "https://github.com/AndrewDavis1191"]
---
+
Set theory is a branch of mathematics that studies sets, their operations, and their properties.
* A set is a collection of disjoint items.
@@ -59,7 +61,7 @@ Long lists may be shortened with ellipses as long as the context is clear. For e
Set builder notation is a more descriptive way of constructing a set. It relies on a _subject_ and a _predicate_ such that `S = { subject : predicate }`. For example,
```
-A = { x : x is a vowel } = { a, e, i, o, u, y}
+A = { x : x is a vowel } = { a, e, i, o, u }
B = { x : x ∈ N, x < 10 } = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
C = { x : x = 2k, k ∈ N } = { 0, 2, 4, 6, 8, ... }
```
diff --git a/sk-sk/latex-sk.html.markdown.tex b/sk-sk/latex-sk.html.markdown
similarity index 100%
rename from sk-sk/latex-sk.html.markdown.tex
rename to sk-sk/latex-sk.html.markdown
diff --git a/sk-sk/learn-latex-sk.tex b/sk-sk/learn-latex-sk.tex
deleted file mode 100644
index 5cc7b11f..00000000
--- a/sk-sk/learn-latex-sk.tex
+++ /dev/null
@@ -1,209 +0,0 @@
-% Všetky komentáre začínajú s %
-% Viac-riadkové komentáre sa nedajú urobiť
-
-% LaTeX NIE JE WYSIWY ("What You See Is What You Get") software ako MS Word, alebo OpenOffice Writer
-
-% Každý LaTeX príkaz začína s opačným lomítkom (\)
-
-% LaTeX dokumenty začínajú s definíciou typu kompilovaného dokumentu
-% Ostatné typy sú napríklad kniha (book), správa (report), prezentácia (presentation), atď.
-% Možnosti dokumentu sa píšu do [] zátvoriek. V tomto prípade tam upresňujeme veľkosť (12pt) fontu.
-\documentclass[12pt]{article}
-
-% Ďalej definujeme balíčky, ktoré dokuemnt používa.
-% Ak chceš zahrnúť grafiku, farebný text, či zdrojový kód iného jazyka, musíš rozšíriť možnosti LaTeXu dodatočnými balíčkami.
-% Zahŕňam float a caption. Na podporu slovenčiny treba zahrnúť aj utf8 balíček.
-\usepackage{caption}
-\usepackage{float}
-\usepackage[utf8]{inputenc}
-% Tu môžme definovať ostatné vlastnosti dokumentu!
-% Autori tohto dokumentu, "\\*" znamená "choď na nový riadok"
-\author{Chaitanya Krishna Ande, Colton Kohnke \& Sricharan Chiruvolu, \\*Preklad: Terka Slanináková}
-% Vygeneruje dnešný dátum
-\date{\today}
-\title{Nauč sa LaTeX za Y Minút!}
-% Teraz môžme začať pracovať na samotnom dokumente.
-% Všetko do tohto riadku sa nazýva "Preambula" ("The Preamble")
-\begin{document}
-% ak zadáme položky author, date a title, LaTeX vytvorí titulnú stranu.
-\maketitle
-
-% Väčšina odborných článkov má abstrakt, na jeho vytvorenie môžeš použiť preddefinované príkazy.
-% Ten by sa mal zobraziť v logickom poradí, teda po hlavičke,
-% no pred hlavnými sekciami tela..
-% Tento príkaz je tiež dostupný v triedach article a report.
-% Tzv. makro "abstract" je fixnou súčasťou LaTeXu, ak chceme použiť abstract
-% a napísať ho po slovensky, musíme ho redefinovať nasledujúcim príkazom
-\renewcommand\abstractname{Abstrakt}
-
-\begin{abstract}
-LaTeX dokumentácia v LaTeXe! Aké netradičné riešenie cudzieho nápadu!
-\end{abstract}
-
-% Príkazy pre sekciu sú intuitívne
-% Všetky nadpisy sekcií sú pridané automaticky do obsahu.
-\section{Úvod}
-Čaute, volám sa Colton a spoločne sa pustíme do skúmania LaTeXu (toho druhého)!
-
-\section{Ďalšia sekcia}
-Toto je text ďalšej sekcie. Myslím, že potrebuje podsekciu.
-
-\subsection{Toto je podsekcia} % Podsekcie sú tiež intuitívne.
-Zdá sa mi, že treba ďalšiu.
-
-\subsubsection{Pytagoras}
-To je ono!
-\label{subsec:pytagoras}
-
-% Použitím '*' môžeme potlačiť zabudované číslovanie LaTeXu.
-% Toto funguje aj na iné príkazy.
-\section*{Toto je nečíslovaná sekcia}
-Všetky číslované byť nemusia!
-
-\section{Nejaké poznámočky}
-Zarovnávať veci tam, kde ich chceš mať, je všeobecne ľahké. Ak
-potrebuješ \\ nový \\ riadok \\ pridaj \textbackslash\textbackslash do
-zdrojového kódu. \\
-
-\section{Zoznamy}
-Zoznamy sú jednou z najjednoduchších vecí vôbec! Treba mi zajtra nakúpiť, urobím si zoznam.
-\begin{enumerate} % "enumerate" spustí číslovanie prvkov.
- % \item povie LaTeXu, ako že treba pripočítať 1
- \item Vlašský šalát.
- \item 5 rožkov.
- \item 3 Horalky.
- % číslovanie môžeme pozmeniť použitím []
- \item[koľko?] Stredne veľkých guličkoviek.
-
- Ja už nie som položka zoznamu, no stále som časť "enumerate".
-
-\end{enumerate} % Všetky prostredia končia s "end".
-
-\section{Matika}
-
-Jedným z primárnych použití LaTeXu je písanie akademických, či technických prác. Zvyčajne za použitia matematiky a vedy. Podpora špeciálnych symbolov preto nemôže chýbať!\\
-
-Matematika má veľa symbolov, omnoho viac, než by klávesnica mohla reprezentovať;
-Množinové a relačné symboly, šípky, operátory a Grécke písmená sú len malou ukážkou.\\
-
-Množiny a relácie hrajú hlavnú rolu v mnohých matematických článkoch.
-Takto napíšeš, že niečo platí pre všetky x patriace do X, $\forall$ x $\in$ X. \\
-% Všimni si, že som pridal $ pred a po symboloch. Je to
-% preto, lebo pri písaní sme v textovom móde,
-% no matematické symboly existujú len v matematickom.
-% Vstúpime doňho z textového práve '$' znamienkami.
-% Platí to aj opačne. Premenná môže byť zobrazená v matematickom móde takisto.
-% Do matematického módu sa dá dostať aj s \[\]
-
-\[a^2 + b^2 = c^2 \]
-
-Moje obľúbené Grécke písmeno je $\xi$. Tiež sa mi pozdávajú $\beta$, $\gamma$ a $\sigma$.
-Ešte som neprišiel na Grécke písmeno, ktoré by LaTeX nepoznal!
-
-Operátory sú dôležitou súčasťou matematických dokumentov:
-goniometrické funkcie ($\sin$, $\cos$, $\tan$),
-logaritmy and exponenciálne výrazy ($\log$, $\exp$),
-limity ($\lim$), atď.
-majú pred-definované LaTeXové príkazy.
-Napíšme si rovnicu, nech vidíme, ako to funguje: \\
-
-$\cos(2\theta) = \cos^{2}(\theta) - \sin^{2}(\theta)$
-
-Zlomky(Čitateľ-menovateľ) sa píšu v týchto formách:
-
-% 10 / 7
-$^{10}/_{7}$
-
-% Relatívne komplexné zlomky sa píšu ako
-% \frac{čitateľ}{menovateľ}
-$\frac{n!}{k!(n - k)!}$ \\
-
-Rovnice tiež môžeme zadať v "rovnicovom prostredí".
-
-% Takto funguje rovnicové prostredie
-\begin{equation} % vstúpi do matematického módu
- c^2 = a^2 + b^2.
- \label{eq:pythagoras} % na odkazovanie
-\end{equation} % všetky \begin príkazy musia mať konečný príkaz.
-
-Teraz môžeme odkázať na novovytvorenú rovnicu!
-Rovn.~\ref{eq:pythagoras} je tiež známa ako Pytagorova Veta, ktorá je tiež predmetom Sekc.~\ref{subsec:pytagoras}. Odkazovať môžme na veľa vecí, napr na: čísla, rovnice, či sekcie.
-
-Sumácie a Integrály sa píšu príkazmi sum a int:
-
-% Niektoré prekladače LaTeXu sa môžu sťažovať na prázdne riadky (ak tam sú)
-% v rovnicovom prostredí.
-\begin{equation}
- \sum_{i=0}^{5} f_{i}
-\end{equation}
-\begin{equation}
- \int_{0}^{\infty} \mathrm{e}^{-x} \mathrm{d}x
-\end{equation}
-
-\section{Obrázky}
-
-Vloženie obrázku môže byť zložitejšie. Ja si vždy možnosti vloženia pozerám pre každý obrázok.
-\renewcommand\figurename{Obrázok}
-\begin{figure}[H] % H značí možnosť zarovnania.
- \centering % nacentruje obrázok na stránku
- % Vloží obrázok na 80% šírky stránky.
- %\includegraphics[width=0.8\linewidth]{right-triangle.png}
- % Zakomentované kvôli kompilácií, použi svoju predstavivosť :).
- \caption{Pravouhlý trojuholník so stranami $a$, $b$, $c$}
- \label{fig:right-triangle}
-\end{figure}
-% Opäť, fixné makro "table" nahradíme slovenskou tabuľkou. Pokiaľ preferuješ table, nasledujúci riadok nepridávaj
-\renewcommand\tablename{Tabuľka}
-
-\subsection{Tabuľky}
-Tabuľky sa vkládajú podobne ako obrázky.
-
-\begin{table}[H]
- \caption{Nadpis tabuľky.}
- % zátvorky: {} hovoria ako sa vykreslí každý riadok.
- % Toto si nikdy nepamätám a vždy to musím hľadať. Všetko. Každý. Jeden. Raz!
- \begin{tabular}{c|cc}
- Číslo & Priezvisko & Krstné meno \\ % Stĺpce sú rozdelené $
- \hline % horizontálna čiara
- 1 & Ladislav & Meliško \\
- 2 & Eva & Máziková
- \end{tabular}
-\end{table}
-
-% \section{Hyperlinks} % Už čoskoro :)
-
-\section{Prikáž LaTeXu nekompilovať (napr. Zdrojový Kód)}
-Povedzme, že chceme do dokumentu vložiť zdrojový kód, budeme musieť LaTeXu povedať, nech sa ho nesnaží skompilovať, ale nech s ním pracuje ako s textom.
-Toto sa robí vo verbatim prostredí.
-
-% Tiež sú na to špeciálne balíčky, (napr. minty, lstlisting, atď.)
-% ale verbatim je to najzákladnejšie, čo môžeš použiť.
-\begin{verbatim}
- print("Hello World!")
- a%b; pozri! Vo verbatime môžme použiť % znamienka.
- random = 4; #priradené randomným hodom kockou
-\end{verbatim}
-
-\section{Kompilácia}
-
-Už by bolo načase túto nádheru skompilovať a zhliadnuť jej úžasnú úžasnosť v podobe LaTeX pdfka, čo povieš?
-(áno, tento dokument sa musí kompilovať). \\
-Cesta k finálnemu dokumentu pomocou LaTeXu pozostáva z nasledujúcich krokov:
- \begin{enumerate}
- \item Napíš dokument v čistom texte (v "zdrojáku").
- \item Skompiluj zdroják na získanie pdfka.
- Kompilácia by mala vyzerať nasledovne (v Linuxe): \\
- \begin{verbatim}
- $pdflatex learn-latex.tex learn-latex.pdf
- \end{verbatim}
- \end{enumerate}
-
-Mnoho LaTeX editorov kombinuje Krok 1 a Krok 2 v jednom prostredí. Krok 1 teda uvidíš, krok 2 už nie.
-Ten sa deje za oponou. Kompilácia v 2. kroku sa postará o produkciu dokumentu v tebou zadanom formáte.
-
-\section{Koniec}
-
-To je zatiaľ všetko!
-
-% koniec dokumentu
-\end{document}
diff --git a/sl-si/asciidoc-sl.html.markdown b/sl-si/asciidoc-sl.html.markdown
index 52f30fbd..84bb85a1 100644
--- a/sl-si/asciidoc-sl.html.markdown
+++ b/sl-si/asciidoc-sl.html.markdown
@@ -6,7 +6,7 @@ contributors:
translators:
- ["Filip Štamcar", "https://github.com/filips123"]
lang: sl-si
-filename: asciidoc-sl.md
+filename: asciidoc-sl.adoc
---
AsciiDoc je označevalni jezik, ki je podoben Markdownu in ga je mogoče uporabiti za vse od knjig do spletnih dnevnikov. Jezik, ki ga je leta 2002 ustvaril Stuart Rackham, je preprost, vendar omogoča veliko prilagoditev.
diff --git a/smalltalk.html.markdown b/smalltalk.html.markdown
index d4016ecf..9c2e870e 100644
--- a/smalltalk.html.markdown
+++ b/smalltalk.html.markdown
@@ -2,16 +2,15 @@
language: Smalltalk
filename: smalltalk.st
contributors:
- - ["Jigyasa Grover", "https://github.com/jigyasa-grover"]
+ - ["Jigyasa Grover", "https://jigyasa-grover.github.io"]
- ["tim Rowledge", "tim@rowledge.org"]
---
+Every effort has been made in the preparation of this material to ensure the accuracy and completeness of the information presented. However, no guarantee is given nor responsibility taken for errors or omissions. In case of any error, questions or suggestions on reach out to me at jigyasa-grover.github.io or drop me an e-mail at grover[dot]jigyasa1[at]gmail.com.
- Smalltalk is a fully object-oriented, dynamically typed, reflective programming language with no 'non-object' types.
- Smalltalk was created as the language to underpin the "new world" of computing exemplified by "human–computer symbiosis."
- It was designed and created in part for educational use, more so for constructionist learning, at the Learning Research Group (LRG) of Xerox PARC by Alan Kay, Dan Ingalls, Adele Goldberg, Ted Kaehler, Scott Wallace, and others during the 1970s.
-`Feedback highly appreciated! Reach me at [@jigyasa_grover](https://twitter.com/jigyasa_grover) or send me an e-mail at grover.jigyasa1@gmail.com.`
-
## The Basics
### Everything is an object
@@ -162,7 +161,7 @@ b := (x < 5) xor: (y > 1). "test if one true and other false"
b := 5 between: 3 and: 12. "between (inclusive)"
b := 123 isKindOf: Number. "test if object is class or subclass of"
b := 123 isMemberOf: SmallInteger. "test if object is type of class"
-b := 123 respondsTo: sqrt. "test if object responds to message"
+b := 123 respondsTo: #sqrt. "test if object responds to message"
b := x isNil. "test if object is nil"
b := x isZero. "test if number is zero"
b := x positive. "test if number is positive"
diff --git a/sorbet.html.markdown b/sorbet.html.markdown
new file mode 100644
index 00000000..9c2e809b
--- /dev/null
+++ b/sorbet.html.markdown
@@ -0,0 +1,1040 @@
+---
+language: sorbet
+filename: learnsorbet.rb
+contributors:
+ - ["Jeremy Kaplan", "https://jdkaplan.dev"]
+---
+
+Sorbet is a type checker for Ruby. It adds syntax for method signatures that
+enable both static and runtime type checking.
+
+The easiest way to see it in action is in the playground at
+[sorbet.run](https://sorbet.run).
+
+Try copying in one of the sections below! Each top-level `class` or `module`
+is independent from the others.
+
+```ruby
+# Every file should have a "typed sigil" that tells Sorbet how strict to be
+# during static type checking.
+#
+# Strictness levels (lax to strict):
+#
+# ignore: Sorbet won't even read the file. This means its contents are not
+# visible during type checking. Avoid this.
+#
+# false: Sorbet will only report errors related to constant resolution. This is
+# the default if no sigil is included.
+#
+# true: Sorbet will report all static type errors. This is the sweet spot of
+# safety for effort.
+#
+# strict: Sorbet will require that all methods, constants, and instance
+# variables have static types.
+#
+# strong: Sorbet will no longer allow anything to be T.untyped, even
+# explicitly. Almost nothing satisfies this.
+
+# typed: true
+
+# Include the runtime type-checking library. This lets you write inline sigs
+# and have them checked at runtime (instead of running Sorbet as RBI-only).
+# These runtime checks happen even for files with `ignore` or `false` sigils.
+require 'sorbet-runtime'
+
+class BasicSigs
+ # Bring in the type definition helpers. You'll almost always need this.
+ extend T::Sig
+
+ # Sigs are defined with `sig` and a block. Define the return value type with
+ # `returns`.
+ #
+ # This method returns a value whose class is `String`. These are the most
+ # common types, and Sorbet calls them "class types".
+ sig { returns(String) }
+ def greet
+ 'Hello, World!'
+ end
+
+ # Define parameter value types with `params`.
+ sig { params(n: Integer).returns(String) }
+ def greet_repeat(n)
+ (1..n).map { greet }.join("\n")
+ end
+
+ # Define keyword parameters the same way.
+ sig { params(n: Integer, sep: String).returns(String) }
+ def greet_repeat_2(n, sep: "\n")
+ (1..n).map { greet }.join(sep)
+ end
+
+ # Notice that positional/keyword and required/optional make no difference
+ # here. They're all defined the same way in `params`.
+
+ # For lots of parameters, it's nicer to use do..end and a multiline block
+ # instead of curly braces.
+ sig do
+ params(
+ str: String,
+ num: Integer,
+ sym: Symbol,
+ ).returns(String)
+ end
+ def uhh(str:, num:, sym:)
+ 'What would you even do with these?'
+ end
+
+ # For a method whose return value is useless, use `void`.
+ sig { params(name: String).void }
+ def say_hello(name)
+ puts "Hello, #{name}!"
+ end
+
+ # Splats! Also known as "rest parameters", "*args", "**kwargs", and others.
+ #
+ # Type the value that a _member_ of `args` or `kwargs` will have, not `args`
+ # or `kwargs` itself.
+ sig { params(args: Integer, kwargs: String).void }
+ def no_op(*args, **kwargs)
+ if kwargs[:op] == 'minus'
+ args.each { |i| puts(i - 1) }
+ else
+ args.each { |i| puts(i + 1) }
+ end
+ end
+
+ # Most initializers should be `void`.
+ sig { params(name: String).void }
+ def initialize(name:)
+ # Instance variables must have annotated types to participate in static
+ # type checking.
+
+ # The value in `T.let` is checked statically and at runtime.
+ @upname = T.let(name.upcase, String)
+
+ # Sorbet can infer this one!
+ @name = name
+ end
+
+ # Constants also need annotated types.
+ SORBET = T.let('A delicious frozen treat', String)
+
+ # Class variables too.
+ @@the_answer = T.let(42, Integer)
+
+ # Sorbet knows about the `attr_*` family.
+ sig { returns(String) }
+ attr_reader :upname
+
+ sig { params(write_only: Integer).returns(Integer) }
+ attr_writer :write_only
+
+ # You say the reader part and Sorbet will say the writer part.
+ sig { returns(String) }
+ attr_accessor :name
+end
+
+module Debugging
+ extend T::Sig
+
+ # Sometimes it's helpful to know what type Sorbet has inferred for an
+ # expression. Use `T.reveal_type` to make type-checking show a special error
+ # with that information.
+ #
+ # This is most useful if you have Sorbet integrated into your editor so you
+ # can see the result as soon as you save the file.
+
+ sig { params(obj: Object).returns(String) }
+ def debug(obj)
+ T.reveal_type(obj) # Revealed type: Object
+ repr = obj.inspect
+
+ # Remember that Ruby methods can be called without arguments, so you can
+ # save a couple characters!
+ T.reveal_type repr # Revealed type: String
+
+ "DEBUG: " + repr
+ end
+end
+
+module StandardLibrary
+ extend T::Sig
+ # Sorbet provides some helpers for typing the Ruby standard library.
+
+ # Use T::Boolean to catch both `true` and `false`.
+ #
+ # For the curious, this is equivalent to
+ #
+ # T.type_alias { T.any(TrueClass, FalseClass) }
+ #
+ sig { params(str: String).returns(T::Boolean) }
+ def confirmed?(str)
+ str == 'yes'
+ end
+
+ # Remember that the value `nil` is an instance of NilClass.
+ sig { params(val: NilClass).void }
+ def only_nil(val:); end
+
+ # To avoid modifying standard library classes, Sorbet provides wrappers to
+ # support common generics.
+ #
+ # Here's the full list:
+ # * T::Array
+ # * T::Enumerable
+ # * T::Enumerator
+ # * T::Hash
+ # * T::Range
+ # * T::Set
+ sig { params(config: T::Hash[Symbol, String]).returns(T::Array[String]) }
+ def merge_values(config)
+ keyset = [:old_key, :new_key]
+ config.each_pair.flat_map do |key, value|
+ keyset.include?(key) ? value : 'sensible default'
+ end
+ end
+
+ # Sometimes (usually dependency injection), a method will accept a reference
+ # to a class rather than an instance of the class. Use `T.class_of(Dep)` to
+ # accept the `Dep` class itself (or something that inherits from it).
+ class Dep; end
+
+ sig { params(dep: T.class_of(Dep)).returns(Dep) }
+ def dependency_injection(dep:)
+ dep.new
+ end
+
+ # Blocks, procs, and lambdas, oh my! All of these are typed with `T.proc`.
+ #
+ # Limitations:
+ # 1. All parameters are assumed to be required positional parameters.
+ # 2. The only runtime check is that the value is a `Proc`. The argument types
+ # are only checked statically.
+ sig do
+ params(
+ data: T::Array[String],
+ blk: T.proc.params(val: String).returns(Integer),
+ ).returns(Integer)
+ end
+ def count(data, &blk)
+ data.sum(&blk)
+ end
+
+ sig { returns(Integer) }
+ def count_usage
+ count(["one", "two", "three"]) { |word| word.length + 1 }
+ end
+
+ # If the method takes an implicit block, Sorbet will infer `T.untyped` for
+ # it. Use the explicit block syntax if the types are important.
+ sig { params(str: String).returns(T.untyped) }
+ def implicit_block(str)
+ yield(str)
+ end
+
+ # If you're writing a DSL and will execute the block in a different context,
+ # use `bind`.
+ sig { params(num: Integer, blk: T.proc.bind(Integer).void).void }
+ def number_fun(num, &blk)
+ num.instance_eval(&blk)
+ end
+
+ sig { params(num: Integer).void }
+ def number_fun_usage(num)
+ number_fun(10) { puts digits.join }
+ end
+
+ # If the block doesn't take any parameters, don't include `params`.
+ sig { params(blk: T.proc.returns(Integer)).returns(Integer) }
+ def doubled_block(&blk)
+ 2 * blk.call
+ end
+end
+
+module Combinators
+ extend T::Sig
+ # These methods let you define new types from existing types.
+
+ # Use `T.any` when you have a value that can be one of many types. These are
+ # sometimes known as "union types" or "sum types".
+ sig { params(num: T.any(Integer, Float)).returns(Rational) }
+ def hundreds(num)
+ num.rationalize
+ end
+
+ # `T.nilable(Type)` is a convenient alias for `T.any(Type, NilClass)`.
+ sig { params(val: T.nilable(String)).returns(Integer) }
+ def strlen(val)
+ val.nil? ? -1 : val.length
+ end
+
+ # Use `T.all` when you have a value that must satisfy multiple types. These
+ # are sometimes known as "intersection types". They're most useful for
+ # interfaces (described later), but can also describe helper modules.
+
+ module Reversible
+ extend T::Sig
+ sig { void }
+ def reverse
+ # Pretend this is actually implemented
+ end
+ end
+
+ module Sortable
+ extend T::Sig
+ sig { void }
+ def sort
+ # Pretend this is actually implemented
+ end
+ end
+
+ class List
+ include Reversible
+ include Sortable
+ end
+
+ sig { params(list: T.all(Reversible, Sortable)).void }
+ def rev_sort(list)
+ # reverse from Reversible
+ list.reverse
+ # sort from Sortable
+ list.sort
+ end
+
+ def rev_sort_usage
+ rev_sort(List.new)
+ end
+
+ # Sometimes, actually spelling out the type every time becomes more confusing
+ # than helpful. Use type aliases to make them easier to work with.
+ JSONLiteral = T.type_alias { T.any(Float, String, T::Boolean, NilClass) }
+
+ sig { params(val: JSONLiteral).returns(String) }
+ def stringify(val)
+ val.to_s
+ end
+end
+
+module DataClasses
+ extend T::Sig
+ # Use `T::Struct` to create a new class with type-checked fields. It combines
+ # the best parts of the standard Struct and OpenStruct, and then adds static
+ # typing on top.
+ #
+ # Types constructed this way are sometimes known as "product types".
+
+ class Matcher < T::Struct
+ # Use `prop` to define a field with both a reader and writer.
+ prop :count, Integer
+ # Use `const` to only define the reader and skip the writer.
+ const :pattern, Regexp
+ # You can still set a default value with `default`.
+ const :message, String, default: 'Found one!'
+
+ # This is otherwise a normal class, so you can still define methods.
+
+ # You'll still need to bring `sig` in if you want to use it though.
+ extend T::Sig
+
+ sig { void }
+ def reset
+ self.count = 0
+ end
+ end
+
+ sig { params(text: String, matchers: T::Array[Matcher]).void }
+ def awk(text, matchers)
+ matchers.each(&:reset)
+ text.lines.each do |line|
+ matchers.each do |matcher|
+ if matcher.pattern =~ line
+ Kernel.puts matcher.message
+ matcher.count += 1
+ end
+ end
+ end
+ end
+
+ # Gotchas and limitations
+
+ # 1. `const` fields are not truly immutable. They don't have a writer method,
+ # but may be changed in other ways.
+ class ChangeMe < T::Struct
+ const :list, T::Array[Integer]
+ end
+
+ sig { params(change_me: ChangeMe).returns(T::Boolean) }
+ def whoops!(change_me)
+ change_me = ChangeMe.new(list: [1, 2, 3, 4])
+ change_me.list.reverse!
+ change_me.list == [4, 3, 2, 1]
+ end
+
+ # 2. `T::Struct` inherits its equality method from `BasicObject`, which uses
+ # identity equality (also known as "reference equality").
+ class Coordinate < T::Struct
+ const :row, Integer
+ const :col, Integer
+ end
+
+ sig { returns(T::Boolean) }
+ def never_equal!
+ p1 = Coordinate.new(row: 1, col: 2)
+ p2 = Coordinate.new(row: 1, col: 2)
+ p1 != p2
+ end
+
+ # Define your own `#==` method to check the fields, if that's what you want.
+ class Position < T::Struct
+ extend T::Sig
+
+ const :x, Integer
+ const :y, Integer
+
+ sig { params(other: Object).returns(T::Boolean) }
+ def ==(other)
+ # There's a real implementation here:
+ # https://github.com/tricycle/sorbet-struct-comparable
+ true
+ end
+ end
+
+ # Use `T::Enum` to define a fixed set of values that are easy to reference.
+ # This is especially useful when you don't care what the values _are_ as much
+ # as you care that the set of possibilities is closed and static.
+ class Crayon < T::Enum
+ extend T::Sig
+
+ # Initialize members with `enums`.
+ enums do
+ # Define each member with `new`. Each of these is an instance of the
+ # `Crayon` class.
+ Red = new
+ Orange = new
+ Yellow = new
+ Green = new
+ Blue = new
+ Violet = new
+ Brown = new
+ Black = new
+ # The default value of the enum is its name in all-lowercase. To change
+ # that, pass a value to `new`.
+ Gray90 = new('light-gray')
+ end
+
+ sig { returns(String) }
+ def to_hex
+ case self
+ when Red then '#ff0000'
+ when Green then '#00ff00'
+ # ...
+ else '#ffffff'
+ end
+ end
+ end
+
+ sig { params(crayon: Crayon, path: T::Array[Position]).void }
+ def draw(crayon:, path:)
+ path.each do |pos|
+ Kernel.puts "(#{pos.x}, #{pos.y}) = " + crayon.to_hex
+ end
+ end
+
+ # To get all the values in the enum, use `.values`. For convenience there's
+ # already a `#serialize` to get the enum string value.
+
+ sig { returns(T::Array[String]) }
+ def crayon_names
+ Crayon.values.map(&:serialize)
+ end
+
+ # Use the "deserialize" family to go from string to enum value.
+
+ sig { params(name: String).returns(T.nilable(Crayon)) }
+ def crayon_from_name(name)
+ if Crayon.has_serialized?(name)
+ # If the value is not found, this will raise a `KeyError`.
+ Crayon.deserialize(name)
+ end
+
+ # If the value is not found, this will return `nil`.
+ Crayon.try_deserialize(name)
+ end
+end
+
+module FlowSensitivity
+ extend T::Sig
+ # Sorbet understands Ruby's control flow constructs and uses that information
+ # to get more accurate types when your code branches.
+
+ # You'll see this most often when doing nil checks.
+ sig { params(name: T.nilable(String)).returns(String) }
+ def greet_loudly(name)
+ if name.nil?
+ 'HELLO, YOU!'
+ else
+ # Sorbet knows that `name` must be a String here, so it's safe to call
+ # `#upcase`.
+ "HELLO, #{name.upcase}!"
+ end
+ end
+
+ # The nils are a special case of refining `T.any`.
+ sig { params(id: T.any(Integer, T::Array[Integer])).returns(T::Array[String]) }
+ def database_lookup(id)
+ if id.is_a?(Integer)
+ # `ids` must be an Integer here.
+ [id.to_s]
+ else
+ # `ids` must be a T::Array[Integer] here.
+ id.map(&:to_s)
+ end
+ end
+
+ # Sorbet recognizes these methods that narrow type definitions:
+ # * is_a?
+ # * kind_of?
+ # * nil?
+ # * Class#===
+ # * Class#<
+ # * block_given?
+ #
+ # Because they're so common, it also recognizes these Rails extensions:
+ # * blank?
+ # * present?
+ #
+ # Be careful to maintain Sorbet assumptions if you redefine these methods!
+
+ # Have you ever written this line of code?
+ #
+ # raise StandardError, "Can't happen"
+ #
+ # Sorbet can help you prove that statically (this is known as
+ # "exhaustiveness") with `T.absurd`. It's extra cool when combined with
+ # `T::Enum`!
+
+ class Size < T::Enum
+ extend T::Sig
+
+ enums do
+ Byte = new('B')
+ Kibibyte = new('KiB')
+ Mebibyte = new('MiB')
+ # "640K ought to be enough for anybody"
+ end
+
+ sig { returns(Integer) }
+ def bytes
+ case self
+ when Byte then 1 << 0
+ when Kibibyte then 1 << 10
+ when Mebibyte then 1 << 20
+ else
+ # Sorbet knows you've checked all the cases, so there's no possible
+ # value that `self` could have here.
+ #
+ # But if you _do_ get here somehow, this will raise at runtime.
+ T.absurd(self)
+
+ # If you're missing a case, Sorbet can even tell you which one it is!
+ end
+ end
+ end
+
+ # We're gonna need `puts` and `raise` for this next part.
+ include Kernel
+
+ # Sorbet knows that no code can execute after a `raise` statement because it
+ # "never returns".
+ sig { params(num: T.nilable(Integer)).returns(Integer) }
+ def decrement(num)
+ raise ArgumentError, '¯\_(ツ)_/¯' unless num
+
+ num - 1
+ end
+
+ class CustomError < StandardError; end
+
+ # You can annotate your own error-raising methods with `T.noreturn`.
+ sig { params(message: String).returns(T.noreturn) }
+ def oh_no(message = 'A bad thing happened')
+ puts message
+ raise CustomError, message
+ end
+
+ # Infinite loops also don't return.
+ sig { returns(T.noreturn) }
+ def loading
+ loop do
+ %q(-\|/).each_char do |c|
+ print "\r#{c} reticulating splines..."
+ sleep 1
+ end
+ end
+ end
+
+ # You may run into a situation where Sorbet "loses" your type refinement.
+ # Remember that almost everything you do in Ruby is a method call that could
+ # return a different value next time you call it. Sorbet doesn't assume that
+ # any methods are pure (even those from `attr_reader` and `attr_accessor`).
+ sig { returns(T.nilable(Integer)) }
+ def answer
+ rand > 0.5 ? 42 : nil
+ end
+
+ sig { void }
+ def bad_typecheck
+ if answer.nil?
+ 0
+ else
+ # But answer might return `nil` if we call it again!
+ answer + 1
+ # ^ Method + does not exist on NilClass component of T.nilable(Integer)
+ end
+ end
+
+ sig { void }
+ def good_typecheck
+ ans = answer
+ if ans.nil?
+ 0
+ else
+ # This time, Sorbet knows that `ans` is non-nil.
+ ans + 1
+ end
+ end
+end
+
+module InheritancePatterns
+ extend T::Sig
+
+ # If you have a method that always returns the type of its receiver, use
+ # `T.self_type`. This is common in fluent interfaces and DSLs.
+ #
+ # Warning: This feature is still experimental!
+ class Logging
+ extend T::Sig
+
+ sig { returns(T.self_type) }
+ def log
+ pp self
+ self
+ end
+ end
+
+ class Data < Logging
+ extend T::Sig
+
+ sig { params(x: Integer, y: String).void }
+ def initialize(x: 0, y: '')
+ @x = x
+ @y = y
+ end
+
+ # You don't _have_ to use `T.self_type` if there's only one relevant class.
+ sig { params(x: Integer).returns(Data) }
+ def setX(x)
+ @x = x
+ self
+ end
+
+ sig { params(y: String).returns(Data) }
+ def setY(y)
+ @y = y
+ self
+ end
+ end
+
+ # Ta-da!
+ sig { params(data: Data).void }
+ def chaining(data)
+ data.setX(1).log.setY('a')
+ end
+
+ # If it's a class method (a.k.a. singleton method), use `T.attached_class`.
+ #
+ # No warning here. This one is stable!
+ class Box
+ extend T::Sig
+
+ sig { params(contents: String, weight: Integer).void }
+ def initialize(contents, weight)
+ @contents = contents
+ @weight = weight
+ end
+
+ sig { params(contents: String).returns(T.attached_class) }
+ def self.pack(contents)
+ new(contents, contents.chars.uniq.length)
+ end
+ end
+
+ class CompanionCube < Box
+ extend T::Sig
+
+ sig { returns(String) }
+ def pick_up
+ "♥#{@contents}🤍"
+ end
+ end
+
+ sig { returns(String) }
+ def befriend
+ CompanionCube.pack('').pick_up
+ end
+
+ # Sorbet has support for abstract classes and interfaces. It can check that
+ # all the concrete classes and implementations actually define the required
+ # methods with compatible signatures.
+
+ # Here's an abstract class:
+
+ class WorkflowStep
+ extend T::Sig
+
+ # Bring in the inheritance helpers.
+ extend T::Helpers
+
+ # Mark this class as abstract. This means it cannot be instantiated with
+ # `.new`, but it can still be subclassed.
+ abstract!
+
+ sig { params(args: T::Array[String]).void }
+ def run(args)
+ pre_hook
+ execute(args)
+ post_hook
+ end
+
+ # This is an abstract method, which means it _must_ be implemented by
+ # subclasses. Add a signature with `abstract` to an empty method to tell
+ # Sorbet about it.
+ #
+ # If this implementation of the method actually gets called at runtime, it
+ # will raise `NotImplementedError`.
+ sig { abstract.params(args: T::Array[String]).void }
+ def execute(args); end
+
+ # The following non-abstract methods _can_ be implemented by subclasses,
+ # but they're optional.
+
+ sig { void }
+ def pre_hook; end
+
+ sig { void }
+ def post_hook; end
+ end
+
+ class Configure < WorkflowStep
+ extend T::Sig
+
+ sig { void }
+ def pre_hook
+ puts 'Configuring...'
+ end
+
+ # To implement an abstract method, mark the signature with `override`.
+ sig { override.params(args: T::Array[String]).void }
+ def execute(args)
+ # ...
+ end
+ end
+
+ # And here's an interface:
+
+ module Queue
+ extend T::Sig
+
+ # Bring in the inheritance helpers.
+ extend T::Helpers
+
+ # Mark this module as an interface. This adds the following restrictions:
+ # 1. All of its methods must be abstract.
+ # 2. It cannot have any private or protected methods.
+ interface!
+
+ sig { abstract.params(num: Integer).void }
+ def push(num); end
+
+ sig { abstract.returns(T.nilable(Integer)) }
+ def pop; end
+ end
+
+ class PriorityQueue
+ extend T::Sig
+
+ # Include the interface to tell Sorbet that this class implements it.
+ # Sorbet doesn't support implicitly implemented interfaces (also known as
+ # "duck typing").
+ include Queue
+
+ sig { void }
+ def initialize
+ @items = T.let([], T::Array[Integer])
+ end
+
+ # Implement the Queue interface's abstract methods. Remember to use
+ # `override`!
+
+ sig { override.params(num: Integer).void }
+ def push(num)
+ @items << num
+ @items.sort!
+ end
+
+ sig { override.returns(T.nilable(Integer)) }
+ def pop
+ @items.shift
+ end
+ end
+
+ # If you use the `included` hook to get class methods from your modules,
+ # you'll have to use `mixes_in_class_methods` to get them to type-check.
+
+ module Mixin
+ extend T::Helpers
+ interface!
+
+ module ClassMethods
+ extend T::Sig
+
+ sig { void }
+ def whisk
+ 'fskfskfsk'
+ end
+ end
+
+ mixes_in_class_methods(ClassMethods)
+ end
+
+ class EggBeater
+ include Mixin
+ end
+
+ EggBeater.whisk # Meringue!
+end
+
+module EscapeHatches
+ extend T::Sig
+
+ # Ruby is a very dynamic language, and sometimes Sorbet can't infer the
+ # properties you already know to be true. Although there are ways to rewrite
+ # your code so Sorbet can prove safety, you can also choose to "break out" of
+ # Sorbet using these "escape hatches".
+
+ # Once you start using `T.nilable`, Sorbet will start telling you _all_ the
+ # places you're not handling nils. Sometimes, you know a value can't be nil,
+ # but it's not practical to fix the sigs so Sorbet can prove it. In that
+ # case, you can use `T.must`.
+ sig { params(maybe_str: T.nilable(String)).returns(String) }
+ def no_nils_here(maybe_str)
+ # If maybe_str _is_ actually nil, this will error at runtime.
+ str = T.must(maybe_str)
+ str.downcase
+ end
+
+ # More generally, if you know that a value must be a specific type, you can
+ # use `T.cast`.
+ sig do
+ params(
+ str_or_ary: T.any(String, T::Array[String]),
+ idx_or_range: T.any(Integer, T::Range[Integer]),
+ ).returns(T::Array[String])
+ end
+ def slice2(str_or_ary, idx_or_range)
+ # Let's say that, for some reason, we want individual characters from
+ # strings or sub-arrays from arrays. The other options are not allowed.
+ if str_or_ary.is_a?(String)
+ # Here, we know that `idx_or_range` must be a single index. If it's not,
+ # this will error at runtime.
+ idx = T.cast(idx_or_range, Integer)
+ [str_or_ary.chars.fetch(idx)]
+ else
+ # Here, we know that `idx_or_range` must be a range. If it's not, this
+ # will error at runtime.
+ range = T.cast(idx_or_range, T::Range[Integer])
+ str_or_ary.slice(range) || []
+ end
+ end
+
+ # If you know that a method exists, but Sorbet doesn't, you can use
+ # `T.unsafe` so Sorbet will let you call it. Although we tend to think of
+ # this as being an "unsafe method call", `T.unsafe` is called on the receiver
+ # rather than the whole expression.
+ sig { params(count: Integer).returns(Date) }
+ def the_future(count)
+ # Let's say you've defined some extra date helpers that Sorbet can't find.
+ # So `2.decades` is effectively `(2*10).years` from ActiveSupport.
+ Date.today + T.unsafe(count).decades
+ end
+
+ # If this is a method on the implicit `self`, you'll have to make that
+ # explicit to use `T.unsafe`.
+ sig { params(count: Integer).returns(Date) }
+ def the_past(count)
+ # Let's say that metaprogramming defines a `now` helper method for
+ # `Time.new`. Using it would normally look like this:
+ #
+ # now - 1234
+ #
+ T.unsafe(self).now - 1234
+ end
+
+ # There's a special type in Sorbet called `T.untyped`. For any value of this
+ # type, Sorbet will allow it to be used for any method argument and receive
+ # any method call.
+
+ sig { params(num: Integer, anything: T.untyped).returns(T.untyped) }
+ def nothing_to_see_here(num, anything)
+ anything.digits # Is it an Integer...
+ anything.upcase # ... or a String?
+
+ # Sorbet will not be able to infer anything about this return value because
+ # it's untyped.
+ BasicObject.new
+ end
+
+ def see_here
+ # It's actually nil! This will crash at runtime, but Sorbet allows it.
+ nothing_to_see_here(1, nil)
+ end
+
+ # For a method without a sig, Sorbet infers the type of each argument and the
+ # return value to be `T.untyped`.
+end
+
+# The following types are not officially documented but are still useful. They
+# may be experimental, deprecated, or not supported.
+
+module ValueSet
+ extend T::Sig
+
+ # A common pattern in Ruby is to have a method accept one value from a set of
+ # options. Especially when starting out with Sorbet, it may not be practical
+ # to refactor the code to use `T::Enum`. In this case, you can use `T.enum`.
+ #
+ # Note: Sorbet can't check this statically becuase it doesn't track the
+ # values themselves.
+ sig do
+ params(
+ data: T::Array[Numeric],
+ shape: T.enum([:circle, :square, :triangle])
+ ).void
+ end
+ def plot_points(data, shape: :circle)
+ data.each_with_index do |y, x|
+ Kernel.puts "#{x}: #{y}"
+ end
+ end
+end
+
+module Generics
+ extend T::Sig
+
+ # Generics are useful when you have a class whose method types change based
+ # on the data it contains or a method whose method type changes based on what
+ # its arguments are.
+
+ # A generic method uses `type_parameters` to declare type variables and
+ # `T.type_parameter` to refer back to them.
+ sig do
+ type_parameters(:element)
+ .params(
+ element: T.type_parameter(:element),
+ count: Integer,
+ ).returns(T::Array[T.type_parameter(:element)])
+ end
+ def repeat_value(element, count)
+ count.times.each_with_object([]) do |elt, ary|
+ ary << elt
+ end
+ end
+
+ sig do
+ type_parameters(:element)
+ .params(
+ count: Integer,
+ block: T.proc.returns(T.type_parameter(:element)),
+ ).returns(T::Array[T.type_parameter(:element)])
+ end
+ def repeat_cached(count, &block)
+ elt = block.call
+ ary = []
+ count.times do
+ ary << elt
+ end
+ ary
+ end
+
+ # A generic class uses `T::Generic.type_member` to define type variables that
+ # can be like regular type names.
+ class BidirectionalHash
+ extend T::Sig
+ extend T::Generic
+
+ Left = type_member
+ Right = type_member
+
+ sig { void }
+ def initialize
+ @left_hash = T.let({}, T::Hash[Left, Right])
+ @right_hash = T.let({}, T::Hash[Right, Left])
+ end
+
+ # Implement just enough to make the methods below work.
+
+ sig { params(lkey: Left).returns(T::Boolean) }
+ def lhas?(lkey)
+ @left_hash.has_key?(lkey)
+ end
+
+ sig { params(rkey: Right).returns(T.nilable(Left)) }
+ def rget(rkey)
+ @right_hash[rkey]
+ end
+ end
+
+ # To specialize a generic type, use brackets.
+ sig do
+ params(
+ options: BidirectionalHash[Symbol, Integer],
+ choice: T.any(Symbol, Integer),
+ ).returns(T.nilable(String))
+ end
+ def lookup(options, choice)
+ case choice
+ when Symbol
+ options.lhas?(choice) ? choice.to_s : nil
+ when Integer
+ options.rget(choice).to_s
+ else
+ T.absurd(choice)
+ end
+ end
+
+ # To specialize through inheritance, re-declare the `type_member` with
+ # `fixed`.
+ class Options < BidirectionalHash
+ Left = type_member(fixed: Symbol)
+ Right = type_member(fixed: Integer)
+ end
+
+ sig do
+ params(
+ options: Options,
+ choice: T.any(Symbol, Integer),
+ ).returns(T.nilable(String))
+ end
+ def lookup2(options, choice)
+ lookup(options, choice)
+ end
+
+ # There are other variance annotations you can add to `type_member`, but
+ # they're rarely used.
+end
+```
+
+## Additional resources
+
+- [Official Documentation](https://sorbet.org/docs/overview)
+- [sorbet.run](https://sorbet.run) - Playground
diff --git a/sql.html.markdown b/sql.html.markdown
index 685e522d..834cf00b 100644
--- a/sql.html.markdown
+++ b/sql.html.markdown
@@ -95,7 +95,7 @@ UPDATE tablename1 SET fname='John' WHERE lname='Mutt';
-- Delete rows from the tablename1 table
-- where the lname value begins with 'M'.
-DELETE FROM tablename1 WHERE lname like 'M%';
+DELETE FROM tablename1 WHERE lname LIKE 'M%';
-- Delete all rows from the tablename1 table, leaving the empty table.
DELETE FROM tablename1;
diff --git a/swift.html.markdown b/swift.html.markdown
index e46dcc75..36124e11 100644
--- a/swift.html.markdown
+++ b/swift.html.markdown
@@ -679,6 +679,9 @@ class Rect: Shape {
// A simple class `Square` extends `Rect`
class Square: Rect {
+ // Use a convenience initializer to make calling a designated initializer faster and more "convenient".
+ // Convenience initializers call other initializers in the same class and pass default values to one or more of their parameters.
+ // Convenience initializers can have parameters as well, which are useful to customize the called initializer parameters or choose a proper initializer based on the value passed.
convenience init() {
self.init(sideLength: 5)
}
diff --git a/tact.html.markdown b/tact.html.markdown
new file mode 100644
index 00000000..2cb650ee
--- /dev/null
+++ b/tact.html.markdown
@@ -0,0 +1,603 @@
+---
+language: Tact
+filename: tact.tc
+contributors:
+ - ["Tal Kol", "https://www.orbs.com/"]
+ - ["Kirill Malev", "https://fslabs.io"]
+ - ["Yash Garg", "https://github.com/yash0501"]
+---
+
+Tact language is used to program smart contracts on the
+[The Open Network](https://ton.org) blockchain. Contract logic is executed in
+TVM, the stack-based TON Virtual Machine.
+
+Tact is a statically typed, but language was designed to be friendly for
+developers with JS and Python background.
+
+This page is based on [Tact-by-Example](https://tact-by-example.org/).
+You can use this resource to play around with contracts and check out
+the interactive features.
+
+# Basic syntax, function definition
+
+```c
+// Single line comment
+
+ // This is a multi-line comment
+ // this is a comment in the comment
+
+ get fun greeting(): String {
+ // This is a function that returns "hello world" message
+ // Return type is specified after a colon :
+ return "hello world";
+ }
+```
+
+# A Simple Counter contract
+
+This is a simple counter contract that allows users to increment its value.
+
+This contract has a state variable `val` that persists between contract calls
+
+- the counter value. When persisted, this variable is encoded as `uint32` -
+ a 32-bit unsigned integer. Contracts pay rent in proportion to the amount
+ of persistent space they consume, so compact representations are encouraged.
+
+State variables should be initialized in `init()` that runs on deployment of
+the contract.
+
+## Messages
+
+The actor model is a model of concurrent computation and is at the heart of TON
+smart contracts. Each smart contract can process one message at a time, change
+its own state, or send one or several messages. Processing of the message
+occurs in one transaction, that is, it cannot be interrupted. Messages to one
+contract are processed consequently one by one. As a result, the execution of
+each transaction is local and can be parallelized at the blockchain level,
+which allows for on-demand throughput horizontal scaling and hosting an
+unlimited number of users and transactions.
+
+## Receiving messages
+
+This contract can receive messages from users. Unlike getters that are just
+read-only, messages can do write operations and change the contract's
+persistent state. Incoming messages are processed in receive() methods as
+transactions and cost gas for the sender.
+
+After deploying the contract, send the increment message by pressing the Send
+increment button in order to increase the counter value by one. Afterwards,
+call the getter value() to see that the value indeed changed.
+
+```c
+contract Counter {
+// Tact allows to create a contract
+ // persistent state variable of type Int to hold the counter value
+ val: Int as uint32;
+
+ // initialize the state variable when contract is deployed
+ init() {
+ self.val = 0;
+ }
+
+ // handler for incoming increment messages that change the state
+ receive("increment") {
+ self.val = self.val + 1;
+ }
+
+ // read-only getter for querying the counter value
+ get fun value(): Int {
+ return self.val;
+ }
+}
+```
+
+# The Deployable Trait
+
+Tact doesn't support classical class inheritance, but contracts can implement
+traits. One of the commonly used traits is `Deployable`. It implements a simple
+receiver for the Deploy message which helps deploy contracts in a standard way.
+
+All contracts are deployed by sending them a message. This can be any message,
+but best practice is to designate the special `Deploy`
+message for this purpose.
+
+This message has a single field, `queryId`, which is provided by the deployer
+(normally zero). If the deploy succeeds, the contract will reply with the
+message `DeployOk` and echo the same `queryId` in the response.
+
+If you're using Tact's [auto-generated](https://docs.tact-lang.org/tools/typescript#tact-contract-in-typescript) TypeScript
+classes to deploy, sending the deploy message should look like:
+
+```c
+const msg = { $$type: "Deploy", queryId: 0n };
+ await contract.send(sender, { value: toNano(1) }, msg);
+```
+
+You can see the implementation of the trait [here](https://github.com/tact-lang/tact/blob/main/stdlib/libs/deploy.tact).
+Notice that the file deploy.tact needs to be imported from the standard
+library using the import keyword.
+
+```c
+// this trait has to be imported
+import "@stdlib/deploy";
+
+// the Deployable trait adds a default receiver for the "Deploy" message
+contract Counter with Deployable {
+
+ val: Int as uint32;
+
+ init() {
+ self.val = 0;
+ }
+
+ receive("increment") {
+ self.val = self.val + 1;
+ }
+
+ get fun value(): Int {
+ return self.val;
+ }
+}
+```
+
+# Integers
+
+Tact supports a number of primitive data types that are tailored for
+smart contract use.
+
+`Int` is the primary number type. Math in smart contracts is always done
+with integers and never with floating points since floats are [unpredictable](https://learn.microsoft.com/en-us/cpp/build/why-floating-point-numbers-may-lose-precision).
+
+The runtime type `Int` is always 257-bit signed, so all runtime calculations
+are done at 257-bit. This should be large enough for pretty much anything you
+need as it's large enough to hold the number of atoms in the universe.
+
+Persistent state variables can be initialized inline or inside `init()`.
+If you forget to initialize a state variable, the code will not compile.
+
+## State costs
+
+When encoding `Int` to persistent state, we will usually use smaller
+representations than 257-bit to reduce storage cost.
+The persistent state size is specified in every declaration of
+a state variable after the `as` keyword.
+
+Storing 1000 257-bit integers in state [costs](https://ton.org/docs/develop/smart-contracts/fees#how-to-calculate-fees) about
+0.184 TON per year. Storing 1000 32-bit integers only costs
+0.023 TON per year by comparison.
+
+```c
+import "@stdlib/deploy";
+
+contract Integers with Deployable {
+
+ // contract persistent state variables
+ // integers can be persisted in state in various sizes
+ // range -2^256 to 2^256 - 1 (takes 257 bit = 32 bytes + 1 bit)
+ i1: Int as int257 = 3001;
+ i2: Int as uint256; // range 0 to 2^256 - 1 (takes 256 bit = 32 bytes)
+ // range -2^255 to 2^255 - 1 (takes 256 bit = 32 bytes)
+ i3: Int as int256 = 17;
+ i4: Int as uint128; // range 0 to 2^128 - 1 (takes 128 bit = 16 bytes)
+ // range -2^127 to 2^127 - 1 (takes 128 bit = 16 bytes)
+ i5: Int as int128;
+ i6: Int as coins; // range 0 to 2^120 - 1 (takes 120 bit = 15 bytes)
+ // range 0 to 18,446,744,073,709,551,615 (takes 64 bit = 8 bytes)
+ i7: Int as uint64 = 0x1c4a;
+ // range -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
+ // (takes 64 bit = 8 bytes)
+ i8: Int as int64 = -203;
+ i9: Int as uint32 = 0; // range 0 to 4,294,967,295 (takes 32 bit = 4 bytes)
+ // range -2,147,483,648 to 2,147,483,647 (takes 32 bit = 4 bytes)
+ i10: Int as int32 = 0;
+ i11: Int as uint16 = 0; // range 0 to 65,535 (takes 16 bit = 2 bytes)
+ i12: Int as int16 = 0; // range -32,768 to 32,767 (takes 16 bit = 2 bytes)
+ i13: Int as uint8 = 0; // range 0 to 255 (takes 8 bit = 1 byte)
+ i14: Int as int8 = 0; // range -128 to 127 (takes 8 bit = 1 byte)
+
+ init() {
+ // we can define numbers in hex (base 16)
+ self.i2 = 0x83dfd552e6372;
+ self.i4 = 1507998500293440234999; // we can define numbers in decimal
+ self.i5 = pow(10, 9); // this is 10^9 = 1,000,000,000
+ self.i6 = ton("1.23"); // easy to read coin balances
+ // (coins type is nano-tons, like cents, just with 9 decimals)
+ }
+
+ receive("show all") {
+ dump(self.i1);
+ dump(self.i2);
+ dump(self.i3);
+ dump(self.i4);
+ dump(self.i5);
+ dump(self.i6);
+ dump(self.i7);
+ dump(self.i8);
+ }
+
+ get fun result(): Int {
+ return self.i1;
+ }
+}
+```
+
+## Bools, Addresses, Strings, Operators and Constants
+
+### Bool
+
+Bool can be used for boolean variables
+
+```js
+b1: Bool = true;
+b2: Bool = false;
+```
+
+### Address
+
+Address is another primitive data type. It represents standard addresses on
+the TON blockchain.
+TON is divided into multiple chains called workchains. One of the internal
+fields of the address is the workchain id:
+0 - The standard workchain, for regular users. Your contracts will be here.
+-1 - The masterchain, usually for validators.
+
+```js
+// bouncable (same foundation wallet)
+a1: Address = address("EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N");
+// non-bounceable (same foundation wallet)
+a2: Address = address("UQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqEBI");
+```
+
+### String
+
+Tact has basic support for strings. Strings support unicode and don't
+have any special escape characters like \n.
+Strings are immutable. Once a sequence of characters is created, this
+sequence cannot be modified.
+If you need to concatenate strings in run-time, you can use a StringBuilder.
+This object handles gas efficiently and supports append() of various types to
+the string.
+
+```js
+s1: String = "hello world";
+sb: StringBuilder = beginString();
+sb.append(self.s1);
+```
+
+### Integer Operations
+
+Addition, subtraction, multiplication, division, modulo,
+shift left and right, minimum and maximum numbers, absolute value
+
+```js
+i: Int = -12; // temporary variable, runtime Int type is always int257
+i = i1 * 3 + (i2 - i); // basic math expressions
+i = i1 % 10; // modulo (remainder after division), 3001 % 10 = 1
+i = i1 / 1000; // integer division (truncation toward zero), 3001 / 1000 = 3
+i = i1 >> 3; // shift right (multiply by 2^n)
+i = i1 << 2; // shift left (divide by 2^n)
+i = min(i2, 11); // minimum between two numbers
+i = max(i2, 66); // maximum between two numbers
+i = abs(-1 * i2); // absolute value
+```
+
+### Constants
+
+Unlike variables, constants cannot change. Their values are
+calculated in compile-time and cannot change during execution.
+
+```js
+const StateUnpaid: Int = 0;
+```
+
+## Getters, Receivers and Messages
+
+### Getters
+
+Getters are special contract functions that allow users to query
+information from the contract.
+Contract methods starting with the prefix get fun are all getters.
+Calling getters is free and does not cost gas.
+Getters are read-only, they cannot change the contract persistent state.
+A contract cannot execute a getter of another contract. Getters are only
+executable by end-users off-chain.
+
+```js
+count: Int as uint32 = 17;
+
+get fun counter(): Int {
+ return self.count;
+}
+```
+
+### Receivers
+
+Contract methods named receive() are the handlers that process
+each incoming message type.
+Tact will automatically route every incoming message to the correct receiver
+listening for it according to its type. A message is only handled by one receiver.
+
+Handler for "increment" textual message - this is a textual string message,
+these cannot carry input arguments
+
+```js
+receive("increment") {
+ self.val = self.val + 1;
+}
+```
+
+### Messages
+
+Messages are defined using the message keyword. They can carry input
+arguments. For integers, you must define the encoding size, just like in
+state variables.
+
+Handler for the "Add" message - this is a binary message that has an input
+argument (amount)
+
+```js
+receive(msg: Add) {
+ self.val = self.val + msg.amount;
+}
+```
+
+## Structs
+
+Structs allow you to combine multiple primitives together in a more semantic way.
+Structs can define complex data types that contain multiple fields of
+different types. They can also be nested.
+
+```js
+// Normal struct
+struct Point {
+ x: Int as int64;
+ y: Int as int64;
+}
+
+// Nested struct
+struct Params {
+ name: String = "Satoshi"; // default value
+ age: Int? = null; // optional field
+ point: Point; // nested structs
+}
+```
+
+## Message Sender and Throwing Errors
+
+### Message Sender
+
+Every incoming message is sent from some contract that has
+an address. You can query the address of the message sender by calling sender()
+
+```js
+deployer: Address = sender();
+```
+
+### Errors
+
+When an error is thrown, the transaction reverts. By writing a
+require() on a condition that isn't met
+
+```js
+require(self.val < 5, "Counter is too high");
+```
+
+## Messages Between Contracts, Sending and Receiving TON Coins
+
+### Messages Between Contracts
+
+Different contracts can only communicate with
+each other by sending each other messages.
+
+This example sends a message to the to address with value of 1 TON and body
+of a comment with a string "Hello, World!".
+SendIgnoreErrors means that even when error occurs during message sending
+next messages would be sent anyway.
+
+```js
+let to: Address = ...;
+let value: Int = ton("1");
+send(SendParameters{
+ to: to, // address of receiver
+ value: value, // amount of TON you want to send
+ mode: SendIgnoreErrors, // 8-bit flag configuring how to send message
+ bounce: true, // if set to true (default) then message
+ // will be bounced back to sender
+ body: "Hello, World!".asComment() // message body as Cell
+});
+```
+
+### Receiving TONs
+
+You can query the contract balance with myBalance() - note
+that the value is in nano-tons (like cents, just with 9 decimals). The balance
+already contains the incoming message value.
+You can also get the incoming TON balance with context().value
+
+```js
+val: Int as int64 = myBalance()
+// or
+// print how much TON coin were sent with this message
+dump(context().value);
+```
+
+### Sending TONs
+
+We can send any amount of TON to any address just like we created
+a send call between different contracts
+
+Send mode SendRemainingValue will add to the outgoing value any excess left
+from the incoming message after all gas costs are deducted from it.
+
+```js
+amount: Int as coins = ton("1");
+send(SendParameters{
+ to: sender(),
+ bounce: true,
+ value: amount,
+ mode: SendRemainingValue + SendIgnoreErrors
+});
+```
+
+## If/Else statements and Loops
+
+### If
+
+Tact supports if statements in a similar syntax to most programming
+languages. Curly braces are required.
+We can have the else and else if similar to other programming languages.
+
+```js
+if (val > 1000) {
+ dump("larger than 1000");
+} else if (val > 500) {
+ dump("between 500 and 1000");
+} else {
+ dump("smaller than 500");
+}
+```
+
+### Loops
+
+Tact does not support traditional 'for' loops, 'break' and 'continue'
+statements in loops.
+The repeat loop statement input number must fit within an int32.
+
+```js
+// repeat exactly 10 times
+
+repeat (10) {
+ i = i + 1;
+ sum = sum + i;
+}
+
+// While loop
+
+let x: Int = 10;
+while(x > 0) {
+ x = x - 1;
+}
+
+// do-until loop
+
+let x: Int = 10;
+do {
+ x = x - 1;
+} until (x <= 0);
+```
+
+## Functions
+
+Functions in Tact start with the fun keyword. Functions can receive multiple
+input arguments and can optionally return a single output value. You can
+return a struct if you want to return multiple values.
+
+```js
+fun average(a: Int, b: Int): Int {
+ return (a + b) / 2;
+}
+```
+
+## Maps and Arrays
+
+### Maps
+
+Maps are a dictionary type that can hold an arbitrary number of items,
+each under a different key.
+The keys in maps can either be an Int type or an Address type.
+You can check if a key is found in the map by calling the get() method.
+Replace the value under a key by calling the set() method.
+
+```js
+mi1: map; // maps with Int as key
+ma1: map; // maps with Address as key
+```
+
+### Arrays
+
+To create an array, define a map with 'Int' type as key as well as value.
+
+```js
+arr: map; // this is our array implemented with a map
+```
+
+## Ownable Standard Library
+
+The Ownable trait allows the contract to set an owner role, which can have
+higher priviliges from everybody else.
+For this you would need to import the "@stdlib/ownable" library and inherit
+it in your contract
+
+- Use the self.requireOwner() call to verify that the person making that
+ function call is the owner of contract
+- 'ChangeOwner{newOwner: Address}' message which allows the owner to
+ transfer ownership.
+- Define state variables named 'owner: Address' and 'stopped: Bool' and
+ call 'self.requireNotStopped()' on actions that should be stopped.
+- Define state variables named 'owner: Address' and "stopped: Bool' and
+ call 'self.requireNotStopped()' on actions that should be stopped.
+
+```js
+import "@stdlib/ownable";
+import "@stdlib/deploy";
+
+contract Counter with Deployable, Ownable {
+ owner: Address;
+
+ init() { // initialize a contract with default values like 'constructor'
+ self.owner = sender(); // we can initialize owner to any value we want, the deployer in this case
+ self.val = 0;
+ }
+
+ // this message in only available to the owner
+ receive("double") {
+ self.requireOwner();
+ self.val = self.val * 2;
+ }
+
+ // this message will only work until the contract was stopped
+ receive("increment") {
+ self.requireNotStopped();
+ self.val = self.val + 1;
+ }
+
+ // this message will only work as long as the contract is not stopped
+ receive("increment2") {
+ self.requireNotStopped();
+ self.val = self.val + 1;
+ }
+}
+
+```
+
+## Additional resources
+
+- [TON Documentation](https://ton.org/docs/#/)
+- [Tact Docs](https://docs.tact-lang.org/)
+- [Tact by Example](https://tact-by-example.org/)
+- [Community portal](https://society.ton.org)
+- [Blockchain portal](https://ton.org)
+- [Stackoverflow](https://stackoverflow.com/questions/tagged/ton)
+
+## Social
+
+- [Tact community](https://t.me/tactlang)
+- [Developer community](https://t.me/tondev_eng)
+- [TON Learn](https://t.me/ton_learn)
+- [Tondev News](https://t.me/tondevnews)
+- [TON Technical Updates](https://t.me/thetontech)
+
+## Useful blogposts
+
+- [Setting up a TON Development Environment](https://society.ton.org/setting-up-a-ton-development-environment)
+- [Hello World on TON](https://society.ton.org/ton-hello-world-step-by-step-guide-for-writing-your-first-smart-contract-in-func)
+
+## Future To Dos
+
+- Add smart contracts examples
+- Add more links to documentations
+
+This file is based on [Tact By Example](https://tact-by-example.org).
+
+P.S. If by any chance you're familiar with [Forth](https://learnxinyminutes.com/docs/forth/),
+you can also take a look at [Fift](https://ton-blockchain.github.io/docs/fiftbase.pdf).
diff --git a/tailspin.html.markdown b/tailspin.html.markdown
new file mode 100644
index 00000000..89ccdb1f
--- /dev/null
+++ b/tailspin.html.markdown
@@ -0,0 +1,383 @@
+---
+language: tailspin
+filename: learntailspin.tt
+contributors:
+ - ["Torbjörn Gannholm", "https://github.com/tobega/"]
+
+---
+
+**Tailspin** works with streams of values in pipelines. You may often feel
+that your program is the machine and that the input data is the program.
+
+While Tailspin is unlikely to become mainstream, or even production-ready,
+it will change the way you think about programming in a good way.
+
+```c
+// Comment to end of line
+
+// Process data in a pipeline with steps separated by ->
+// String literals are delimited by single quotes
+// A bang (!) indicates a sink, or end of the pipe
+// OUT is the standard output object, ::write is the message to write output
+'Hello, World!' -> !OUT::write
+
+// Output a newline by just entering it in the string (multiline strings)
+'
+' -> !OUT::write
+// Or output the decimal unicode value for newline (10) between $# and ;
+'$#10;' -> !OUT::write
+
+// Define an immutable named value. Value syntax is very literal.
+def names: ['Adam', 'George', 'Jenny', 'Lucy'];
+
+// Stream the list to process each name. Note the use of $ to get the value.
+// The current value in the pipeline is always just $
+// String interpolation starts with a $ and ends with ;
+$names... -> 'Hello $;!
+' -> !OUT::write
+
+// You can also stream in the interpolation and nest interpolations
+// Note the list indexing with parentheses and the slice extraction
+// Note the use of ~ to signify an exclusive bound to the range
+// Outputs 'Hello Adam, George, Jenny and Lucy!'
+'Hello $names(first);$names(first~..~last)... -> ', $;'; and $names(last);!
+' -> !OUT::write
+
+// Conditionally say different things to different people
+// Matchers (conditional expressions) are delimited by angle brackets
+// A set of matchers, evaluated top down, must be in templates (a function)
+// Here it is an inline templates delimited by \( to \)
+// Note the doubled '' and $$ to get a literal ' and $
+$names... -> \(
+ when <='Adam'> do 'What''s up $;?' !
+ when <='George'> do 'George, where are the $$10 you owe me?' !
+ otherwise 'Hello $;!' !
+\) -> '$;$#10;' -> !OUT::write
+
+// You can also define templates (functions)
+// A lone ! emits the value into the calling pipeline without returning control
+// The # sends the value to be matched by the matchers
+// Note that templates always take one input value and emit 0 or more outputs
+templates collatz-sequence
+ when <..0> do 'The start seed must be a positive integer' !
+ when <=1> do $!
+// The ?( to ) allows matching a computed value. Can be concatenated as "and"
+ when ($ mod 2 <=1>)> do
+ $ !
+ 3 * $ + 1 -> #
+ otherwise
+ $ !
+ $ ~/ 2 -> #
+end collatz-sequence
+
+// Collatz sequence from random start on one line separated by spaces
+1000 -> SYS::randomInt -> $ + 1 -> collatz-sequence -> '$; ' -> !OUT::write
+'
+' -> !OUT::write
+
+// Collatz sequence formatted ten per line by an indexed list template
+// Note the square brackets creates a list of the enclosed pipeline results
+// The \[i]( to \) defines a templates to apply to each value of a list,
+// the i (or whatever identifier you choose) holds the index
+[1000 -> SYS::randomInt -> $ + 1 -> collatz-sequence]
+-> \[i](
+ when <=1|?($i mod 10 <=0>)> do '$;$#10;' !
+ otherwise '$; ' !
+\)... -> !OUT::write
+
+// A range can have an optional stride
+def odd-numbers: [1..100:2];
+
+// Use mutable state locally. One variable per templates, always called @
+templates product
+ @: $(first);
+ $(first~..last)... -> @: $@ * $;
+ $@ !
+end product
+
+$odd-numbers(6..8) -> product -> !OUT::write
+'
+' -> !OUT::write
+
+// Use processor objects to hold mutable state.
+// Note that the outer @ must be referred to by name in inner contexts
+// A sink templates gives no output and is called prefixed by !
+// A source templates takes no input and is called prefixed by $
+processor Product
+ @: 1;
+ sink accumulate
+ @Product: $@Product * $;
+ end accumulate
+ source result
+ $@Product !
+ end result
+end Product
+
+// The processor is a constructor templates. This one called with $ (no input)
+def multiplier: $Product;
+
+// Call object templates by sending messages with ::
+1..7 -> !multiplier::accumulate
+-1 -> !multiplier::accumulate
+$multiplier::result -> 'The product is $;
+' -> !OUT::write
+
+// Syntax sugar for a processor implementing the collector interface
+1..7 -> ..=Product -> 'The collected product is $;$#10;' -> !OUT::write
+
+// Symbol sets (essentially enums) can be defined for finite sets of values
+data colour #{green, red, blue, yellow}
+
+// Use processor typestates to model state cleanly.
+// The last named mutable state value set determines the typestate
+processor Lamp
+ def colours: $;
+ @Off: 0;
+ state Off
+ source switchOn
+ @On: $@Off mod $colours::length + 1;
+ 'Shining a $colours($@On); light$#10;' !
+ end switchOn
+ end Off
+ state On
+ source turnOff
+ @Off: $@On;
+ 'Lamp is off$#10;' !
+ end turnOff
+ end On
+end Lamp
+
+def myLamp: [colour#green, colour#blue] -> Lamp;
+
+$myLamp::switchOn -> !OUT::write // Shining a green light
+$myLamp::turnOff -> !OUT::write // Lamp is off
+$myLamp::switchOn -> !OUT::write // Shining a blue light
+$myLamp::turnOff -> !OUT::write // Lamp is off
+$myLamp::switchOn -> !OUT::write // Shining a green light
+
+// Use regular expressions to test strings
+['banana', 'apple', 'pear', 'cherry']... -> \(
+ when <'.*a.*'> do '$; contains an ''a''' !
+ otherwise '$; has no ''a''' !
+\) -> '$;
+' -> !OUT::write
+
+// Use composers with regular expressions and defined rules to parse strings
+composer parse-stock-line
+ {inventory-id: (), name: <'\w+'> (), currency: <'.{3}'>,
+ unit-price: (?) ?}
+ rule parts: associated-parts: [+]
+ rule part: <'[A-Z]\d+'> (<=','>?)
+end parse-stock-line
+
+'705 gizmo EUR5 A67,G456,B32' -> parse-stock-line -> !OUT::write
+// {associated-parts: [A67, G456, B32], currency: EUR,
+// inventory-id: 705, name: gizmo, unit-price: 5}
+'
+' -> !OUT::write
+
+// Stream a string to split it into glyphs.
+// A list can be indexed/sliced by an array of indexes
+// Outputs ['h','e','l','l','o'], indexing arrays/lists starts at 1
+['abcdefghijklmnopqrstuvwxyz'...] -> $([8,5,12,12,15]) -> !OUT::write
+'
+' -> !OUT::write
+
+// We have used only raw strings above.
+// Strings can have different types as determined by a tag.
+// Comparing different types is an error, unless a wider type bound is set
+// Type bound is given in ´´ and '' means any string value, tagged or raw
+templates get-string-type
+ when <´''´ '.*'> do '$; is a raw string' !
+ when <´''´ id´'\d+'> do '$; is a numeric id string' !
+ when <´''´ =id´'foo'> do 'id foo found' !
+ when <´''´ id´'.*'> do '$; is an id' !
+ when <´''´ name´'.+'> do '$; is a name' !
+ otherwise '$; is not a name or id, nor a raw string' !
+end get-string-type
+
+[name´'Anna', 'foo', id´'789', city´'London', id´'xzgh', id´'foo']...
+-> get-string-type -> '$;
+' -> !OUT::write
+
+// Numbers can be raw, tagged or have a unit of measure
+// Type .. is any numeric value, tagged, measure or raw
+templates get-number-type
+ when <´..´ =inventory-id´86> do 'inventory-id 86 found' !
+ when <´..´ inventory-id´100..> do '$; is an inventory-id >= 100' !
+ when <´..´ inventory-id´0..|..inventory-id´0> do '$; is an inventory-id' !
+ when <´..´ 0"m"..> do '$; is an m-measure >= 0"m"' !
+ when <´..´ ..0|0..> do '$; is a raw number' !
+ otherwise '$; is not a positive m-measure nor an inventory-id, nor raw' !
+end get-number-type
+
+[inventory-id´86, inventory-id´6, 78"m", 5"s", 99, inventory-id´654]...
+-> get-number-type -> '$;
+' -> !OUT::write
+
+// Measures can be used in arithmetic, "1" is the scalar unit
+// When mixing measures you have to cast to the result measure
+4"m" + 6"m" * 3"1" -> ($ ~/ 2"s")"m/s" -> '$;
+' -> !OUT::write
+
+// Tagged identifiers must be made into raw numbers when used in arithmetic
+// Then you can cast the result back to a tagged identifier if you like
+inventory-id´300 -> inventory-id´($::raw + 1) -> get-number-type -> '$;
+' -> !OUT::write
+
+// Fields get auto-typed, tagging raw strings or numbers by default
+// You cannot assign the wrong type to a field
+def item: { inventory-id: 23, name: 'thingy', length: 12"m" };
+
+'Field inventory-id $item.inventory-id -> get-number-type;
+' -> !OUT::write
+'Field name $item.name -> get-string-type;
+' -> !OUT::write
+'Field length $item.length -> get-number-type;
+' -> !OUT::write
+
+// You can define types and use as type-tests. This also defines a field.
+// It would be an error to assign a non-standard plate to a standard-plate field
+data standard-plate <'[A-Z]{3}[0-9]{3}'>
+
+[['Audi', 'XYZ345'], ['BMW', 'I O U']]... -> \(
+ when ($(2) )> do {make: $(1), standard-plate: $(2)}!
+ otherwise {make: $(1), vanity-plate: $(2)}!
+\) -> '$;
+' -> !OUT::write
+
+// You can define union types
+data age <"years"|"months">
+
+[ {name: 'Cesar', age: 20"years"},
+ {name: 'Francesca', age: 19"years"},
+ {name: 'Bobby', age: 11"months"}]...
+-> \(
+// Conditional tests on structures look a lot like literals, with field tests
+ when <{age: <13"years"..19"years">}> do '$.name; is a teenager'!
+ when <{age: <"months">}> do '$.name; is a baby'!
+// You don't need to handle all cases, 'Cesar' will just be ignored
+\) -> '$;
+' -> !OUT::write
+
+// Array/list indexes start at 1 by default, but you can choose
+// Slices return whatever overlaps with the actual array
+[1..5] -> $(-2..2) -> '$;
+' -> !OUT::write // Outputs [1,2]
+0:[1..5] -> $(-2..2) -> '$;
+' -> !OUT::write // Outputs [1,2,3]
+-2:[1..5] -> $(-2..2) -> '$;
+' -> !OUT::write // Outputs [1,2,3,4,5]
+
+// Arrays can have indexes of measures or tagged identifiers
+def game-map: 0"y":[
+ 1..5 -> 0"x":[
+ 1..5 -> level´1:[
+ 1..3 -> {
+ level: $,
+ terrain-id: 6 -> SYS::randomInt,
+ altitude: (10 -> SYS::randomInt)"m"
+ }
+ ]
+ ]
+];
+
+// Projections (indexing) can span several dimensions
+$game-map(3"y"; 1"x"..3"x"; level´1; altitude:) -> '$;
+' -> !OUT::write // Gives a list of three altitude values
+
+// Flatten and do a grouping projection to get stats
+// Count and Max are built-in collector processors
+[$game-map... ... ...] -> $(collect {
+ occurences: Count,
+ highest-on-level: Max&{by: :(altitude:), select: :(level:)}
+ } by $({terrain-id:}))
+-> !OUT::write
+'
+' -> !OUT::write
+
+// Relations are sets of structures/records.
+// Here we get all unique {level:, terrain-id:, altitude:} combinations
+def location-types: {|$game-map... ... ...|};
+
+// Projections can re-map structures. Note § is the relative accessor
+$location-types({terrain-id:, foo: §.level::raw * §.altitude})
+-> '$;
+' -> !OUT::write
+
+// Relational algebra operators can be used on relations
+($location-types join {| {altitude: 3"m"} |})
+-> !OUT::write
+'
+' -> !OUT::write
+
+// Define your own operators for binary operations
+operator (left dot right)
+ $left -> \[i]($ * $right($i)!\)... -> ..=Sum&{of: :()} !
+end dot
+
+([1,2,3] dot [2,5,8]) -> 'dot product: $;
+' -> !OUT::write
+
+// Supply parameters to vary templates behaviour
+templates die-rolls&{sides:}
+ 1..$ -> $sides::raw -> SYS::randomInt -> $ + 1 !
+end die-rolls
+
+[5 -> die-rolls&{sides:4}] -> '$;
+' -> !OUT::write
+
+// Pass templates as parameters, maybe with some parameters pre-filled
+source damage-roll&{first:, second:, third:}
+ (1 -> first) + (1 -> second) + (1 -> third) !
+end damage-roll
+
+$damage-roll&{first: die-rolls&{sides:4},
+ second: die-rolls&{sides:6}, third: die-rolls&{sides:20}}
+-> 'Damage done is $;
+' -> !OUT::write
+
+// Write tests inline. Run by --test flag on command line
+// Note the ~ in the matcher means "not",
+// and the array content matcher matches elements < 1 and > 4
+test 'die-rolls'
+ assert [100 -> die-rolls&{sides: 4}] <~[<..~1|4~..>]> 'all rolls 1..4'
+end 'die-rolls'
+
+// Provide modified modules to tests (aka test doubles or mocks)
+// IN is the standard input object and ::lines gets all lines
+source read-numbers
+ $IN::lines -> #
+ when <'\d+'> do $!
+end read-numbers
+
+test 'read numbers from input'
+ use shadowed core-system/
+ processor MockIn
+ source lines
+ [
+ '12a',
+ '65',
+ 'abc'
+ ]... !
+ end lines
+ end MockIn
+ def IN: $MockIn;
+ end core-system/
+ assert $read-numbers <=65> 'Only 65 is read'
+end 'read numbers from input'
+
+// You can work with byte arrays
+composer hexToBytes
+
+end hexToBytes
+
+'1a5c678d' -> hexToBytes -> ($ and [x 07 x]) -> $(last-1..last) -> '$;
+' -> !OUT::write // Outputs 0005
+
+```
+
+## Further Reading
+
+- [Main Tailspin site](https://github.com/tobega/tailspin-v0/)
+- [Tailspin language reference](https://github.com/tobega/tailspin-v0/blob/master/TailspinReference.md)
diff --git a/tcsh.html.markdown b/tcsh.html.markdown
index 05954442..8f8429bc 100644
--- a/tcsh.html.markdown
+++ b/tcsh.html.markdown
@@ -28,23 +28,23 @@ Some more files:
```tcsh
#!/bin/tcsh
-# First line of the script is shebang which tells the system how to execute the
-# script: http://en.wikipedia.org/wiki/Shebang_(Unix)
-# TCSH emulates the shebang on systems which don't understand it.
+# The first line of the script is a shebang which tells the system how to execute
+# the script: http://en.wikipedia.org/wiki/Shebang_(Unix)
+# TCSH emulates the shebang on systems that don't understand it.
-# In most cases you'll use `#!/bin/tcsh -f', because `-f' option does not load
+# In most cases you'll use `#!/bin/tcsh -f`, because `-f` option does not load
# any resource or start-up files, or perform any command hashing, and thus
# starts faster.
# --- the echo command --------------------------------------------------------
-# The `echo' writes each word to the shell's standard output, separated by
+# The `echo` writes each word to the shell's standard output, separated by
# spaces and terminated with a newline. The echo_style shell variable may be
# set to emulate (or not) the flags and escape sequences.
# Display the value of echo_style
echo $echo_style
-# Enable `echo' to support backslashed characters and `-n' option (no new line)
+# Enable `echo` to support backslashed characters and `-n` option (no new line)
# This is the default for tcsh, but your distro may change it. Slackware has
# done so.
set echo_style = both
@@ -65,17 +65,17 @@ echo 'two\nlines'
# --- Basic Syntax ------------------------------------------------------------
# A special character (including a blank or tab) may be prevented from having
-# its special meaning by preceding it with a backslash `\'.
-# this will display the last history commands
+# its special meaning by preceding it with a backslash `\`.
+# This will display the last history commands
echo !!
-# this will not
+# This will not
echo \!\!
-# Single quotes prevents expanding special characters too, but some
-# characters like `!' and backslash have higher priority
-# `$' (variable value) will not expands
+# Single quotes prevent expanding special characters too, but some
+# characters like `!` and backslash have higher priority
+# `$` (variable value) will not expand
echo '$1 tip'
-# `!' (history) will expands
+# `!` (history) will expand
echo '!!'
# Strings enclosed by back-quotes will be executed and replaced by the result.
@@ -85,16 +85,16 @@ echo `ls`
echo 'first line'; echo 'second line'
# There is also conditional execution
-echo "Always executed" || echo "Only executed if first command fails"
-echo "Always executed" && echo "Only executed if first command does NOT fail"
+echo "Always executed" || echo "Only executed if the first command fails"
+echo "Always executed" && echo "Only executed if the first command does NOT fail"
# Parenthesised commands are always executed in a subshell,
-# example: create a project and then informs you that it finished while
+# example: creates a project and then informs you that it finished while
# it does the installation.
make && ( espeak "BOSS, compilation finished"; make install )
-# prints the home directory but leaving you where you were
+# prints the home directory but leaves you where you were
(cd; pwd); pwd
# Read tcsh man-page documentation
@@ -103,10 +103,10 @@ man tcsh
# --- Variables ---------------------------------------------------------------
# The shell maintains a list of variables, each of which has as value a list of
# zero or more words. The values of shell variables can be displayed and
-# changed with the `set' and `unset' commands.
-# The system maintains its own list of ``environment'' variables.
-# These can be displayed and changed with `printenv', `setenv' and `unsetenv'.
-# The syntax of setenv is similar to POSIX sh.
+# changed with the `set` and `unset` commands.
+# The system maintains its own list of "environment" variables.
+# These can be displayed and changed with `printenv`, `setenv`, and `unsetenv`.
+# The syntax of `setenv` is similar to POSIX sh.
# Assign a value or nothing will create a variable
# Assign nothing
@@ -122,7 +122,7 @@ set var = `ls`
# Remove a variable
unset var
-# Prints 1 (true) if the variable `var' exists otherwise prints 0 (false)
+# Prints 1 (true) if the variable `var` exists otherwise prints 0 (false)
echo $?var
# Print all variables and their values
set
@@ -130,10 +130,10 @@ set
# Prints the contents of 'var'
echo $var;
echo "$var";
-# Prints the string `$var'
+# Prints the string `$var`
echo \$var
echo '$var'
-# braces can be used to separate variable from the rest when its needed
+# Braces can be used to separate variables from the rest when it is needed
set num = 12; echo "There ${num}th element"
# Prints the number of characters of the value: 6
@@ -147,7 +147,7 @@ echo $var
echo $var[*]
# Print the count of elements: 5
echo $#var
-# Print indexed element; prints the second element: two
+# Print the indexed element; This prints the second element: two
echo $var[2]
# Print range of elements; prints 2nd up to 3rd: two, three
echo $var[2-3]
@@ -165,8 +165,8 @@ echo $var[-3]
# $! the PID of the last background process started by this shell
# $$ script's PID
-# $path, $PATH the list of directories that will search for executable to run
-# $home, $HOME user's home directory, also the `~' can be used instead
+# $path, $PATH the list of directories that will search for an executable to run
+# $home, $HOME user's home directory, also the `~` can be used instead
# $uid user's login ID
# $user user's login name
# $gid the user's group ID
@@ -174,24 +174,24 @@ echo $var[-3]
# $cwd, $PWD the Current/Print Working Directory
# $owd the previous working directory
# $tcsh tcsh version
-# $tty the current tty; ttyN for linux console, pts/N for terminal
+# $tty the current tty; ttyN for Linux console, pts/N for terminal
# emulators under X
# $term the terminal type
# $verbose if set, causes the words of each command to be printed.
-# can be set by the `-v' command line option too.
+# can be set by the `-v` command line option too.
# $loginsh if set, it is a login shell
# TIP: $?0 is always false in interactive shells
# TIP: $?prompt is always false in non-interactive shells
-# TIP: if `$?tcsh' is unset; you run the original `csh' or something else;
-# try `echo $shell'
-# TIP: $verbose this is useful to debugging scripts
-# NOTE: $PWD and $PATH are synchronised with $cwd and $pwd automatically.
+# TIP: if `$?tcsh` is unset; you run the original `csh` or something else;
+# try `echo $shell`
+# TIP: `$verbose` is useful for debugging scripts
+# NOTE: `$PWD` and `$PATH` are synchronised with `$cwd` and `$pwd` automatically.
# --- Variable modifiers ------------------------------------------------------
# Syntax: ${var}:m[:mN]
# Where is:
-# h : the directory t : the filenane r : remove extension e : the extension
+# h : the directory t : the filename r : remove extension e : the extension
# u : uppercase the first lowercase letter
# l : lowercase the first uppercase letter
# p : print but do not execute it (hist)
@@ -199,8 +199,8 @@ echo $var[-3]
# x : like q, but break into words at white spaces
# g : apply the following modifier once to each word
# a : apply the following modifier as many times as possible to single word
-# s/l/r/ : search for `l' and replace with `r', not regex; the `&' in the r is
-# replaced by l
+# s/l/r/ : search for `l` and replace with `r`, not regex; the `&` in the `r` is
+# replaced by `l`
# & : Repeat the previous substitution
# start with this file
@@ -232,7 +232,7 @@ echo 'this string' >> file.txt
echo 'this string' >>& file.txt
# Redirect the standard input from file.txt
cat < file.txt
-# Input from keyboard; this stores the input line to variable `x'
+# Input from keyboard; this stores the input line to variable `x`
set x = $<
# Document here;
cat << LABEL
@@ -243,7 +243,7 @@ LABEL
(grep 'AGP' /usr/src/linux/Documentation/* > output-file.txt) >& error-file.txt
# example: read a name from standard input and display a greetings message
-echo -n "Enter your name? "
+echo -n "Enter your name: "
set name = $<
echo "Greetings $name"
@@ -266,15 +266,15 @@ if ( $name != $user ) echo "Your name isn't your username"
# NOTE: if $name is empty, tcsh sees the above condition as:
# if ( != $user ) ...
# which is invalid syntax
-# so the "safe" way to use potentially empty variables in tcsh is:
+# The "safe" way to use potentially empty variables in tcsh is:
# if ( "$name" != $user ) ...
# which, when $name is empty, is seen by tcsh as:
# if ( "" != $user ) ...
# which works as expected
# There is also conditional execution
-echo "Always executed" || echo "Only executed if first command fails"
-echo "Always executed" && echo "Only executed if first command does NOT fail"
+echo "Always executed" || echo "Only executed if the first command fails"
+echo "Always executed" && echo "Only executed if the first command does NOT fail"
# To use && and || with if statements, you don't need multiple pairs of
# square brackets:
@@ -286,14 +286,14 @@ if ( "$name" == "Daniya" || "$name" == "Zach" ) then
echo "This will run if $name is Daniya OR Zach."
endif
-# String matching operators ( `=~' and `!~' )
+# String matching operators ( `=~` and `!~` )
# The ‘==’ ‘!=’ ‘=~’ and ‘!~’ operators compare their arguments as strings;
# all others operate on numbers. The operators ‘=~’ and ‘!~’ are like ‘!=’
# and ‘==’ except that the right hand side is a glob-pattern against which
-# the left hand operand is matched.
+# the left-hand operand is matched.
if ( $user =~ ni[ck]* ) echo "Greetings Mr. Nicholas."
-if ( $user !~ ni[ck]* ) echo "Hey, get out of Nicholas PC."
+if ( $user !~ ni[ck]* ) echo "Hey, get out of Nicholas' PC."
# Arithmetic expressions are denoted with the following format:
@ result = 10 + 5
@@ -302,16 +302,16 @@ echo $result
# Arithmetic Operators
# +, -, *, /, %
#
-# Arithmetic Operators which must be parenthesised
+# Arithmetic Operators which must be parenthesized
# !, ~, |, &, ^, ~, <<, >>,
# Compare and logical operators
#
-# All operators are same as in C.
+# All operators are the same as in C.
# It is non so well documented that numeric expressions require spaces
-# in-between; Also, `@' has its own parser, it seems that work well when the
-# expression is parenthesised otherwise the primary parser seems it is active.
-# Parenthesis require spaces around, this is documented.
+# in-between; Also, `@` has its own parser, it seems that it works well when
+# the expression is parenthesized, otherwise the primary parser seems to be
+# active. Parentheses require spaces around, this is documented.
# wrong
@ x = $y+1
@@ -330,32 +330,32 @@ echo $result
# C's operators ++ and -- are supported if there is not assignment
@ result ++
-# None shell created to do mathematics;
+# No shell was created to do mathematics;
# Except for the basic operations, use an external command with backslashes.
#
# I suggest the calc as the best option.
# (http://www.isthe.com/chongo/tech/comp/calc/)
#
-# The standard Unix's bc as second option
+# The standard Unix's bc as the second option
# (https://www.gnu.org/software/bc/manual/html_mono/bc.html)
#
-# The standard Unix's AWK as third option
+# The standard Unix's AWK as the third option
# (https://www.gnu.org/software/gawk/manual/gawk.html)
-# You can also use `perl', `php' or even several BASICs, but prefer the
-# above utilities for faster load-and-run results.
+# You can also use `Perl`, `PHP`, `python`, or even several BASICs, but prefer
+# the above utilities for faster load-and-run results.
# real example: (that I answer in StackExchange)
# REQ: x := 1001b OR 0110b
-# in `tcsh' expression (by using octal)
+# in `tcsh` expression (by using octal)
@ x = ( 011 | 06 ); echo $x
-# the same by using `calc' (and using binary as the original req)
+# the same by using `calc` (and using binary as the original req)
set x = `calc '0b1001 | 0b110'`; echo $x
# --- File Inquiry Operators --------------------------------------------------
-# NOTE: The builtin `filetest' command do the same thing.
+# NOTE: The built-in `filetest` command does the same thing.
#### Boolean operators
# -r read access -w write access -x execute access -e existence
@@ -366,23 +366,23 @@ set x = `calc '0b1001 | 0b110'`; echo $x
# -b block device -c char device
# -t file (digit) is an open file descriptor for a terminal device
-# if the file `README' exists, displays a message
+# If the file `README` exists, display a message
if ( -e README ) echo "I have already README file"
-# if the `less' program is installed, use this instead of `more'
+# If the `less` program is installed, use it instead of `more`
if ( -e `where less` ) then
- alias more 'less'
+ alias more 'less'
endif
#### Non-boolean operators
# -Z returns the file size in bytes
# -M returns the modification time (mtime) -M: returns mtime string
-# -A returns the lass access time (atime) -A: returns atime string
-# -U returns the owners user ID -U: returns the owners user-name
-# -G returns the group ID -G: returns the group-name
+# -A returns the last access time (atime) -A: returns atime string
+# -U returns the owner's user ID -U: returns the owner's user name
+# -G returns the owner's group ID -G: returns the owner's group name
# -P returns the permissions as octal number -Pmode returns perm. AND mode
-# this will display the date as Unix-time integer: 1498511486
+# this will display the date as a Unix-time integer: 1498511486
filetest -M README.md
# This will display "Tue Jun 27 00:11:26 2017"
@@ -390,14 +390,14 @@ filetest -M: README.md
# --- Basic Commands ----------------------------------------------------------
-# Navigate though file system with `chdir' (cd)
+# Navigate through the filesystem with `chdir` (cd)
cd path # change working directory
-cd # change to home directory
-cd - # change to previous directory
+cd # change to the home directory
+cd - # change to the previous directory
cd .. # go up one directory
# Examples:
-cd ~/Downloads # go to my `Downloads' directory
+cd ~/Downloads # go to my `Downloads` directory
# Use `mkdir` to create new directories.
mkdir newdir
@@ -413,7 +413,7 @@ where csh
# --- Pipe-lines --------------------------------------------------------------
# A pipeline is a sequence of processes chained together by their standard
# streams, so that the output of each process (stdout) feeds directly as input
-# (stdin) to the next one. This `pipes' are created with the `|' special
+# (stdin) to the next one. These `pipes` are created with the `|` special
# character and it is one of the most powerful characteristics of Unix.
# example:
@@ -422,18 +422,18 @@ ls -l | grep key | less
# input (stdin) of the process for "grep key"; and likewise for the process
# for "less".
-# the `ls', the `grep' and the `less' are programs of Unix and they have their
-# own man-page. The `pipe' mechanism is part of the kernel but the syntax
-# and the control is job of the shell, the tcsh in our case.
+# the `ls`, the `grep`, and the `less` are Unix programs and they have their
+# own man-page. The `pipe` mechanism is part of the kernel but the syntax
+# and the control is the shell's job, the tcsh in our case.
-# NOTE: `pipe' mechanism has Windows too, but it is buggy and I sign it for all
-# versions until Windows XP SP3 API32 which was the last one that I worked on.
-# Microsoft still denied it but is well known bug since it is a common method
-# for inter-process communication. For small I/O it will work well.
-# tcsh, along with grep, gcc and perl is one of the first Unix programs that
+# NOTE: Windows has the `pipe` mechanism too, but it is buggy and I signed it
+# for all versions until Windows XP SP3 API32 which was the last one that I
+# worked on. Microsoft denied it, but it is a well-known bug since it is a
+# common method for inter-process communication. For small I/O it will work well.
+# tcsh, along with grep, GCC, and Perl is one of the first Unix programs that
# ported to DOS (with EMX DOS extender) and later to Windows (1998).
-# example: this will convert tcsh to PostScript and will show it with okular
+# example: this will convert tcsh to PostScript and will show it with Okular
zcat /usr/man/man1/tcsh.1.gz | groff -Tps -man | okular -
# a better version
@@ -451,10 +451,10 @@ set page = tcsh; set loc = (locate -b -n 1 "\\\\"${page}".1.gz");
set page = tcsh; set loc = (locate -b -n 1 "\\\\"${page}".1.gz");
zcat `eval $loc` | groff -Tps -man | ps2pdf - ${page}.pdf && okular tcsh.pdf
-# NOTE: `okular' is the default application of KDE environment and it shows
-# postcript and pdf files. You can replace it with your lovely pdf viewer.
-# zcat, locate, groff, are common programs in all Unices. `ps2pdf' program
-# is part of `ghostscript' package that is widely used.
+# NOTE: `okular` is the default application of the KDE environment and it shows
+# postcript and pdf files. You can replace it with your lovely PDF viewer.
+# `zcat`, `locate`, `groff`, are common programs in all Unixes. The `ps2pdf`
+# program is part of the `ghostscript` package that is widely used.
# --- Control Flow ------------------------------------------------------------
@@ -468,8 +468,8 @@ set page = tcsh; set loc = (locate -b -n 1 "\\\\"${page}".1.gz");
# ...]
# endif
#
-# If the specified expr is true then the commands to the first else are
-# executed; otherwise if expr2 is true then the commands to the second else
+# If the specified `expr` is true then the commands to the first else are
+# executed; otherwise if `expr2` is true then the commands to the second else
# are executed, etc.
# Any number of else-if pairs are possible; only one endif is needed.
#
@@ -477,24 +477,24 @@ set page = tcsh; set loc = (locate -b -n 1 "\\\\"${page}".1.gz");
#
# if ( expr ) command
#
-# If `expr' evaluates true, then command is executed.
-# `command' must be a simple command, not an alias, a pipeline, a command list
-# or a parenthesized command list. With few words, avoid to use it.
+# If `expr` evaluates to true, then the command is executed.
+# `command` must be a simple command, not an alias, a pipeline, a command list
+#, or a parenthesized command list. With a few words, avoid using it.
#
-# BUG: Input/output redirection occurs even if expr is false and command is
-# thus not executed.
+# BUG: Input/output redirection occurs even if expr is false and the command
+# is thus not executed.
#
-# check if we are in non-interactive shell and quit if true
+# check if we are in a non-interactive shell and quit if true
if ( $?USER == 0 || $?prompt == 0 ) exit
# check if we are a login shell
if ( $?loginsh ) then
- # check if you are on linux console (not X's terminal)
- if ( $tty =~ tty* ) then
- # enable keypad application keys (man console_codes)
- echo '\033='
- endif
+ # check if you are on linux console (not X's terminal)
+ if ( $tty =~ tty* ) then
+ # enable keypad application keys (man console_codes)
+ echo '\033='
+ endif
endif
#### SWITCH-ENDSW
@@ -509,37 +509,37 @@ endif
#
# tcsh uses a case statement that works similarly to switch in C.
# Each case label is successively matched, against the specified string which
-# is first command and filename expanded. The file metacharacters `*', `?'
-# and `[...]' may be used in the case labels. If none of the labels match the
-# execution begins after the default label if its defined.
-# The command `breaksw' causes execution to continue after the endsw. Otherwise
+# is first command and filename expanded. The file metacharacters `*`, `?`
+# and `[...]` may be used in the case labels. If none of the labels match the
+# execution begins after the default label if it's defined.
+# The command `breaksw` causes execution to continue after the endsw. Otherwise,
# control may fall through case labels and default labels as in C.
switch ( $var )
case *.[1-9]:
case *.[1-9].gz:
- echo "$var is a man-page."
- breaksw
+ echo "$var is a man-page."
+ breaksw
case *gz:
- echo "$var is gzipped"
- breaksw
+ echo "$var is gzipped"
+ breaksw
default:
- file $var
+ file $var
endsw
#### FOREACH-END
# Syntax:
# foreach name ( wordlist )
-# ...
+# ...
# [break | continue]
# end
#
-# Successively sets the variable `name' to each member of `wordlist' and
+# Successively sets the variable `name` to each member of `wordlist` and
# executes the sequence of commands between this command and the matching
-# `end' keyword. The `continue' keyword jump to the next element back to
-# top; and the `break' keyword terminates the loop.
+# `end` keyword. The `continue` keyword jumps to the next element back to
+# top, and the `break` keyword terminates the loop.
#
-# BUG: `foreach' doesn't ignore here documents when looking for its end.
+# BUG: `foreach` doesn't ignore here documents when looking for its end.
# example: counting 1 to 10
foreach i ( `seq 1 10` )
@@ -548,12 +548,12 @@ end
# example: type all files in the list
foreach f ( a.txt b.txt c.txt )
- cat $f
+ cat $f
end
# example: convert wma to ogg
foreach f ( *.wma )
- ffmpeg -i "$f" "$f:r".ogg
+ ffmpeg -i "$f" "$f:r".ogg
end
#### WHILE-END
@@ -562,22 +562,22 @@ end
# [break | continue]
# end
#
-# Executes the commands between the `while' and the matching `end' while `expr'
-# evaluates non-zero. `break' and `continue' may be used to terminate or
+# Executes the commands between the `while` and the matching `end` while `expr`
+# evaluates non-zero. `break` and `continue` may be used to terminate or
# continue the loop prematurely.
# count from 1 to 10
set num = 1
while ( $num <= 10 )
- echo $num
- @ num ++
+ echo $num
+ @ num ++
end
# print all directories of CWD
set lst = ( * )
while ( $#lst )
- if ( -d $lst[1] ) echo $lst[1] is directory
- shift lst
+ if ( -d $lst[1] ) echo $lst[1] is directory
+ shift lst
end
# separate command-line arguments to options or parameters
@@ -585,12 +585,12 @@ set options
set params
set lst = ( $* )
while ( $#lst )
- if ( "$lst[1]" =~ '-*' ) then
- set options = ( $options $lst[1] )
- else
- set params = ( $params $lst[1] )
- endif
- shift lst
+ if ( "$lst[1]" =~ '-*' ) then
+ set options = ( $options $lst[1] )
+ else
+ set params = ( $params $lst[1] )
+ endif
+ shift lst
end
echo 'options =' $options
echo 'parameters =' $params
@@ -599,16 +599,16 @@ echo 'parameters =' $params
# Syntax: repeat count command
#
# The specified command, which is subject to the same restrictions as the
-# command in the one line if statement above, is executed count times.
-# I/O redirections occur exactly once, even if count is 0.
+# command in the one line `if` statement above, is executed count times.
+# I/O redirections occur exactly once, even if `count` is 0.
#
-# TIP: in most cases prefer `while'
+# TIP: in most cases prefer `while`
repeat 3 echo "ding dong"
# --- Functions ---------------------------------------------------------------
# tcsh has no functions but its expression syntax is advanced enough to use
-# `alias' as functions. Another method is recursion
+# `alias` as functions. Another method is recursion
# Alias argument selectors; the ability to define an alias to take arguments
# supplied to it and apply them to the commands that it refers to.
@@ -637,48 +637,48 @@ alias cd 'cd \!* && ls'
#!/bin/tcsh -f
set todo = option1
if ( $#argv > 0 ) then
- set todo = $argv[1]
+ set todo = $argv[1]
endif
switch ( $todo )
case option1:
-# ...
- $0 results
- breaksw
+# ...
+ $0 results
+ breaksw
case option2:
-# ...
- $0 results
- breaksw
+# ...
+ $0 results
+ breaksw
case results:
- echo "print the results here"
-# ...
- breaksw
+ echo "print the results here"
+# ...
+ breaksw
default:
- echo "Unknown option: $todo"
-# exit 0
+ echo "Unknown option: $todo"
+# exit 0
endsw
# --- Recursion method --- end ---
# --- examples ----------------------------------------------------------------
# this script prints available power-states if no argument is set;
-# otherwise it set the state of the $argv[1]
+# otherwise it sets the state of the $argv[1]
# --- power-state script --- begin --------------------------------------------
#!/bin/tcsh -f
# get parameter ("help" for none)
set todo = help
if ( $#argv > 0 ) then
- set todo = $argv[1]
+ set todo = $argv[1]
endif
# available options
set opts = `cat /sys/power/state`
# is known?
foreach o ( $opts )
- if ( $todo == $o ) then
- # found; execute it
- echo -n $todo > /sys/power/state
- break
- endif
+ if ( $todo == $o ) then
+ # found; execute it
+ echo -n $todo > /sys/power/state
+ break
+ endif
end
# print help and exit
echo "usage: $0 [option]"
@@ -691,19 +691,19 @@ echo "available options on kernel: $opts"
set secret=`shuf -i1-100 -n1`
echo "I have a secret number from 1 up to 100"
while ( 1 )
- echo -n "Guess: "
- set guess = $<
- if ( $secret == $guess ) then
- echo "You found it"
- exit 1
- else
- if ( $secret > $guess ) then
- echo "its greater"
- else if ( $secret < $guess ) then
- echo "its lesser"
- endif
- endif
- endif
+ echo -n "Guess: "
+ set guess = $<
+ if ( $secret == $guess ) then
+ echo "You found it"
+ exit 1
+ else
+ if ( $secret > $guess ) then
+ echo "its greater"
+ else if ( $secret < $guess ) then
+ echo "its lesser"
+ endif
+ endif
+ endif
end
# --- secretnum.csh --- end ---------------------------------------------------
@@ -711,36 +711,36 @@ end
# Appendices
#### About [T]CSH:
-# * CSH is notorious about its bugs;
-# * It was also famous about its advanced interactive mode.
-# * TCSH is famous that have the most advanced completion subsystem.
-# * TCSH is famous that have the most advanced aliases subsystem; aliases
-# can take parameters and often used as functions!
-# * TCSH is well known that preferred by people (me too) because of better
-# syntax. All shells are using Thomson's syntax with exception of [t]csh,
-# fish and plan9's shells (rc, ex).
-# * It is smaller and consume far less memory than bash, zsh even mksh!
+# * CSH is notorious for its bugs;
+# * It is also famous for its advanced interactive mode.
+# * TCSH is famous for having the most advanced completion subsystem.
+# * TCSH is famous for having the most advanced aliases subsystem; aliases
+# can take parameters and often be used as functions!
+# * TCSH is well known and preferred by people (me too) because of better
+# syntax. All shells are using Thomson's syntax with the exception of
+# [t]csh, fish, and plan9's shells (rc, ex).
+# * It is smaller and consumes far less memory than bash, zsh, and even mksh!
# (memusage reports)
-# * TCSH still has bugs; less but have; if you write readable clean code you'll
-# find none; well almost none... This has to do with the implementation of
-# csh; that no means the other shells has good implementation.
-# * no one well known shell is capable for regular programming; if your script
-# getting big, use a programming language, or at least PHP or Perl (good
-# script languages).
+# * TCSH still has bugs; fewer, but it does; if you write readable clean code
+# you'll find none; well almost none... This has to do with the implementation
+# of csh; that doesn't mean the other shells have a good implementation.
+# * no well-known shell is capable of regular programming; if your script
+# is getting big, use a programming language, like Python, PHP, or Perl (good
+# scripting languages).
#
-# Advises:
-# 1. Do not use redirection in single-line if (it is well documented bug)
-# In most cases avoid to use single-line IFs.
-# 2. Do not mess up with other shells code, c-shell is not compatible with
+# Advice:
+# 1. Do not use redirection in single-line IFs (it is well documented bug)
+# In most cases avoid using single-line IFs.
+# 2. Do not mess up with other shells' code, c-shell is not compatible with
# other shells and has different abilities and priorities.
# 3. Use spaces as you'll use them to write readable code in any language.
-# A bug of csh was `set x=1' worked, `set x = 1' worked, `set x =1' did not!
-# 4. It is well documented that numeric expressions require spaces in-between;
-# also parenthesise all bit-wise and unary operators.
-# 5. Do not write a huge weird expression with several quotes, backslashes etc
+# A bug of csh was `set x=1` and `set x = 1` worked, but `set x =1` did not!
+# 4. It is well documented that numeric expressions require spaces in between;
+# also parenthesize all bit-wise and unary operators.
+# 5. Do not write a huge weird expression with several quotes, backslashes, etc
# It is bad practice for generic programming, it is dangerous in any shell.
# 6. Help tcsh, report the bug here
-# 7. Read the man page, `tcsh' has huge number of options, and variables.
+# 7. Read the man page, `tcsh` has a huge number of options and variables.
#
# I suggest the following options enabled by default
# --------------------------------------------------
@@ -770,14 +770,14 @@ end
# unset time
# unset tperiod
#
-# NOTE: If the `backslash_quote' is set, it may create compatibility issues
-# with other tcsh scripts which was written without it.
+# NOTE: If the `backslash_quote` is set, it may create compatibility issues
+# with other tcsh scripts that were written without it.
#
-# NOTE: The same for `parseoctal', but it is better to fix the problematic
+# NOTE: The same for `parseoctal`, but it is better to fix the problematic
# scripts.
#
# NOTE: **for beginners only**
-# This enable automatically rescan `path' directories if need to. (like bash)
+# This enables automatic rescanning of `path` directories if needed. (like bash)
# set autorehash
#### common aliases
diff --git a/toml.html.markdown b/toml.html.markdown
index 79aa544c..69dfd754 100755
--- a/toml.html.markdown
+++ b/toml.html.markdown
@@ -69,11 +69,15 @@ The first newline is trimmed in raw strings.
###########
## Integers can start with a +, a - or nothing.
-## Leading zeros are not allowed. Hex, octal, and binary forms are not allowed.
+## Leading zeros are not allowed.
+## Hex, octal, and binary forms are allowed.
## Values that cannot be expressed as a series of digits are not allowed.
int1 = +42
int2 = 0
int3 = -21
+int4 = 0xdeadbeef
+int5 = 0o755
+int6 = 0b11011100
integerRange = 64
## You can use underscores to enhance readability. Each
diff --git a/uk-ua/go-ua.html.markdown b/uk-ua/go-ua.html.markdown
index f980f7b1..6f294b1f 100644
--- a/uk-ua/go-ua.html.markdown
+++ b/uk-ua/go-ua.html.markdown
@@ -434,15 +434,15 @@ func requestServer() {
## Подальше вивчення
-Основним джерелом всієї інформації про Go залишається [офіційна веб-сторінка](http://golang.org/). Там можна знайти уроки, інтерактивно пограти та багато про що почитати.
-Окрім туру, у [документації](https://golang.org/doc/) міститься інформація як писати чистий та ефективний код на Go, документація пакетів та окремих команд, а також історія релізів.
+Основним джерелом всієї інформації про Go залишається [офіційна веб-сторінка](https://go.dev/). Там можна знайти уроки, інтерактивно пограти та багато про що почитати.
+Окрім туру, у [документації](https://go.dev/doc/) міститься інформація як писати чистий та ефективний код на Go, документація пакетів та окремих команд, а також історія релізів.
Надзвичайно рекомендується ознайомитись із визначенням мови. Вона легко читається та на диво коротка (в порівнянні з іншими сучасними мовами).
-Можна погратись з кодом вище на [Go playground](https://play.golang.org/p/tnWMjr16Mm). Спробуй змінити його та запустити із свого браузера. Поміть, що можна використовувати [https://play.golang.org](https://play.golang.org) як [REPL](https://uk.wikipedia.org/wiki/REPL) до тестів та коду в твоєму браузері, без встановлення Go.
+Можна погратись з кодом вище на [Go playground](https://go.dev/play/p/tnWMjr16Mm). Спробуй змінити його та запустити із свого браузера. Поміть, що можна використовувати [https://go.dev/play/](https://go.dev/play/) як [REPL](https://uk.wikipedia.org/wiki/REPL) до тестів та коду в твоєму браузері, без встановлення Go.
-В списку для прочитання новачкам в Go - [вихідний код стандартної бібліотеки](http://golang.org/src/pkg/). Код всеосяжно задокоментований, тому є найкращим прикладом з боку зручного для прочитання та швидкості розуміння коду на цій мові програмування. Приведений стиль та ідіоми Go.
-Крім того, можна просто натиснути на назву функції в [документації](http://golang.org/pkg/), щоб перейти до її реалізації.
+В списку для прочитання новачкам в Go - [вихідний код стандартної бібліотеки](https://go.dev/src/). Код всеосяжно задокоментований, тому є найкращим прикладом з боку зручного для прочитання та швидкості розуміння коду на цій мові програмування. Приведений стиль та ідіоми Go.
+Крім того, можна просто натиснути на назву функції в [документації](https://go.dev/pkg/), щоб перейти до її реалізації.
Іншим прекрасним посиланням для вивчення Go є [Go by example](https://gobyexample.com/).
diff --git a/v.html.markdown b/v.html.markdown
new file mode 100644
index 00000000..4f698184
--- /dev/null
+++ b/v.html.markdown
@@ -0,0 +1,229 @@
+---
+language: v
+filename: vlang.v
+contributors:
+ - ["Maou Shimazu", "https://github.com/Maou-Shimazu"]
+---
+
+V is a statically typed compiled programming language
+designed for building maintainable software.
+
+It's similar to Go and its design has also been influenced by
+Oberon, Rust, Swift, Kotlin, and Python.
+
+The language promotes writing
+simple and clear code with minimal abstraction.
+
+Despite being simple, V gives the developer a lot of power.
+Anything you can do in other languages, you can do in V.
+
+```v
+// Single Line Comment.
+/*
+ Multi Line Comment
+*/
+
+struct User { // Cannot be defined in main, explained later.
+ age int
+ name string
+ pos int = -1 // custom default value
+}
+// struct method
+fn (u User) can_register() bool {
+ return u.age > 16
+}
+
+struct Parser {
+ token Token
+}
+
+// c like enums
+enum Token {
+ plus
+ minus
+ div
+ mult
+}
+
+// 1. functions
+// language does not use semi colons
+fn add(x int, y int) int {
+ return x + y
+}
+// can return multiple values
+fn foo() (int, int) {
+ return 2, 3
+}
+
+// function visibility
+pub fn public_function() { // pub can only be used from a named module.
+}
+
+fn private_function() {
+}
+
+
+
+// Main function
+fn main() {
+ // Anonymous functions can be declared inside other functions:
+ double_fn := fn (n int) int {
+ return n + n
+ }
+ // 2. Variables: they are immutable by default
+ // implicitly typed
+ x := 1
+ // x = 2 // error
+ mut y := 2
+ y = 4
+ name := "John"
+ large_number := i64(9999999999999)
+ println("$x, $y, $name, $large_number") // 1, 4, John, 9999999999999
+
+ // unpacking values from functions.
+ a, b := foo()
+ println("$a, $b") // 2, 3
+ c, _ := foo() // ignore values using `_`
+ println("$c") // 2
+
+ // Numbers
+ u := u16(12)
+ v := 13 + u // v is of type `u16`
+ r := f32(45.6)
+ q := r + 3.14 // x is of type `f32`
+ s := 75 // a is of type `int`
+ l := 14.7 // b is of type `f64`
+ e := u + s // c is of type `int`
+ d := l + r // d is of type `f64`
+
+ // Strings
+ mut bob := 'Bob'
+ assert bob[0] == u8(66) // indexing gives a byte, u8(66) == `B`
+ assert bob[1..3] == 'ob' // slicing gives a string 'ob'
+ bobby := bob + 'by' // + is used to concatenate strings
+ println(bobby) // "Bobby"
+ bob += "by2" // += is used to append to strings
+ println(bob) // "Bobby2"
+
+ //String values are immutable. You cannot mutate elements:
+ //mut s := 'hello 🌎'
+ //s[0] = `H` // not allowed
+
+ //For raw strings, prepend r. Escape handling is not done for raw strings:
+ rstring := r'hello\nworld' // the `\n` will be preserved as two characters
+ println(rstring) // "hello\nworld"
+
+ // string interpolation
+ println('Hello, $bob!') // Hello, Bob!
+ println('Bob length + 10: ${bob.len + 10}!') // Bob length + 10: 13!
+
+ // 3. Arrays
+ mut numbers := [1, 2, 3]
+ println(numbers) // `[1, 2, 3]`
+ numbers << 4 // append elements with <<
+ println(numbers[3]) // `4`
+ numbers[1] = 5
+ println(numbers) // `[1, 5, 3]`
+ // numbers << "John" // error: `numbers` is an array of numbers
+ numbers = [] // array is now empty
+ arr := []int{len: 5, init: -1}
+ // `arr == [-1, -1, -1, -1, -1]`, arr.cap == 5
+
+ number_slices := [0, 10, 20, 30, 40]
+ println(number_slices[1..4]) // [10, 20, 30]
+ println(number_slices[..4]) // [0, 10, 20, 30]
+ println(number_slices[1..]) // [10, 20, 30, 40]
+
+ // 4. structs and enums
+ // struct User {
+ // age int
+ // name string
+ // pos int = -1 // custom default value
+ // }
+ mut users := User{21, 'Bob', 0}
+ println(users.age) // 21
+
+ // enum Token {
+ // plus
+ // minus
+ // div
+ // mult
+ // }
+
+ // struct Parser {
+ // token Token
+ // }
+ parser := Parser{}
+ if parser.token == .plus || parser.token == .minus
+ || parser.token == .div || parser.token == .mult {
+ // ...
+ }
+
+
+ // 5. Maps
+ number_map := {
+ 'one': 1
+ 'two': 2
+ }
+ println(number_map) // {'one': 1, 'two': 2}
+ println(number_map["one"]) // 1
+ mut m := map[string]int{} // a map with `string` keys and `int` values
+ m['one'] = 1
+ m['two'] = 2
+ println(m['one']) // "1"
+ println(m['bad_key']) // "0"
+ m.delete('two')
+
+ // 6. Conditionals
+ a_number := 10
+ b_number := 20
+ if a_number < b {
+ println('$a_number < $b_number')
+ } else if a_number > b {
+ println('$a_number > $b_number')
+ } else {
+ println('$a_number == $b_number')
+ }
+ num := 777
+ even_odd := if num % 2 == 0 { 'even' } else { 'odd' }
+ println(even_odd)
+
+ match even_odd {
+ 'even' { println('even') }
+ 'odd' { println('odd') }
+ else { println('unknown') }
+ }
+
+ // 7. Loops
+ loops := [1, 2, 3, 4, 5]
+ for lp in loops {
+ println(lp)
+ }
+ loop_names := ['Sam', 'Peter']
+ for i, lname in loop_names {
+ println('$i) $lname')
+ // Output: 0) Sam
+ // 1) Peter
+ }
+ // You can also use break and continue followed by a
+ // label name to refer to an outer for loop:
+ outer: for i := 4; true; i++ {
+ println(i)
+ for {
+ if i < 7 {
+ continue outer
+ } else {
+ break outer
+ }
+ }
+ }
+}
+
+```
+## Further reading
+
+There are more complex concepts to be learnt in V which are available at the
+official [V documentation](https://github.com/vlang/v/blob/master/doc/docs.md).
+
+You can also find more information about the V language at the [official website](https://vlang.io/)
+or check it out at the [v playground](https://v-wasm.vercel.app/).
\ No newline at end of file
diff --git a/vi-vn/xml-vi.html.markdown b/vi-vn/xml-vi.html.markdown
new file mode 100644
index 00000000..7a74c154
--- /dev/null
+++ b/vi-vn/xml-vi.html.markdown
@@ -0,0 +1,170 @@
+---
+language: xml
+filename: learnxml.xml
+contributors:
+ - ['João Farias', 'https://github.com/JoaoGFarias']
+ - ['Rachel Stiyer', 'https://github.com/rstiyer']
+ - ['Deepanshu Utkarsh', 'https://github.com/duci9y']
+translators:
+ - ['Thanh Duy Phan', 'https://github.com/thanhpd']
+lang: vi-vn
+---
+
+XML là ngôn ngữ đánh dấu được thiết kế để lưu trữ và truyền tải dữ liệu. Nó có thể được đọc hiểu bởi cả người và máy.
+
+Không giống như HTML, XML không biểu đạt cách hiển thị hoặc định dạng dữ liệu, chỉ chứa dữ liệu mà thôi.
+
+Có những sự khác biệt rõ ràng giữa **nội dung** và **các đánh dấu**. Nói vắn tắt thì nội dung có thể là bất cứ gì trong khi các đánh dấu được định nghĩa trước.
+
+## Một số định nghĩa và giới thiệu
+
+Các XML Document (Văn bản XML) được cấu thành bởi các _elements (phần tử)_ và chúng có thể có các _attributes (thuộc tính)_ để mô tả, đồng thời cũng có thể chứa các nội dung theo ngữ cảnh và một hoặc nhiều phần tử con. Tất cả XML document phải có một phần tử gốc đóng vai trò tổ tiên cho tất cả các phần tử khác trong văn bản.
+
+Các trình phân tích cú pháp XML (XML Parser) được thiết kế để phân tích rất chặt chẽ, và sẽ dừng phân tích các văn bản không đúng định dạng. Vì vậy cần đảm bảo tất cả văn bản XML tuân theo [Các luật cú pháp XML](http://www.w3schools.com/xml/xml_syntax.asp).
+
+```xml
+
+
+
+
+
+
+
+Nội dung
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Text
+
+
+
+
+
+
+ Văn bản
+
+
+Văn bản
+```
+
+## Một văn bản XML - XML document
+
+Đây là thứ làm cho XML rất linh hoạt do nó giúp con người cũng đọc được. Văn bản sau đây cho ta biết nó định nghĩa một hiệu sách bản ba quyển sách, trong đó có một cuốn tên Learning XML bởi Erik T. Ray. Tất cả những việc này chưa cần phải sử dụng XML Parser.
+
+```xml
+
+
+
+
+ Everyday Italian
+ Giada De Laurentiis
+ 2005
+ 30.00
+
+
+ Harry Potter
+ J K. Rowling
+ 2005
+ 29.99
+
+
+ Learning XML
+ Erik T. Ray
+ 2003
+ 39.95
+
+
+```
+
+## Tính đúng đắn và việc xác minh
+
+Một văn bản XML là _đúng đắn (well-formed)_ nếu nó có cú pháp chính xác. Ty nhiên, ta có thể thêm nhiều ràng buộc vào văn bản, sử dụng Document Type Definition (DTD) - Định dạng loại văn bản. Một văn bản mà các phần tử và thuộc tính được khai báo trong một DTĐ và tuân theo ngữ pháp được đưa ra trong DTD đó được gọi là _valid - được chấp nhận_ và tuân theo DTD bên cạnh việc đúng đắn.
+
+```xml
+
+
+
+
+
+
+ Everyday Italian
+ Giada De Laurentiis
+ 2005
+ 30.00
+
+
+
+
+
+
+
+
+
+
+
+
+
+]>
+
+
+
+
+
+
+
+
+
+
+]>
+
+
+
+ Everyday Italian
+ 30.00
+
+
+```
+
+## DTD Compatibility and XML Schema Definitions (Tương thích DTD và định nghĩa XML Schema)
+
+Hỗ trợ cho DTD khá nhiều do chúng đã quá cũ. Tuy nhiên, nhiều tính năng hiện đại của XML như namespace không được hỗ trợ bởi DTD. XML Schema Definition (XSD) - Định nghĩa lược đồ XML được coi như sẽ thay thế DTD để định nghĩa cấu trúc ngữ pháp của văn bản XML.
+
+## Tra cứu
+
+- [Validate your XML (Xác minh XML)](http://www.xmlvalidation.com)
+
+## Đọc thêm
+
+- [Hướng dẫn XML Schema Definitions](http://www.w3schools.com/schema/)
+- [Hướng dẫn DTD](http://www.w3schools.com/xml/xml_dtd_intro.asp)
+- [Hướng dẫn XML](http://www.w3schools.com/xml/default.asp)
+- [Dùng XPath queries để phân tích cú pháp XML](http://www.w3schools.com/xml/xml_xpath.asp)
diff --git a/xml.html.markdown b/xml.html.markdown
index 2a258d94..630e4c90 100644
--- a/xml.html.markdown
+++ b/xml.html.markdown
@@ -165,7 +165,7 @@ Support for DTDs is ubiquitous because they are so old. Unfortunately, modern XM
## Further Reading
-* [XML Schema Definitions Tutorial](http://www.w3schools.com/schema/)
+* [XML Schema Definitions Tutorial](https://www.w3schools.com/xml/schema_intro.asp)
* [DTD Tutorial](http://www.w3schools.com/xml/xml_dtd_intro.asp)
* [XML Tutorial](http://www.w3schools.com/xml/default.asp)
* [Using XPath queries to parse XML](http://www.w3schools.com/xml/xml_xpath.asp)
diff --git a/yaml.html.markdown b/yaml.html.markdown
index 135213d2..2bb35d42 100644
--- a/yaml.html.markdown
+++ b/yaml.html.markdown
@@ -44,8 +44,8 @@ key with spaces: value
# Yes and No (doesn't matter the case) will be evaluated to boolean
# true and false values respectively.
# To use the actual value use single or double quotes.
-no: no # evaluates to "false": false
-yes: No # evaluates to "true": false
+no: no # evaluates to "no": false
+yes: No # evaluates to "yes": false
not_enclosed: yes # evaluates to "not_enclosed": true
enclosed: "yes" # evaluates to "enclosed": yes
diff --git a/zfs.html.markdown b/zfs.html.markdown
index 6795b1fa..3f5a76b5 100644
--- a/zfs.html.markdown
+++ b/zfs.html.markdown
@@ -3,6 +3,7 @@ category: tool
tool: zfs
contributors:
- ["sarlalian", "http://github.com/sarlalian"]
+ - ["A1EF", "https://github.com/A1EF"]
filename: LearnZfs.txt
---
@@ -25,7 +26,6 @@ RAID setup with ZFS, as ZFS expects to directly manage the underlying disks.
Types of VDEV's
-* stripe (a single disk, no redundancy)
* mirror (n-way mirrors supported)
* raidz
* raidz1 (1-disk parity, similar to RAID 5)
@@ -71,7 +71,7 @@ List zpools
```bash
# Create a raidz zpool
-$ zpool create bucket raidz1 gpt/zfs0 gpt/zfs1 gpt/zfs2
+$ zpool create zroot raidz1 gpt/zfs0 gpt/zfs1 gpt/zfs2
# List ZPools
$ zpool list
@@ -160,22 +160,22 @@ Create datasets
```bash
# Create dataset
-$ zfs create tank/root/data
+$ zfs create zroot/root/data
$ mount | grep data
-tank/root/data on /data (zfs, local, nfsv4acls)
+zroot/root/data on /data (zfs, local, nfsv4acls)
# Create child dataset
-$ zfs create tank/root/data/stuff
+$ zfs create zroot/root/data/stuff
$ mount | grep data
-tank/root/data on /data (zfs, local, nfsv4acls)
-tank/root/data/stuff on /data/stuff (zfs, local, nfsv4acls)
+zroot/root/data on /data (zfs, local, nfsv4acls)
+zroot/root/data/stuff on /data/stuff (zfs, local, nfsv4acls)
# Create Volume
$ zfs create -V zroot/win_vm
$ zfs list zroot/win_vm
NAME USED AVAIL REFER MOUNTPOINT
-tank/win_vm 4.13G 17.9G 64K -
+zroot/win_vm 4.13G 17.9G 64K -
```
List datasets
@@ -213,28 +213,28 @@ zroot/var/tmp@daily-2015-10-15
Rename datasets
```bash
-$ zfs rename tank/root/home tank/root/old_home
-$ zfs rename tank/root/new_home tank/root/home
+$ zfs rename zroot/root/home zroot/root/old_home
+$ zfs rename zroot/root/new_home zroot/root/home
```
Delete dataset
```bash
# Datasets cannot be deleted if they have any snapshots
-$ zfs destroy tank/root/home
+$ zfs destroy zroot/root/home
```
Get / set properties of a dataset
```bash
# Get all properties
-$ zfs get all zroot/usr/home │157 # Create Volume
-NAME PROPERTY VALUE SOURCE │158 $ zfs create -V zroot/win_vm
-zroot/home type filesystem - │159 $ zfs list zroot/win_vm
-zroot/home creation Mon Oct 20 14:44 2014 - │160 NAME USED AVAIL REFER MOUNTPOINT
-zroot/home used 11.9G - │161 tank/win_vm 4.13G 17.9G 64K -
-zroot/home available 94.1G - │162 ```
-zroot/home referenced 11.9G - │163
+$ zfs get all zroot/usr/home
+NAME PROPERTY VALUE SOURCE
+zroot/home type filesystem -
+zroot/home creation Mon Oct 20 14:44 2014 -
+zroot/home used 11.9G -
+zroot/home available 94.1G -
+zroot/home referenced 11.9G -
zroot/home mounted yes -
...
@@ -244,7 +244,7 @@ NAME PROPERTY VALUE SOURCE
zroot/home compression off default
# Set property on dataset
-$ zfs set compression=gzip-9 mypool/lamb
+$ zfs set compression=lz4 zroot/lamb
# Get a set of properties from all datasets
$ zfs list -o name,quota,reservation
@@ -283,16 +283,16 @@ Create snapshots
```bash
# Create a snapshot of a single dataset
-zfs snapshot tank/home/sarlalian@now
+zfs snapshot zroot/home/sarlalian@now
# Create a snapshot of a dataset and its children
-$ zfs snapshot -r tank/home@now
+$ zfs snapshot -r zroot/home@now
$ zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
-tank/home@now 0 - 26K -
-tank/home/sarlalian@now 0 - 259M -
-tank/home/alice@now 0 - 156M -
-tank/home/bob@now 0 - 156M -
+zroot/home@now 0 - 26K -
+zroot/home/sarlalian@now 0 - 259M -
+zroot/home/alice@now 0 - 156M -
+zroot/home/bob@now 0 - 156M -
...
```
@@ -300,10 +300,10 @@ Destroy snapshots
```bash
# How to destroy a snapshot
-$ zfs destroy tank/home/sarlalian@now
+$ zfs destroy zroot/home/sarlalian@now
# Delete a snapshot on a parent dataset and its children
-$ zfs destroy -r tank/home/sarlalian@now
+$ zfs destroy -r zroot/home/sarlalian@now
```
@@ -311,10 +311,10 @@ Renaming Snapshots
```bash
# Rename a snapshot
-$ zfs rename tank/home/sarlalian@now tank/home/sarlalian@today
-$ zfs rename tank/home/sarlalian@now today
+$ zfs rename zroot/home/sarlalian@now zroot/home/sarlalian@today
+$ zfs rename zroot/home/sarlalian@now today
-$ zfs rename -r tank/home@now @yesterday
+$ zfs rename -r zroot/home@now @yesterday
```
Accessing snapshots
@@ -328,26 +328,26 @@ Sending and Receiving
```bash
# Backup a snapshot to a file
-$ zfs send tank/home/sarlalian@now | gzip > backup_file.gz
+$ zfs send zroot/home/sarlalian@now | gzip > backup_file.gz
# Send a snapshot to another dataset
-$ zfs send tank/home/sarlalian@now | zfs recv backups/home/sarlalian
+$ zfs send zroot/home/sarlalian@now | zfs recv backups/home/sarlalian
# Send a snapshot to a remote host
-$ zfs send tank/home/sarlalian@now | ssh root@backup_server 'zfs recv tank/home/sarlalian'
+$ zfs send zroot/home/sarlalian@now | ssh root@backup_server 'zfs recv zroot/home/sarlalian'
# Send full dataset with snapshots to new host
-$ zfs send -v -R tank/home@now | ssh root@backup_server 'zfs recv tank/home'
+$ zfs send -v -R zroot/home@now | ssh root@backup_server 'zfs recv zroot/home'
```
Cloning Snapshots
```bash
# Clone a snapshot
-$ zfs clone tank/home/sarlalian@now tank/home/sarlalian_new
+$ zfs clone zroot/home/sarlalian@now zroot/home/sarlalian_new
# Promoting the clone so it is no longer dependent on the snapshot
-$ zfs promote tank/home/sarlalian_new
+$ zfs promote zroot/home/sarlalian_new
```
### Putting it all together
diff --git a/zh-cn/asciidoc-cn.html.markdown b/zh-cn/asciidoc-cn.html.markdown
index 74eed445..0709e8c1 100644
--- a/zh-cn/asciidoc-cn.html.markdown
+++ b/zh-cn/asciidoc-cn.html.markdown
@@ -1,6 +1,6 @@
---
language: asciidoc
-filename: asciidoc-cn.md
+filename: asciidoc-cn.adoc
contributors:
- ["Ryan Mavilia", "http://unoriginality.rocks/"]
- ["Abel Salgado Romero", "https://twitter.com/abelsromero"]
diff --git a/zh-cn/awk-cn.html.markdown b/zh-cn/awk-cn.html.markdown
index bac833a6..02f1f7d5 100644
--- a/zh-cn/awk-cn.html.markdown
+++ b/zh-cn/awk-cn.html.markdown
@@ -179,7 +179,7 @@ function string_functions( localvar, arr) {
# 都是返回替换的个数
localvar = "fooooobar"
sub("fo+", "Meet me at the ", localvar) # localvar => "Meet me at the bar"
- gsub("e", ".", localvar) # localvar => "m..t m. at th. bar"
+ gsub("e", ".", localvar) # localvar => "M..t m. at th. bar"
# 搜索匹配正则的字符串
# index() 也是搜索, 不支持正则
diff --git a/zh-cn/c-cn.html.markdown b/zh-cn/c-cn.html.markdown
index dd4445f7..851f2981 100644
--- a/zh-cn/c-cn.html.markdown
+++ b/zh-cn/c-cn.html.markdown
@@ -474,7 +474,7 @@ void testFunc() {
// 用户自定义类型和结构
///////////////////////////////////////
-// Typedefs可以创建类型别名
+// typedef 可以创建类型别名
typedef int my_type;
my_type my_type_var = 0;
diff --git a/zh-cn/cobol-cn.html.markdown b/zh-cn/cobol-cn.html.markdown
new file mode 100644
index 00000000..08eb36fb
--- /dev/null
+++ b/zh-cn/cobol-cn.html.markdown
@@ -0,0 +1,192 @@
+---
+language: COBOL
+filename: learn-cn.COB
+contributors:
+ - ["Hyphz", "http://github.com/hyphz/"]
+translators:
+ - ["GOLGO11", "https://github.com/GOLGO11/"]
+lang: zh-cn
+---
+COBOL是一门面向商业的语言,它从1960年最初设计以来被修订过数次。它被宣称仍然有超过80%的机构在使用它。
+
+```cobol
+ *COBOL. 最好是按照它1985年的标准来编程。
+ *用附带GnuCOBOL编译器的OpenCobolIDE 4.7.6来编译。
+
+ *COBOL在老版(COBOL-85)和新版(COBOL-2002以及COBOL-2014)之间有明显的差别。
+ *老版COBOL要求编码的前一到六列是空着的(它们被用来存储穿孔卡片的序列号...
+ *第七列的一个“*”符号表示注释的开始。
+ *在老版COBOL中,一条以*开头的注释最长只能占一行,
+ *新版COBOL不需要额外的列来补序列号,并且用“*>" 来注释,允许在行中开始注释
+ *老版COBOL也强加了对最大行长度的限制
+ *关键字在老版COBOL中必须大写,
+ *但在新版COBOL中不区分大小写
+ *虽然新版COBOL允许你编写大小写混合的代码
+ *但是在大多数情况下编写COBOL代码时全用大写字符
+ *大多数专业的COBOL开发者都是这么做的。
+ *COBOL语句以句点结尾。
+
+ *COBOL代码被拆成了四个部。
+ *各部按顺序,它们是:
+ *IDENTIFICATION DIVSION.(标识部)
+ *ENVIRONMENT DIVISION.(环境部)
+ *DATA DIVISION.(数据部)
+ *PROCEDURE DIVISION.(过程部)
+
+ *第一步,我们必须给我们的程序一个ID。
+ *Identification division 也能包含其他的值,
+ *但它们都只是程序的元数据。Program-id是唯一一个必须给出的值。
+ IDENTIFICATION DIVISION.
+ PROGRAM-ID. LEARN.
+ AUTHOR. JOHN DOE.
+ DATE-WRITTEN. 05/02/2020.
+
+ *让我们来声明一些变量。
+ *我们要在DATA DIVISION的WORKING-STORAGE节来完成这个事情。
+ *每个数据项(又名变量)从一个级别编号开始。
+ *然后是数据项的名字,后边再跟着一个picture关键字,
+ *来描述这个变量将要包含的数据的类型。
+ *几乎所有的COBOL开发者都会把PICTURE简写为PIC。
+ *A代表字母,X代表字母和数字,9代表数字。
+
+ *举例:
+ 01 MYNAME PIC xxxxxxxxxx. *> 十个字符的字符串。
+
+ *但是逐个数那些x会导致错误,
+ *所以以上代码可以,并且应该
+ *这样重写:
+ 01 MYNAME PIC X(10).
+
+ *这是几个更多的例子:
+ 01 AGE PIC 9(3). *> 数字最多三位
+ 01 LAST_NAME PIC X(10). *> 字符串最多十个字符
+
+ *在COBOL里,一行中多个空格和一个空格的效果是一样的, 所以通常
+ *情况下都用多个空格排列代码来便于
+ *其他的开发者阅读。
+ 01 inyear picture s9(7). *> S 使数字为正数.
+ *> 括号里意思是重复7次9,
+ *> 即六位数字(不是数组)
+
+ *现在让我们来写一点儿代码。这是一个简单的Hello World程序。
+ IDENTIFICATION DIVISION.
+ PROGRAM-ID. HELLO.
+ DATA DIVISION.
+ WORKING-STORAGE SECTION.
+ 01 THE-MESSAGE PIC X(20).
+ PROCEDURE DIVSION.
+ DISPLAY "STARTING PROGRAM".
+ MOVE "HELLO WORLD" TO THE-MESSAGE.
+ DISPLAY THE-MESSAGE.
+ STOP RUN.
+
+ *以上的代码会输出:
+ *STARTING PROGRAM
+ *HELLO WORLD
+
+
+
+ ********用COBOL可以做数学运算***************
+ ADD 1 TO AGE GIVING NEW-AGE.
+ SUBTRACT 1 FROM COUNT.
+ DIVIDE VAR-1 INTO VAR-2 GIVING VAR-3.
+ COMPUTE TOTAL-COUNT = COUNT1 PLUS COUNT2.
+
+
+ *********PERFORM********************
+ *PERFORM关键字允许你跳到代码中其他特殊的代码段,
+ *当这段特殊的代码被执行完后继续回来执行下面的可执行语句。
+ *你必须把PERFORM这个词写完整,不可以缩写它。
+
+ IDENTIFICATION DIVISION.
+ PROGRAM-ID. HELLOCOBOL.
+
+ PROCEDURE DIVISION.
+ FIRST-PARA.
+ DISPLAY 'THIS IS IN FIRST-PARA'.
+ PERFORM THIRD-PARA THRU FOURTH-PARA. *>跳过second-para,执行3rd&4th
+ *> 之后当third和fourth执行完,
+ *> 回到这里继续往下执行直到遇到STOP RUN.
+
+ SECOND-PARA.
+ DISPLAY 'THIS IS IN SECOND-PARA'.
+ STOP RUN.
+
+ THIRD-PARA.
+ DISPLAY 'THIS IS IN THIRD-PARA'.
+
+ FOURTH-PARA.
+ DISPLAY 'THIS IS IN FOURTH-PARA'.
+
+
+ *当你编译执行以上程序时,它会生成以下结果:
+ THIS IS IN FIRST-PARA
+ THIS IS IN THIRD-PARA
+ THIS IS IN FOURTH-PARA
+ THIS IS IN SECOND-PARA
+
+
+ **********用STRING关键字把变量组合到一起************
+
+ *现在是时候学习两个类似的COBOL动词了:string和unstring。.
+
+ *string动词经常被用来连接两个或多个字符串(把它们拼在一起)。
+ *没什么特别的,Unstring被用来把一个字符串拆分成两个或多个更小的字符串。
+ *当你在程序中使用string或unstring时不要忘记使用”delimited by“,这个很重要。
+
+ IDENTIFICATION DIVISION.
+ PROGRAM-ID. LEARNING.
+ ENVIRONMENT DIVISION.
+ DATA DIVISION.
+ WORKING-STORAGE SECTION.
+ 01 FULL-NAME PIC X(20).
+ 01 FIRST-NAME PIC X(13) VALUE "BOB GIBBERISH".
+ 01 LAST-NAME PIC X(5) VALUE "COBB".
+ PROCEDURE DIVISION.
+ STRING FIRST-NAME DELIMITED BY SPACE
+ " "
+ LAST-NAME DELIMITED BY SIZE
+ INTO FULL-NAME
+ END-STRING.
+ DISPLAY "THE FULL NAME IS: "FULL-NAME.
+ STOP RUN.
+
+
+ *以上代码将会输出:
+ THE FULL NAME IS: BOB COBB
+
+
+ *让我们来看看为什么是这样。
+
+ *首先,我们在DATA DIVISION声明了所有的变量,
+ *包括我们想存储string命令生成的新字符串用到的的变量。
+
+ *这个操作过程在PROCEDURE DIVISION完成。
+ *我们从STRING 关键字开始,到END-STRING结束。
+ *在它们之间我们列出我们想要组合变量形成更大的主变量的过程。
+ *这里,我们组合了FIRST-NAME, 一个空格和LAST-NAME。
+
+ *跟在FIRST-NAME和LAST-NAME后面的DELIMITED BY短语告诉程序我们想要在各自变量上截取字符的规则。
+ *DELIMITED BY SPACE告诉程序从最开始截取字符直到遇到一个空格。
+ *DELIMITED BY SIZE告诉程序截取字符的完整长度。
+ *我们在FIRST-NAME后面使用DELIMITED BY SPACE,字符串中的GIBBERISH部分就被忽略了。
+
+ *为了更清楚,改变代码中的第10行如下:
+
+ STRING FIRST-NAME DELIMITED BY SIZE
+
+ *然后重新执行程序. 这次的输出变成:
+
+ THE FULL NAME IS: BOB GIBBERISH COBB
+
+
+
+
+
+
+```
+
+## 想了解更多吗?
+
+* [GnuCOBOL](https://sourceforge.net/projects/open-cobol/)
+
diff --git a/zh-cn/csharp-cn.html.markdown b/zh-cn/csharp-cn.html.markdown
index 0bad34ce..b6cc70c0 100644
--- a/zh-cn/csharp-cn.html.markdown
+++ b/zh-cn/csharp-cn.html.markdown
@@ -5,45 +5,64 @@ contributors:
- ["Max Yankov", "https://github.com/golergka"]
- ["Melvyn Laïly", "http://x2a.yt"]
- ["Shaun McCarthy", "http://www.shaunmccarthy.com"]
+ - ["Wouter Van Schandevijl", "http://github.com/laoujin"]
+ - ["Jo Pearce", "http://github.com/jdpearce"]
+ - ["Chris Zimmerman", "https://github.com/chriszimmerman"]
+ - ["Shawn McGuire", "https://github.com/bigbash"]
translators:
- ["Jakukyo Friel", "http://weakish.github.io"]
+ - ["CatfishWen", "http://catfishwen.github.io"]
filename: LearnCSharp-cn.cs
lang: zh-cn
---
+C#是一种优雅且类型安全的面向对象的语言,使开发人员能够构建运行在跨平台的.NET框架上,安全且健壮的应用程序。
-C#是一个优雅的、类型安全的面向对象语言。使用C#,开发者可以在.NET框架下构建安全、健壮的应用程序。
-
-[更多关于C#的介绍](http://msdn.microsoft.com/en-us/library/vstudio/z1zx9t92.aspx)
+[更多关于C#的介绍](https://learn.microsoft.com/zh-cn/dotnet/csharp/tour-of-csharp/)
```c#
// 单行注释以 // 开始
/*
多行注释是这样的
*/
-///
-/// XML文档注释
-///
-// 声明应用用到的命名空间
+///
+/// 这是 XML文档注释
+/// 可用于生成外部文档或在 IDE 中提供上下文帮助
+///
+/// 这是 firstParam 参数的文档
+/// 这是函数返回值的信息
+public void MethodOrClassOrOtherWithParsableHelp(string firstParam) { }
+
+// 声明这段源码使用到的命名空间
+// 下面的命名空间都是标准 .NET Framework 类库的一部分
using System;
using System.Collections.Generic;
-using System.Data.Entity;
using System.Dynamic;
using System.Linq;
-using System.Linq.Expressions;
using System.Net;
using System.Threading.Tasks;
using System.IO;
-// 定义作用域,将代码组织成包
+// 但是这个并不是标准类库:
+using System.Data.Entity;
+// 为了在下方使用它,你需要添加一个 dll 引用
+// 你可以使用 NuGet 包管理器进行安装
+// `Install-Package EntityFramework`
+
+// 命名空间 Namespaces 可用于将一定的代码组织为 “包” 或者 “模块”
+// 你可以在其他文件中这样引用:using Learning.CSharp;
+
+// 在 C# 10 以后,你也可以这样定义命名空间。这被称为 file-scoped namespaces(文件范围的命名空间).
+// namespace Learning.CSharp;
+
namespace Learning
{
// 每个 .cs 文件至少需要包含一个和文件名相同的类
- // 你可以不这么干,但是这样不好。
+ // 你可以不这么干,但是这样并不推荐。
public class LearnCSharp
{
- // 基本语法 - 如果你以前用过 Java 或 C++ 的话,可以直接跳到后文「有趣的特性」
+ // 基本语法 - 如果你以前用过 Java 或 C++ 的话,可以直接跳到后文「有趣的特性」
public static void Syntax()
{
// 使用 Console.WriteLine 打印信息
@@ -53,7 +72,7 @@ namespace Learning
" Double: " + 3.14 +
" Boolean: " + true);
- // 使用 Console.Write 打印,不带换行符号
+ // 使用 Console.Write 打印将不会换行
Console.Write("Hello ");
Console.Write("World");
@@ -113,7 +132,7 @@ namespace Learning
char charFromString = fooString[1]; // => 'e'
// 字符串不可修改: fooString[1] = 'X' 是行不通的;
- // 根据当前的locale设定比较字符串,大小写不敏感
+ // 根据当前的区域格式设置比较字符串,大小写不敏感
string.Compare(fooString, "x", StringComparison.CurrentCultureIgnoreCase);
// 基于sprintf的字符串格式化
@@ -123,12 +142,13 @@ namespace Learning
DateTime fooDate = DateTime.Now;
Console.WriteLine(fooDate.ToString("hh:mm, dd MMM yyyy"));
- // 使用 @ 符号可以创建跨行的字符串。使用 "" 来表示 "
+ // 逐字字符串
+ // 使用 @ 符号可以创建跨行的字符串。使用 "" 来表示 "
string bazString = @"Here's some stuff
on a new line! ""Wow!"", the masses cried";
- // 使用const或read-only定义常量
- // 常量在编译期演算
+ // 使用 const 或 read-only 定义常量
+ // 常量在编译阶段演算
const int HOURS_I_WORK_PER_WEEK = 9001;
///////////////////////////////////////////////////
@@ -136,7 +156,7 @@ on a new line! ""Wow!"", the masses cried";
///////////////////////////////////////////////////
// 数组 - 从0开始计数
- // 声明数组时需要确定数组长度
+ // 声明数组时需要指定数组长度
// 声明数组的格式如下:
// [] = new [];
int[] intArray = new int[10];
@@ -155,8 +175,8 @@ on a new line! ""Wow!"", the masses cried";
// List = new List();
List intList = new List();
List stringList = new List();
- List z = new List { 9000, 1000, 1337 }; // i
- // <>用于泛型 - 参考下文
+ List z = new List { 9000, 1000, 1337 }; // 初始化
+ // <> 用于泛型 - 参考下文
// 列表无默认值
// 访问列表元素时必须首先添加元素
@@ -164,18 +184,18 @@ on a new line! ""Wow!"", the masses cried";
Console.WriteLine("intList @ 0: " + intList[0]);
// 其他数据结构:
- // 堆栈/队列
- // 字典 (哈希表的实现)
- // 哈希集合
- // 只读集合
- // 元组 (.Net 4+)
+ // Stack 堆栈 / Queue 队列
+ // Dictionary 字典 (哈希表的实现)
+ // HashSet 哈希集合
+ // Read-only Collections 只读集合
+ // Tuple 元组 (.Net 4+)
///////////////////////////////////////
// 操作符
///////////////////////////////////////
Console.WriteLine("\n->Operators");
- int i1 = 1, i2 = 2; // 多重声明的简写形式
+ int i1 = 1, i2 = 2; // 声明多个变量的简写形式
// 算术直截了当
Console.WriteLine(i1 + i2 - i1 * 3 / 7); // => 3
@@ -214,7 +234,7 @@ on a new line! ""Wow!"", the masses cried";
///////////////////////////////////////
Console.WriteLine("\n->Control Structures");
- // 类似C的if语句
+ // 类似 C 的 if 语句
int j = 10;
if (j == 10)
{
@@ -239,7 +259,7 @@ on a new line! ""Wow!"", the masses cried";
int fooWhile = 0;
while (fooWhile < 100)
{
- //迭代 100 次, fooWhile 0->99
+ // 迭代 100 次, fooWhile 0->99
fooWhile++;
}
@@ -247,14 +267,21 @@ on a new line! ""Wow!"", the masses cried";
int fooDoWhile = 0;
do
{
- //迭代 100 次, fooDoWhile 0->99
+ // 迭代 100 次, fooDoWhile 0->99
+ if (false)
+ continue; // 跳过本次迭代
+
fooDoWhile++;
+
+ if (fooDoWhile == 50)
+ break; // 结束整个循环
+
} while (fooDoWhile < 100);
- //for 循环结构 => for(<初始条件>; <条件>; <步>)
+ // for 循环结构 => for(<初始条件>; <条件>; <步>)
for (int fooFor = 0; fooFor < 10; fooFor++)
{
- //迭代10次, fooFor 0->9
+ // 迭代10次, fooFor 0->9
}
// foreach循环
@@ -269,7 +296,7 @@ on a new line! ""Wow!"", the masses cried";
}
// Switch 语句
- // switch 适用于 byte、short、char和int 数据类型。
+ // switch 适用于 byte、short、char 和 int 数据类型。
// 同样适用于可枚举的类型
// 包括字符串类, 以及一些封装了原始值的类:
// Character、Byte、Short和Integer。
@@ -307,46 +334,63 @@ on a new line! ""Wow!"", the masses cried";
// 转换字符串为整数
// 转换失败会抛出异常
- int.Parse("123");//返回整数类型的"123"
+ int.Parse("123"); // 返回整数类型的"123"
- // TryParse会尝试转换类型,失败时会返回缺省类型
+ // TryParse 会尝试转换类型,失败时会返回缺省类型
// 例如 0
int tryInt;
if (int.TryParse("123", out tryInt)) // Funciton is boolean
Console.WriteLine(tryInt); // 123
// 转换整数为字符串
- // Convert类提供了一系列便利转换的方法
+ // Convert 类提供了一系列方便转换类型的方法
+
+ // 比如 字符串 与 int 之间
+
+ // 最佳方法
+ bool result = int.TryParse(string, out var integer)
+ int.Parse(string);
+
+ // 不推荐
Convert.ToString(123);
- // or
+
+ // Int 到字符串
tryInt.ToString();
+
+ // 转换
+ // 显式转换 decimal 类型的 15 为 int 类型
+ // 然后隐式转换为 long 类型
+ long x = (int) 15M;
}
///////////////////////////////////////
- // 类
+ // 类 - 请参阅文件末尾的定义
///////////////////////////////////////
public static void Classes()
{
// 参看文件尾部的对象声明
- // 使用new初始化对象
+ // 使用 new 初始化对象
Bicycle trek = new Bicycle();
// 调用对象的方法
- trek.SpeedUp(3); // 你应该一直使用setter和getter方法
+ trek.SpeedUp(3); // 你应该一直使用 setter 和 getter 方法
trek.Cadence = 100;
// 查看对象的信息.
Console.WriteLine("trek info: " + trek.Info());
- // 实例化一个新的Penny Farthing
+ // 实例化一个新的 Penny Farthing 对象
PennyFarthing funbike = new PennyFarthing(1, 10);
Console.WriteLine("funbike info: " + funbike.Info());
Console.Read();
} // 结束main方法
- // 终端程序 终端程序必须有一个main方法作为入口
+ // record 在 C# 9 及以后可用, 这基本上是类的语法糖. record 对象是不可变的 immutable*.
+ public record ARecord(string Csharp);
+
+ // 终端程序入口 终端程序必须有一个 main 方法作为入口
public static void Main(string[] args)
{
OtherInterestingFeatures();
@@ -359,11 +403,11 @@ on a new line! ""Wow!"", the masses cried";
// 默认方法签名
public // 可见性
- static // 允许直接调用类,无需先创建实例
- int, //返回值
+ static // 允许从类直接调用,无需先创建实例
+ int // 返回值类型
MethodSignatures(
- int maxCount, // 第一个变量,类型为整型
- int count = 0, // 如果没有传入值,则缺省值为0
+ int maxCount, // 第一个参数,类型为整型
+ int count = 0, // 如果没有传入值,则缺省值为 0
int another = 3,
params string[] otherParams // 捕获其他参数
)
@@ -371,17 +415,22 @@ on a new line! ""Wow!"", the masses cried";
return -1;
}
- // 方法可以重名,只要签名不一样
- public static void MethodSignature(string maxCount)
+ // 方法可以重名,只要方法签名不一样
+ // 一个只有返回值类型不同的方法
+ public static void MethodSignatures(
+ ref int maxCount, // 通过引用传递
+ out int count)
{
+ // 通过 'count' 参数传入的值将在该方法外保留值 15
+ count = 15; // 必须在离开方法之前为 out 参数赋值
}
- //泛型
- // TKey和TValue类由用用户调用函数时指定。
- // 以下函数模拟了Python的SetDefault
+ // 泛型
+ // TKey 和 TValue 由用户调用方法时指定
+ // 以下函数模拟了 Python 的 SetDefault
public static TValue SetDefault(
- IDictionary dictionary,
- TKey key,
+ IDictionary dictionary,
+ TKey key,
TValue defaultItem)
{
TValue result;
@@ -393,55 +442,125 @@ on a new line! ""Wow!"", the masses cried";
// 你可以限定传入值的范围
public static void IterateAndPrint(T toPrint) where T: IEnumerable
{
- // 我们可以进行迭代,因为T是可枚举的
+ // 我们可以进行迭代,因为 T 是可枚举的
foreach (var item in toPrint)
- // ittm为整数
+ // item 为整数
Console.WriteLine(item.ToString());
}
+ // YIELD
+ // 使用 "yield" 关键字表明它出现的方法是一个迭代器 Iterator
+ // (这意味着你可以在 foreach 循环中使用它)
+ public static IEnumerable YieldCounter(int limit = 10)
+ {
+ for (var i = 0; i < limit; i++)
+ yield return i;
+ }
+
+ // 你可以这样调用它
+ public static void PrintYieldCounterToConsole()
+ {
+ foreach (var counter in YieldCounter())
+ Console.WriteLine(counter);
+ }
+
+ // 你可以在一个方法中使用多个 "yield return"
+ public static IEnumerable ManyYieldCounter()
+ {
+ yield return 0;
+ yield return 1;
+ yield return 2;
+ yield return 3;
+ }
+
+ // 你也可以使用 "yield break" 停止该迭代器
+ // 此方法只会返回从 0 到 limit 的一半值。
+ public static IEnumerable YieldCounterWithBreak(int limit = 10)
+ {
+ for (var i = 0; i < limit; i++)
+ {
+ if (i > limit / 2) yield break;
+ yield return i;
+ }
+ }
+
public static void OtherInterestingFeatures()
{
- // 可选参数
+ // 可选参数
MethodSignatures(3, 1, 3, "Some", "Extra", "Strings");
MethodSignatures(3, another: 3); // 显式指定参数,忽略可选参数
+ // 使用 ref 和 out 参数
+ int maxCount = 0, count; // ref 参数必须有值
+ MethodSignatures(ref maxCount, out count);
+
// 扩展方法
int i = 3;
- i.Print(); // 参见下面的定义
+ i.Print(); // 参见下面的定义
- // 可为null的类型 对数据库交互、返回值很有用
+ // 可为 null 的类型 对数据库交互、返回值很有用
// 任何值类型 (i.e. 不为类) 添加后缀 ? 后会变为可为null的值
// <类型>? <变量名> = <值>
int? nullable = null; // Nullable 的简写形式
Console.WriteLine("Nullable variable: " + nullable);
bool hasValue = nullable.HasValue; // 不为null时返回真
+
// ?? 是用于指定默认值的语法糖
// 以防变量为null的情况
int notNullable = nullable ?? 0; // 0
+ // ?. 是另一个可空类型的操作符 - 简写 null 检查
+ nullable?.Print(); // 当可空类型值不为 null 的时候调用 Print() 拓展方法
+
// 变量类型推断 - 你可以让编译器推断变量类型:
var magic = "编译器确定magic是一个字符串,所以仍然是类型安全的";
- // magic = 9; // 不工作,因为magic是字符串,而不是整数。
+ // magic = 9; // 不工作,因为magic是字符串,而不是整数。
// 泛型
//
- var phonebook = new Dictionary() {
+ var phonebook = new Dictionary() {
{"Sarah", "212 555 5555"} // 在电话簿中加入新条目
};
- // 调用上面定义为泛型的SETDEFAULT
- Console.WriteLine(SetDefault(phonebook, "Shaun", "No Phone")); // 没有电话
- // 你不用指定TKey、TValue,因为它们会被隐式地推导出来
+ // 调用上面定义为泛型的 SETDEFAULT
+ Console.WriteLine(SetDefault(phonebook, "Shaun", "No Phone")); // No Phone
+ // 你不用指定 TKey、TValue 的类型
+ // 因为它们会被隐式地推导出来
Console.WriteLine(SetDefault(phonebook, "Sarah", "No Phone")); // 212 555 5555
// lambda表达式 - 允许你用一行代码搞定函数
Func square = (x) => x * x; // 最后一项为返回值
Console.WriteLine(square(3)); // 9
- // 可抛弃的资源管理 - 让你很容易地处理未管理的资源
- // 大多数访问未管理资源 (文件操作符、设备上下文, etc.)的对象
- // 都实现了IDisposable接口。
- // using语句会为你清理IDisposable对象。
+ // 错误处理 - 应对不确定的世界
+ try
+ {
+ var funBike = PennyFarthing.CreateWithGears(6);
+
+ // 将不再执行,因为 CreateWithGears 抛出异常
+ string some = "";
+ if (true) some = null;
+ some.ToLower(); // 抛出 NullReferenceException
+ }
+ catch (NotSupportedException)
+ {
+ Console.WriteLine("Not so much fun now!");
+ }
+ catch (Exception ex) // 捕获所有其他异常
+ {
+ throw new ApplicationException("It hit the fan", ex);
+ // throw; // 重新抛出异常并保留调用堆栈
+ }
+ // catch { } // 捕获所有没有捕获的异常
+ finally
+ {
+ // 在 try 或 catch 之后执行
+ }
+
+ // 可抛弃的资源管理 - 让你很容易地处理未托管的资源
+ // 大多数访问未托管资源 (文件句柄、设备上下文, etc.) 的对象
+ // 都实现了 IDisposable 接口。
+ // using语句会为你清理 IDisposable 对象
using (StreamWriter writer = new StreamWriter("log.txt"))
{
writer.WriteLine("这里没有什么可疑的东西");
@@ -450,29 +569,23 @@ on a new line! ""Wow!"", the masses cried";
}
// 并行框架
- // http://blogs.msdn.com/b/csharpfaq/archive/2010/06/01/parallel-programming-in-net-framework-4-getting-started.aspx
- var websites = new string[] {
- "http://www.google.com", "http://www.reddit.com",
- "http://www.shaunmccarthy.com"
- };
- var responses = new Dictionary();
-
- // 为每个请求新开一个线程
- // 在运行下一步前合并结果
- Parallel.ForEach(websites,
- new ParallelOptions() {MaxDegreeOfParallelism = 3}, // max of 3 threads
- website =>
- {
- // Do something that takes a long time on the file
- using (var r = WebRequest.Create(new Uri(website)).GetResponse())
- {
- responses[website] = r.ContentType;
- }
- });
+ // https://learn.microsoft.com/zh-cn/dotnet/standard/parallel-programming/data-parallelism-task-parallel-library
- // 直到所有的请求完成后才会运行下面的代码
- foreach (var key in responses.Keys)
- Console.WriteLine("{0}:{1}", key, responses[key]);
+ var words = new List {"dog", "cat", "horse", "pony"};
+
+ Parallel.ForEach(words,
+ new ParallelOptions() { MaxDegreeOfParallelism = 4 },
+ word =>
+ {
+ Console.WriteLine(word);
+ }
+ );
+
+ // 运行它会产生不同的输出
+ // 因为每个线程在不同的时间完成
+ // 一些可能的输出是:
+ // cat dog horse pony
+ // dog horse pony cat
// 动态对象(配合其他语言使用很方便)
dynamic student = new ExpandoObject();
@@ -486,10 +599,10 @@ on a new line! ""Wow!"", the masses cried";
// IQUERYABLE - 几乎所有的集合都实现了它,
// 带给你 Map / Filter / Reduce 风格的方法
var bikes = new List();
- bikes.Sort(); // Sorts the array
+ bikes.Sort(); // 排序 array
bikes.Sort((b1, b2) => b1.Wheels.CompareTo(b2.Wheels)); // 根据车轮数排序
var result = bikes
- .Where(b => b.Wheels > 3) // 筛选 - 可以连锁使用 (返回IQueryable)
+ .Where(b => b.Wheels > 3) // 筛选 - 可以连锁使用 (返回 IQueryable)
.Where(b => b.IsBroken && b.HasTassles)
.Select(b => b.ToString()); // Map - 这里我们使用了select,所以结果是IQueryable
@@ -502,19 +615,19 @@ on a new line! ""Wow!"", the masses cried";
Console.WriteLine(bikeSummary.Name);
// ASPARALLEL
- // 邪恶的特性 —— 组合了linq和并行操作
+ // 这就是事情开始棘手的地方 —— 组合了 linq 和并行操作
var threeWheelers = bikes.AsParallel().Where(b => b.Wheels == 3).Select(b => b.Name);
// 以上代码会并发地运行。会自动新开线程,分别计算结果。
// 适用于多核、大数据量的场景。
- // LINQ - 将IQueryable映射到存储,延缓执行
+ // LINQ - 映射一组 IQueryable 对象,并延迟执行
// 例如 LinqToSql 映射数据库, LinqToXml 映射XML文档
var db = new BikeRespository();
- // 执行被延迟了,这对于查询数据库来说很好
+ // 执行被延迟了,这对于查询数据库来说非常好
var filter = db.Bikes.Where(b => b.HasTassles); // 不运行查询
if (42 > 6) // 你可以不断地增加筛选,包括有条件的筛选,例如用于“高级搜索”功能
- filter = filter.Where(b => b.IsBroken); // 不运行查询
+ filter = filter.Where(b => b.IsBroken); // 不运行查询
var query = filter
.OrderBy(b => b.Wheels)
@@ -541,15 +654,64 @@ on a new line! ""Wow!"", the masses cried";
Console.WriteLine(obj.ToString());
}
}
+
+
+ // 委托 和 事件
+ public class DelegateTest
+ {
+ public static int count = 0;
+ public static int Increment()
+ {
+ // 增加 count 然后返回它
+ return ++count;
+ }
+
+ // 委托是一个方法的引用.
+ // 要引用 Increment 方法,
+ // 首先声明一个具有相同签名的委托,
+ // i.e. 不带参数并返回 int
+ public delegate int IncrementDelegate();
+
+ // 事件也可用于触发委托
+ // 使用委托类型创建事件
+ public static event IncrementDelegate MyEvent;
+
+ static void Main(string[] args)
+ {
+ // 通过实例化委托来引用 Increment 方法
+ // 并将方法本身作为参数传递
+ IncrementDelegate inc = new IncrementDelegate(Increment);
+ Console.WriteLine(inc()); // => 1
+
+ // 委托可以用 + 运算符组合
+ IncrementDelegate composedInc = inc;
+ composedInc += inc;
+ composedInc += inc;
+
+ // composedInc 将执行 Increment 3 次
+ Console.WriteLine(composedInc()); // => 4
+
+
+ // 为事件订阅与委托
+ MyEvent += new IncrementDelegate(Increment);
+ MyEvent += new IncrementDelegate(Increment);
+
+ // 触发事件
+ // ie. 运行这个事件所有的委托订阅
+ Console.WriteLine(MyEvent()); // => 6
+ }
+ }
+
+
// 声明类的语法:
// class <类名>{
- // //数据字段, 构造器, 内部函数.
- / // 在Java中函数被称为方法。
+ // // 数据字段, 构造器, 内部函数
+ // // 在Java中函数被称为方法
// }
public class Bicycle
{
- // 自行车的字段、变量
+ // 自行车的字段/变量
public int Cadence // Public: 任何地方都可以访问
{
get // get - 定义获取属性的方法
@@ -558,30 +720,35 @@ on a new line! ""Wow!"", the masses cried";
}
set // set - 定义设置属性的方法
{
- _cadence = value; // value是被传递给setter的值
+ _cadence = value; // value 是被传递给 setter 的值
}
}
private int _cadence;
- protected virtual int Gear // 类和子类可以访问
+ protected virtual int Gear // Protected: 类和子类可以访问
{
get; // 创建一个自动属性,无需成员字段
set;
}
- internal int Wheels // Internal:在同一程序集内可以访问
+ internal int Wheels // Internal: 在同一程序集内可以访问
{
get;
- private set; // 可以给get/set方法添加修饰符
+ private set; // 可以给 get/set 方法添加修饰符
}
- int _speed; // 默认为private: 只可以在这个类内访问,你也可以使用`private`关键词
+ int _speed; // 类中的任何内容默认为 private: 只可以在这个类内访问
+ // 你也可以使用 `private` 关键词显式指定
public string Name { get; set; }
- // enum类型包含一组常量
+ // 当您想要一个仅返回表达式结果的只读属性时,
+ // 属性还具有特殊的语法
+ public string LongName => Name + " " + _speed + " speed";
+
+ // enum 枚举是一种值类型,由一组命名常量组成
// 它将名称映射到值(除非特别说明,是一个整型)
- // enmu元素的类型可以是byte、sbyte、short、ushort、int、uint、long、ulong。
- // enum不能包含相同的值。
+ // enmu 元素的类型可以是 byte、sbyte、short、ushort、int、uint、long、ulong
+ // enum 不能包含相同的值
public enum BikeBrand
{
AIST,
@@ -589,13 +756,32 @@ on a new line! ""Wow!"", the masses cried";
Electra = 42, //你可以显式地赋值
Gitane // 43
}
- // 我们在Bicycle类中定义的这个类型,所以它是一个内嵌类型。
- // 这个类以外的代码应当使用`Bicycle.Brand`来引用。
+ // 我们在 Bicycle 类中定义的这个类型,所以它是一个内嵌类型
+ // 这个类以外的代码应当使用 `Bicycle.Brand` 来引用
- public BikeBrand Brand; // 声明一个enum类型之后,我们可以声明这个类型的字段
+ public BikeBrand Brand; // 声明一个 enum 类型之后,我们可以声明这个类型的字段
- // 静态方法的类型为自身,不属于特定的对象。
- // 你无需引用对象就可以访问他们。
+ // 使用 FlagsAttribute 定义枚举,表示有多个值可以被匹配
+ // 任何从 Attribute 派生的类都可以用来修饰类型、方法、参数等
+ // 位运算符 & 和 | 可用于 和/或 操作
+
+ [Flags]
+ public enum BikeAccessories
+ {
+ None = 0,
+ Bell = 1,
+ MudGuards = 2, // 需要手动设定值!
+ Racks = 4,
+ Lights = 8,
+ FullPackage = Bell | MudGuards | Racks | Lights
+ }
+
+ // 用法: aBike.Accessories.HasFlag(Bicycle.BikeAccessories.Bell)
+ // 在 .NET 4 之前: (aBike.Accessories & Bicycle.BikeAccessories.Bell) == Bicycle.BikeAccessories.Bell
+ public BikeAccessories Accessories { get; set; }
+
+ // 静态方法属于类型自身,不属于特定的对象
+ // 你无需通过对象就可以访问他们
// Console.WriteLine("Bicycles created: " + Bicycle.bicyclesCreated);
static public int BicyclesCreated = 0;
@@ -607,7 +793,7 @@ on a new line! ""Wow!"", the masses cried";
// 下面是一个默认的构造器
public Bicycle()
{
- this.Gear = 1; // 你可以使用关键词this访问对象的成员
+ this.Gear = 1; // 你可以使用关键词 this 访问对象的成员
Cadence = 50; // 不过你并不总是需要它
_speed = 5;
Name = "Bontrager";
@@ -618,7 +804,7 @@ on a new line! ""Wow!"", the masses cried";
// 另一个构造器的例子(包含参数)
public Bicycle(int startCadence, int startSpeed, int startGear,
string name, bool hasCardsInSpokes, BikeBrand brand)
- : base() // 首先调用base
+ : base() // 显式调用基类的无参构造方法
{
Gear = startGear;
Cadence = startCadence;
@@ -637,8 +823,9 @@ on a new line! ""Wow!"", the masses cried";
// 函数语法
// <返回值> <函数名称>(<参数>)
- // 类可以为字段实现 getters 和 setters 方法 for their fields
- // 或者可以实现属性(C#推荐使用这个)
+ // 类可以为其字段实现 getters 和 setters 方法
+ // 或者可以使用属性封装字段(C#推荐使用这个)
+
// 方法的参数可以有默认值
// 在有默认值的情况下,调用方法的时候可以省略相应的参数
public void SpeedUp(int increment = 1)
@@ -652,8 +839,8 @@ on a new line! ""Wow!"", the masses cried";
}
// 属性可以访问和设置值
- // 当只需要访问数据的时候,考虑使用属性。
- // 属性可以定义get和set,或者是同时定义两者
+ // 当只需要外部访问数据的时候,考虑使用属性。
+ // 属性可以定义 get 和 set,或者是同时定义两者
private bool _hasTassles; // private variable
public bool HasTassles // public accessor
{
@@ -663,7 +850,7 @@ on a new line! ""Wow!"", the masses cried";
// 你可以在一行之内定义自动属性
// 这个语法会自动创建后备字段
- // 你可以给getter或setter设置访问修饰符
+ // 你可以给 getter 或 setter 设置访问修饰符
// 以便限制它们的访问
public bool IsBroken { get; private set; }
@@ -671,12 +858,29 @@ on a new line! ""Wow!"", the masses cried";
public int FrameSize
{
get;
- // 你可以给get或set指定访问修饰符
- // 以下代码意味着只有Bicycle类可以调用Framesize的set
+ // 你可以给 get 或 set 指定访问修饰符
+ // 以下代码意味着只有 Bicycle 类可以调用 Framesize 的 set
private set;
}
- //显示对象属性的方法
+ // 还可以在对象上定义自定义索引器
+ // 尽管这在本例中并不完全有用, you
+ // 你可以使用 bicycle[0] 返回 "chris" 来获得第一项
+ // 或者 bicycle[1] = "lisa" 来设定值
+ private string[] passengers = { "chris", "phil", "darren", "regina" };
+
+ public string this[int i]
+ {
+ get {
+ return passengers[i];
+ }
+
+ set {
+ passengers[i] = value;
+ }
+ }
+
+ // 显示对象属性的方法
public virtual string Info()
{
return "Gear: " + Gear +
@@ -698,7 +902,7 @@ on a new line! ""Wow!"", the masses cried";
} // Bicycle类结束
- // PennyFarthing是Bicycle的一个子类
+ // PennyFarthing 是 Bicycle 的一个子类
class PennyFarthing : Bicycle
{
// (Penny Farthings是一种前轮很大的自行车。没有齿轮。)
@@ -717,10 +921,17 @@ on a new line! ""Wow!"", the masses cried";
}
set
{
- throw new ArgumentException("你不可能在PennyFarthing上切换齿轮");
+ throw new ArgumentException("你不可能在 PennyFarthing 上切换齿轮");
}
}
+ public static PennyFarthing CreateWithGears(int gears)
+ {
+ var penny = new PennyFarthing(1, 1);
+ penny.Gear = gears; // 你不能这样做!
+ return penny;
+ }
+
public override string Info()
{
string result = "PennyFarthing bicycle ";
@@ -732,7 +943,7 @@ on a new line! ""Wow!"", the masses cried";
// 接口只包含成员的签名,而没有实现。
interface IJumpable
{
- void Jump(int meters); // 所有接口成员是隐式地公开的
+ void Jump(int meters); // 所有接口成员是隐式地公开的 public
}
interface IBreakable
@@ -741,6 +952,8 @@ on a new line! ""Wow!"", the masses cried";
}
// 类只能继承一个类,但是可以实现任意数量的接口
+ // 但是基类名称必须是列表中的第一个,所有接口都在后面
+ class MountainBike : Bicycle, IJumpable, IBreakable
{
int damage = 0;
@@ -759,41 +972,374 @@ on a new line! ""Wow!"", the masses cried";
}
///
- /// 连接数据库,一个 LinqToSql的示例。
+ /// 连接数据库,一个 LinqToSql 的示例。
/// EntityFramework Code First 很棒 (类似 Ruby的 ActiveRecord, 不过是双向的)
- /// http://msdn.microsoft.com/en-us/data/jj193542.aspx
+ /// https://learn.microsoft.com/zh-cn/ef/ef6/modeling/code-first/workflows/new-database
///
- public class BikeRespository : DbSet
+ public class BikeRepository : DbContext
{
- public BikeRespository()
+ public BikeRepository()
: base()
{
}
public DbSet Bikes { get; set; }
}
+
+ // 一个类可以通过 partial 关键字分别写在多个 .cs 文件中
+ // A1.cs
+ public partial class A
+ {
+ public static void A1()
+ {
+ Console.WriteLine("Method A1 in class A");
+ }
+ }
+
+ // A2.cs
+ public partial class A
+ {
+ public static void A2()
+ {
+ Console.WriteLine("Method A2 in class A");
+ }
+ }
+
+ // 使用 partial 类 "A"
+ public class Program
+ {
+ static void Main()
+ {
+ A.A1();
+ A.A2();
+ }
+ }
+
+ // 通过在字符串前加上 $ 前缀来进行字符串插值
+ // 并用 { 大括号 } 包裹要插值的表达式
+ // 您还可以将插值字符串和逐字字符串与 $@ 组合起来
+ public class Rectangle
+ {
+ public int Length { get; set; }
+ public int Width { get; set; }
+ }
+
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Rectangle rect = new Rectangle { Length = 5, Width = 3 };
+ Console.WriteLine($"The length is {rect.Length} and the width is {rect.Width}");
+
+ string username = "User";
+ Console.WriteLine($@"C:\Users\{username}\Desktop");
+ }
+ }
+
+ // C# 6 新特性
+ class GlassBall : IJumpable, IBreakable
+ {
+ // 自动属性设置初始值
+ public int Damage { get; private set; } = 0;
+
+ // 为仅有 getter 的自动属性设定初始值
+ public string Name { get; } = "Glass ball";
+
+ // 在构造函数中初始化的仅有 getter 的自动属性
+ public string GenieName { get; }
+
+ public GlassBall(string genieName = null)
+ {
+ GenieName = genieName;
+ }
+
+ public void Jump(int meters)
+ {
+ if (meters < 0)
+ // 新的 nameof() 表达式; 编译器将检查标识符是否存在
+ // nameof(x) == "x"
+ // 预防 例如 参数名称已更改但错误消息中未更新
+ throw new ArgumentException("Cannot jump negative amount!", nameof(meters));
+
+ Damage += meters;
+ }
+
+ // 表达式主体 expression-bodied 属性 ...
+ public bool Broken
+ => Damage > 100;
+
+ // ... 刚发
+ public override string ToString()
+ // 插值字符串
+ => $"{Name}. Damage taken: {Damage}";
+
+ public string SummonGenie()
+ // Null 条件运算符
+ // x?.y 如果 x 为 null 将立即返回 null; y 将不会求值
+ => GenieName?.ToUpper();
+ }
+
+ static class MagicService
+ {
+ private static bool LogException(Exception ex)
+ {
+ // 记录某处的异常
+ return false;
+ }
+
+ public static bool CastSpell(string spell)
+ {
+ try
+ {
+ // 假设我们在这里调用 API
+ throw new MagicServiceException("Spell failed", 42);
+
+ // Spell succeeded
+ return true;
+ }
+ // 仅当 Code 为 42(Spell failed)时才捕获
+ catch(MagicServiceException ex) when (ex.Code == 42)
+ {
+ // Spell failed
+ return false;
+ }
+ // 其他异常,或 MagicServiceException 的 Code 不是 42
+ catch(Exception ex) when (LogException(ex))
+ {
+ // 永远不会执行到这块代码
+ // 堆栈未展开
+ }
+ return false;
+ // 请注意,捕获 MagicServiceException
+ // 并在 Code 不是 42 或 117 时重新抛出是不同的
+ // 因为最终的 catch-all 块将不会捕获重新抛出的异常
+ }
+ }
+
+ public class MagicServiceException : Exception
+ {
+ public int Code { get; }
+
+ public MagicServiceException(string message, int code) : base(message)
+ {
+ Code = code;
+ }
+ }
+
+ public static class PragmaWarning {
+ // 过时的属性
+ [Obsolete("Use NewMethod instead", false)]
+ public static void ObsoleteMethod()
+ {
+ // obsolete code
+ }
+
+ public static void NewMethod()
+ {
+ // new code
+ }
+
+ public static void Main()
+ {
+ ObsoleteMethod(); // CS0618: 'ObsoleteMethod 已过时:使用 NewMethod 代替'
+#pragma warning disable CS0618
+ ObsoleteMethod(); // no warning
+#pragma warning restore CS0618
+ ObsoleteMethod(); // CS0618: 'ObsoleteMethod 已过时:使用 NewMethod 代替'
+ }
+ }
} // 结束 Namespace
+
+using System;
+// C# 6, 静态引用
+using static System.Math;
+
+namespace Learning.More.CSharp
+{
+ class StaticUsing
+ {
+ static void Main()
+ {
+ // 不使用静态引用时..
+ Console.WriteLine("The square root of 4 is {}.", Math.Sqrt(4));
+ // 使用时
+ Console.WriteLine("The square root of 4 is {}.", Sqrt(4));
+ }
+ }
+}
+
+// C# 7 新特性
+// 使用 Nuget 安装 Microsoft.Net.Compilers 最新版
+// 使用 Nuget 安装 System.ValueTuple 最新版
+using System;
+namespace Csharp7
+{
+ // 元组 TUPLES, 析构 DECONSTRUCTION 和 弃元 DISCARDS
+ class TuplesTest
+ {
+ public (string, string) GetName()
+ {
+ // 元组中的字段默认命名为 Item1、Item2...
+ var names1 = ("Peter", "Parker");
+ Console.WriteLine(names1.Item2); // => Parker
+
+ // 字段可以显式命名
+ // 第 1 种声明
+ (string FirstName, string LastName) names2 = ("Peter", "Parker");
+
+ // 第 2 种声明
+ var names3 = (First:"Peter", Last:"Parker");
+
+ Console.WriteLine(names2.FirstName); // => Peter
+ Console.WriteLine(names3.Last); // => Parker
+
+ return names3;
+ }
+
+ public string GetLastName() {
+ var fullName = GetName();
+
+ // 元组可以被析构
+ (string firstName, string lastName) = fullName;
+
+ // 析构获得的字段可以使用 弃元 _ 丢弃
+ var (_, last) = fullName;
+ return last;
+ }
+
+ // 通过指定析构方法,
+ // 可以以相同的方式解构任何类型
+ public int randomNumber = 4;
+ public int anotherRandomNumber = 10;
+
+ public void Deconstruct(out int randomNumber, out int anotherRandomNumber)
+ {
+ randomNumber = this.randomNumber;
+ anotherRandomNumber = this.anotherRandomNumber;
+ }
+
+ static void Main(string[] args)
+ {
+ var tt = new TuplesTest();
+ (int num1, int num2) = tt;
+ Console.WriteLine($"num1: {num1}, num2: {num2}"); // => num1: 4, num2: 10
+
+ Console.WriteLine(tt.GetLastName());
+ }
+ }
+
+ // 模式匹配
+ class PatternMatchingTest
+ {
+ public static (string, int)? CreateLogMessage(object data)
+ {
+ switch(data)
+ {
+ // 使用 when 进行附加过滤
+ case System.Net.Http.HttpRequestException h when h.Message.Contains("404"):
+ return (h.Message, 404);
+ case System.Net.Http.HttpRequestException h when h.Message.Contains("400"):
+ return (h.Message, 400);
+ case Exception e:
+ return (e.Message, 500);
+ case string s:
+ return (s, s.Contains("Error") ? 500 : 200);
+ case null:
+ return null;
+ default:
+ return (data.ToString(), 500);
+ }
+ }
+ }
+
+ // Reference 变量 / ref 局部变量
+ // 允许返回对象的引用而不仅仅是其值
+ class RefLocalsTest
+ {
+ // 返回值前标明 ref
+ public static ref string FindItem(string[] arr, string el)
+ {
+ for(int i=0; i apple
+ }
+ }
+
+ // 本地函数 LOCAL FUNCTIONS
+ class LocalFunctionTest
+ {
+ private static int _id = 0;
+ public int id;
+ public LocalFunctionTest()
+ {
+ id = generateId();
+
+ // 这个本地函数只能在此作用域中被访问
+ int generateId()
+ {
+ return _id++;
+ }
+ }
+
+ public static void AnotherMethod()
+ {
+ var lf1 = new LocalFunctionTest();
+ var lf2 = new LocalFunctionTest();
+ Console.WriteLine($"{lf1.id}, {lf2.id}"); // => 0, 1
+
+ int id = generateId();
+ // error CS0103: 当前上下文中不存在名称“generateId”
+ }
+ }
+}
+
```
## 没有涉及到的主题
+✨ 新的, 👍 旧的, 🎈 长期支持的, 🔥 跨平台的, 🎁 只支持Windows的
- * Flags
- * Attributes
- * 静态属性
- * Exceptions, Abstraction
- * ASP.NET (Web Forms/MVC/WebMatrix)
- * Winforms
- * Windows Presentation Foundation (WPF)
+ * 特性 Attributes
+
+ * 异步编程
+
+ * Web 开发
+ * ASP.NET Core ✨
+
+ * 桌面应用开发 Development
+ * Windows Presentation Foundation (WPF) 👍 🎈 🎁
+ * Universal Windows Platform (UWP) ✨ 🎁
+ * Uno Platform 🔥 ✨
+ * WinForms 👍 🎈 🎁
+ * Avalonia 🔥 ✨
+ * WinUI ✨ 🎁
+
+ * 跨平台开发
+ * Xamarin.Forms 👍
+ * MAUI ✨
## 扩展阅读
+ * [C# language reference](https://docs.microsoft.com/dotnet/csharp/language-reference/)
+ * [Learn .NET](https://dotnet.microsoft.com/learn)
+ * [C# Coding Conventions](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions)
* [DotNetPerls](http://www.dotnetperls.com)
* [C# in Depth](http://manning.com/skeet2)
- * [Programming C#](http://shop.oreilly.com/product/0636920024064.do)
- * [LINQ](http://shop.oreilly.com/product/9780596519254.do)
- * [MSDN Library](http://msdn.microsoft.com/en-us/library/618ayhy6.aspx)
- * [ASP.NET MVC Tutorials](http://www.asp.net/mvc/tutorials)
- * [ASP.NET Web Matrix Tutorials](http://www.asp.net/web-pages/tutorials)
- * [ASP.NET Web Forms Tutorials](http://www.asp.net/web-forms/tutorials)
+ * [Programming C# 5.0](http://shop.oreilly.com/product/0636920024064.do)
+ * [LINQ Pocket Reference](http://shop.oreilly.com/product/9780596519254.do)
* [Windows Forms Programming in C#](http://www.amazon.com/Windows-Forms-Programming-Chris-Sells/dp/0321116208)
- * [C# Coding Conventions](http://msdn.microsoft.com/en-us/library/vstudio/ff926074.aspx)
+ * [freeCodeCamp - C# Tutorial for Beginners](https://www.youtube.com/watch?v=GhQdlIFylQ8)
diff --git a/zh-cn/fortran-cn.html.markdown b/zh-cn/fortran-cn.html.markdown
new file mode 100644
index 00000000..ab521e0a
--- /dev/null
+++ b/zh-cn/fortran-cn.html.markdown
@@ -0,0 +1,444 @@
+---
+language: Fortran
+filename: learnfortran-cn.f90
+contributors:
+ - ["Robert Steed", "https://github.com/robochat"]
+translators:
+ - ["Corvusnest", "https://github.com/Corvusnest"]
+lang: zh-cn
+---
+
+Fortran 是最古老的计算机语言之一。它由 IBM 开发于 1950 年用于数值运算(Fortran 为 "Formula
+Translation" 的缩写)。虽然该语言已年代久远,但目前仍用于高性能计算,如天气预报。
+该语言仍在持续发展,并且基本保持向下兼容。知名的版本为 Fortran 77, Fortran 90,
+Fortran 95, Fortran 2008, Fortran 2015 和 Fortran 2023。
+
+这篇概要将讨论 Fortran 2008 的一些特征。因为它是目前所广泛采用的标准版本,并且与最新版本的内容
+也基本相同(而 Fortran 77 则是一个非常不同的版本)。
+
+```fortran
+! 这是一个注释
+
+program example ! 声明一个名为 example 的程序
+
+ ! 代码只能存在于程序、函数、子程序或模块中
+ ! 使用缩进不是必需的,但推荐使用
+
+ ! 声明变量
+ ! =========
+
+ ! 所有的声明必须在语句和表达式之前
+
+ implicit none ! 防止动态声明变量(推荐!)
+ ! implicit none 推荐在每个函数/程序/模块中重新声明...
+
+ ! 注意 - Fortran 中对大小写不敏感
+ real z
+ REAL Z2
+
+ real :: v, x ! 警告:默认的初始值取决于编译器!
+ real :: a = 3, b = 2E12, c = 0.01
+ integer :: i, j, k = 1, m
+ real, parameter :: PI = 3.1415926535897931 ! 声明一个常数
+ logical :: y = .TRUE., n = .FALSE. ! 布尔类型
+ complex :: w = (0, 1) ! 单位虚数
+ character(len=3) :: month ! 字符串,长度为 3 个字符
+
+ real :: array(6) ! 声明一个包含 6 个实数的数组
+ real, dimension(4) :: arrayb ! 另一种声明数组的方式
+ integer :: arrayc(-10:10) ! 具有自定义索引的数组
+ real :: array2d(3, 2) ! 多维数组
+
+ ! 这些分隔符 '::' 并不总是必需的,但推荐使用
+
+ ! 还有许多其他的变量属性:
+ real, pointer :: p ! 声明一个指针
+
+ integer, parameter :: LP = selected_real_kind(20)
+ real(kind=LP) :: d ! 长精度变量
+
+ ! 警告:在声明过程中初始化变量会在函数中造成问题,
+ ! 因为这会自动暗示 'save' 属性,
+ ! 在函数调用之间保存变量的值一般情况下,
+ ! 除了常量外,声明和初始化的代码应该分开!
+
+ ! 字符串
+ ! =======
+
+ character :: a_char = 'i'
+ character(len=6) :: a_str = "qwerty"
+ character(len=30) :: str_b
+ character(len=*), parameter :: a_long_str = "This is a long string."
+ ! 使用 (len=*) 可以自动计算长度,但只适用于常量
+
+ str_b = a_str//" keyboard" ! 使用 // 运算符连接字符串
+
+ ! 赋值和算术
+ ! =============
+
+ Z = 1 ! 对上面声明的变量 z 进行赋值(对大小写不敏感)
+ j = 10 + 2 - 3
+ a = 11.54/(2.3*3.1)
+ b = 2**3 ! 幂运算
+
+ ! 流程控制语句和操作符
+ ! ===================
+
+ ! 单行 if 语句
+ if (z == a) b = 4 ! 条件始终需要在括号中
+
+ if (z /= a) then ! z 不等于 a
+ ! 其他的比较操作符包括 < > <= >= == /=
+ b = 4
+ else if (z .GT. a) then ! z 大于 a
+ ! 文本等价于符号操作符中的 .LT. .GT. .LE. .GE. .EQ. .NE.
+ b = 6
+ else if (z < a) then ! 'then' 必须在本行上
+ b = 5 ! 执行块必须在新的一行上
+ else
+ b = 10
+ end if ! end 语句后需要 'if'(或可以使用 'endif')
+
+ if (.NOT. (x < c .AND. v >= a .OR. z == z)) then ! 布尔运算符
+ inner: if (.TRUE.) then ! 可以对 if 结构命名
+ b = 1
+ end if inner ! then 必须命名对应的 endif 语句
+ end if
+
+ i = 20
+ select case (i)
+ case (0, 1) ! 当 i == 0 或 i == 1 时
+ j = 0
+ case (2:10) ! 当 i 在 2 到 10 之间(包括边界)时
+ j = 1
+ case (11:) ! 当 i >= 11 时
+ j = 2
+ case default
+ j = 3
+ end select
+
+ month = 'jan'
+ ! 条件可以是整数、逻辑、或字符类型
+ ! Select 结构也可以命名
+ monthly:select case(month)
+ case ("jan")
+ j = 0
+ case default
+ j = -1
+ end select monthly
+
+ do i = 2, 10, 2 ! 循环从 2 到 10(包括)以 2 为步长
+ innerloop: do j = 1, 3 ! 循环也可以命名
+ exit ! 退出循环
+ end do innerloop
+ cycle ! 跳到下一个循环迭代
+ end do
+
+ ! 虽然存在 Goto 语句,但它被强烈不推荐
+ goto 10
+ stop 1 ! 立即停止代码(并返回指定的条件代码)
+10 j = 201 ! 这一行被标记为 10 行
+
+ ! 数组
+ ! =====
+ array = (/1, 2, 3, 4, 5, 6/)
+ array = [1, 2, 3, 4, 5, 6] ! 使用 Fortran 2003 的表示法
+ arrayb = [10.2, 3e3, 0.41, 4e-5]
+ array2d = reshape([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], [3, 2])
+
+ ! Fortran 数组索引从 1 开始
+ ! (默认情况下,但对于特定数组可以定义不同的索引)
+ v = array(1) ! 取数组的第一个元素
+ v = array2d(2, 2)
+
+ print *, array(3:5) ! 打印从第三个到第五个元素(包括)
+ print *, array2d(1, :) ! 打印二维数组的第一列
+
+ array = array*3 + 2 ! 可以对数组应用数学表达式
+ array = array*array ! 数组操作是逐元素进行的
+ ! array = array*array2d ! 这两个数组是不兼容的
+
+ ! 有许多内置函数可用于数组
+ c = dot_product(array, array) ! 这是点积
+ ! 使用 matmul() 进行矩阵运算
+ c = sum(array)
+ c = maxval(array)
+ print *, minloc(array)
+ c = size(array)
+ print *, shape(array)
+ m = count(array > 0)
+
+ ! 循环数组(通常使用 product() 函数)
+ v = 1
+ do i = 1, size(array)
+ v = v*array(i)
+ end do
+
+ ! 条件性地执行逐元素赋值
+ array = [1, 2, 3, 4, 5, 6]
+ where (array > 3)
+ array = array + 1
+ elsewhere(array == 2)
+ array = 1
+ elsewhere
+ array = 0
+ end where
+
+ ! 隐含 do 循环是创建数组的紧凑方式
+ array = [(i, i=1, 6)] ! 创建一个数组 [1,2,3,4,5,6]
+ array = [(i, i=1, 12, 2)] ! 创建一个数组 [1,3,5,7,9,11]
+ array = [(i**2, i=1, 6)] ! 创建一个数组 [1,4,9,16,25,36]
+ array = [(4, 5, i=1, 3)] ! 创建一个数组 [4,5,4,5,4,5]
+
+ ! 输入/输出
+ ! =========
+
+ print *, b ! 将变量 'b' 打印到命令行
+
+ ! 可以对打印的输出进行格式化
+ print "(I6)", 320 ! 打印 ' 320'
+ print "(I6.4)", 3 ! 打印 ' 0003'
+ print "(F6.3)", 4.32 ! 打印 ' 4.320'
+
+ ! 字母表示预期的类型,后面的数字表示用于打印值的字符数
+ ! 字母可以是 I(整数),F(实数),E(工程表示法),
+ ! L(逻辑),A(字符串)...
+ print "(I3)", 3200 ! 打印 '***',因为该数字不适合
+
+ ! 可以有多个格式规范
+ print "(I5,F6.2,E6.2)", 120, 43.41, 43.41
+ print "(3I5)", 10, 20, 30 ! 整数的三次重复(字段宽度为 5)
+ print "(2(I5,F6.2))", 120, 43.42, 340, 65.3 ! 格式重复组合
+
+ ! 我们还可以从终端读取输入
+ read (*, *) v
+ read (*, "(2F6.2)") v, x ! 读取两个数字
+
+ ! 写入文件
+ open (unit=12, file="records.txt", status="replace")
+ ! 文件通过 'unit number' 引用,这个数字可以在 9:99 范围内选择
+ ! Status 可以是 {'old','replace','new'} 中的一个
+ write (12, "(F10.2,F10.2,F10.2)") c, b, a
+ close (12)
+
+ ! 读取文件
+ open (newunit=m, file="records.txt", status="old")
+ ! 文件通过 'new unit number' 引用,编译器为您选择一个整数
+ read (unit=m, fmt="(3F10.2)") a, b, c
+ close (m)
+
+ ! 还有更多功能可用,超出了本文所讨论的范围,
+ ! 还有由于与旧版本的 Fortran 的向后兼容性而存在的替代方案
+
+ ! 内置函数
+ ! ===========
+
+ ! Fortran 大约有 200 个语言内部的函数/子程序
+ ! 例如 -
+ call cpu_time(v) ! 将 'v' 设置为以秒为单位的时间
+ k = ior(i, j) ! 两个整数的位 OR 运算
+ v = log10(x) ! 以 10 为底的对数
+ i = floor(b) ! 返回小于或等于 x 的最接近的整数
+ v = aimag(w) ! 复数的虚部
+
+ ! 函数和子程序
+ ! ==============
+
+ ! 子程序运行一些代码,并可以对输入值产生副作用或修改输入值
+
+ call routine(a, c, v) ! 子程序调用
+
+ ! 函数采用一系列输入参数,并返回一个单个值
+ ! 不过,输入参数可能仍会被修改,并且会执行副作用
+
+ m = func(3, 2, k) ! 函数调用
+
+ ! 函数调用还可以在表达式中使用
+ print *, func2(3, 2, k)
+
+ ! 一个纯函数是一个不修改其输入参数,
+ ! 也不会引起任何副作用的函数
+ m = func3(3, 2, k)
+
+contains ! 包含程序内部定义的子程序的区域
+
+ ! Fortran 有几种稍微不同的方式来定义函数
+
+ integer function func(a, b, c) ! 函数返回一个整数值
+ ! implicit none ! 子变量域可以不再声明 implicit none
+ integer, intent(in) :: a, b, c ! 在函数内部定义输入参数的类型
+
+ if (a >= 2) then
+ func = a + b + c ! 返回变量默认为函数名
+ return ! 随时可以从函数返回当前值
+ end if
+ func = a + c
+
+ ! 在函数的末尾不需要 return 语句
+ end function func
+
+ function func2(a, b, c) result(f) ! 返回变量声明为 'f'
+ integer, intent(in) :: a, b ! 可以声明和强制约定变量
+ ! 不会被函数修改
+ integer, intent(inout) :: c
+ integer :: f ! 函数返回类型在函数内部声明
+ integer :: cnt = 0 ! 注意:初始化暗示变量在函数调用之间保存
+ !
+
+ f = a + b - c
+ c = 4 ! 修改输入变量的值
+ cnt = cnt + 1 ! 计算函数调用的次数
+
+ end function func2
+
+ pure function func3(a, b, c) ! 纯函数不能有副作用
+ integer, intent(in) :: a, b, c
+ integer :: func3
+
+ func3 = a*b*c
+
+ end function func3
+
+ subroutine routine(d, e, f)
+ real, intent(inout) :: f
+ real, intent(in) :: d, e
+
+ f = 2*d + 3*e + f
+
+ end subroutine routine
+
+end program example ! 程序定义结束--------------------------
+
+! 函数和子程序在程序列表之外声明,在程序之间以及模块中声明时,需要使用 interface 声明(即使它们在同一源文件中)(见下面)将它们定义在模块或程序的 'contains' 部分更容易
+
+elemental real function func4(a) result(res)
+! elemental 函数是一个纯函数,它采用标量输入变量,
+! 但也可以在数组上独立应用,并返回一个新的数组
+ real, intent(in) :: a
+
+ res = a**2 + 1.0
+
+end function func4
+
+! 模块
+! =======
+
+! 模块是在可重用性中将相关的声明、函数和子程序结合在一起的有用方式
+
+module fruit
+
+ real :: apple
+ real :: pear
+ real :: orange
+
+end module fruit
+
+module fruity
+ ! 声明的顺序必须是:模块、接口、变量
+ !(也可以在程序中声明模块和接口)
+
+ use fruit, only: apple, pear ! 使用 fruit 模块中的 apple 和 pear
+ implicit none ! 导入模块之后
+
+ private ! 将一些内容私有化(默认为公共)
+ ! 显式将一些变量/函数声明为公共
+ public :: apple, mycar, create_mycar
+ ! 将一些变量/函数声明为模块私有(本例中是多余的)
+ private :: func4
+
+ ! 接口
+ ! ========
+ ! 在模块内部(最好放在 'contains' 部分)显式声明外部函数/过程
+ interface
+ elemental real function func4(a) result(res)
+ real, intent(in) :: a
+ end function func4
+ end interface
+
+ ! 可以使用命名接口定义重载函数
+ interface myabs
+ ! 可以使用 'module procedure' 关键字包括模块内已经定义的函数
+ module procedure real_abs, complex_abs
+ end interface
+
+ ! 派生数据类型
+ ! ==================
+ ! 可以创建自定义的结构化数据集合
+ type car
+ character(len=100) :: model
+ real :: weight !(千克)
+ real :: dimensions(3) ! 即,长度-宽度-高度(米)
+ character :: colour
+ contains
+ procedure :: info ! 将过程绑定到类型
+ end type car
+
+ type(car) :: mycar ! 声明自定义类型的变量
+ ! 请查看 create_mycar() 程序的用法
+
+ ! 注意:模块中没有可以执行的语句
+
+contains
+
+ subroutine create_mycar(mycar)
+ ! 演示派生数据类型的用法
+ type(car), intent(out) :: mycar
+
+ ! 使用 '%' 运算符访问类型元素
+ mycar%model = "Ford Prefect"
+ mycar%colour = 'r'
+ mycar%weight = 1400
+ mycar%dimensions(1) = 5.0 ! 默认索引从 1 开始!
+ mycar%dimensions(2) = 3.0
+ mycar%dimensions(3) = 1.5
+
+ end subroutine create_mycar
+
+ subroutine info(self)
+ class(car), intent(in) :: self
+ ! 使用 'class' 关键字将过程绑定到类型
+
+ print *, "Model : ", self%model
+ print *, "Colour : ", self%colour
+ print *, "Weight : ", self%weight
+ print *, "Dimensions: ", self%dimensions
+
+ end subroutine info
+
+ real pure function real_abs(x)
+ real, intent(in) :: x
+
+ if (x < 0) then
+ real_abs = -x
+ else
+ real_abs = x
+ end if
+
+ end function real_abs
+
+ real pure function complex_abs(z)
+ complex, intent(in) :: z
+ ! 长行可以使用继续字符 '&' 进行延续
+
+ complex_abs = sqrt(real(z)**2 + &
+ aimag(z)**2)
+
+ end function complex_abs
+
+end module fruity
+
+```
+
+### 更多资源
+
+了解更多的 Fortran 信息:
+
++ [wikipedia](https://en.wikipedia.org/wiki/Fortran)
++ [Fortran-lang Organization](https://fortran-lang.org/)
++ [Fortran_95_language_features](https://en.wikipedia.org/wiki/Fortran_95_language_features)
++ [fortranwiki.org](http://fortranwiki.org)
++ [www.fortran90.org/](http://www.fortran90.org)
++ [list of Fortran 95 tutorials](http://www.dmoz.org/Computers/Programming/Languages/Fortran/FAQs%2C_Help%2C_and_Tutorials/Fortran_90_and_95/)
++ [Fortran wikibook](https://en.wikibooks.org/wiki/Fortran)
++ [Fortran resources](http://www.fortranplus.co.uk/resources/fortran_resources.pdf)
++ [Mistakes in Fortran 90 Programs That Might Surprise You](http://www.cs.rpi.edu/~szymansk/OOF90/bugs.html)
diff --git a/zh-cn/fortran95-cn.html.markdown b/zh-cn/fortran95-cn.html.markdown
deleted file mode 100644
index e28d309f..00000000
--- a/zh-cn/fortran95-cn.html.markdown
+++ /dev/null
@@ -1,435 +0,0 @@
----
-language: Fortran
-filename: learnfortran-cn.f95
-contributors:
- - ["Robert Steed", "https://github.com/robochat"]
-translators:
- - ["Corvusnest", "https://github.com/Corvusnest"]
-lang: zh-cn
----
-
-Fortran 是最古老的计算机语言之一。它由IBM开发于1950年用于数值运算(Fortran 为 "Formula
-Translation" 的缩写)。虽然该语言已年代久远,但目前仍用于高性能计算,如天气预报。
-该语言仍在持续发展,并且基本保持向下兼容。知名的版本为 Fortran 77, Fortran 90,
-Fortran 95, Fortran 2003, Fortran 2008 与 Fortran 2015。
-
-这篇概要将讨论 Fortran 95 的一些特征。因为它是目前所广泛采用的标准版本,并且与最新版本的内容
-也基本相同(而 Fortran 77 则是一个非常不同的版本)。
-
-```fortran
-
-! 这是一行注释
-
-
-program example !声明一个叫做 example 的程序
-
- ! 代码只能放在程序、函数、子程序或者模块内部
- ! 推荐使用缩进,但不是必须的。
-
- ! 声明变量
- ! ===================
-
- ! 所有的声明必须放在语句与表达式之前
-
- implicit none !阻止变量的隐式声明 (推荐!)
- ! Implicit none 必须在每一个 函数/程序/模块 中进行声明
-
- ! 重要 - Fortran 对大小写不敏感
- real z
- REAL Z2
-
- real :: v,x ! 警告: 默认值取决于编译器!
- real :: a = 3, b=2E12, c = 0.01
- integer :: i, j, k=1, m
- real, parameter :: PI = 3.1415926535897931 !声明一个常量
- logical :: y = .TRUE. , n = .FALSE. !布尔值
- complex :: w = (0,1) !sqrt(-1) (译注: 定义复数,此为-1的平方根)
- character (len=3) :: month !长度为3的字符串
-
- real :: array(6) !声明长度为6的浮点数数组
- real, dimension(4) :: arrayb !声明数组的另一种方法
- integer :: arrayc(-10:10) !有着自定义索引的数组
- real :: array2d(3,2) !多维数组
-
- ! 分隔符 '::' 并不总是必要的,但推荐使用
-
- ! 还存在很多其他的变量特征:
- real, pointer :: p !声明一个指针
-
- integer, parameter :: LP = selected_real_kind(20)
- real (kind = LP) :: d !长精度变量
-
- ! 警告:在声明期间初始化变量将导致在函数内发生问题,因为这将自动具备了 “save” 属性,
- ! 因此变量的值在函数的多次调用期间将被存储。一般来说,除了常量,应分开声明与初始化!
-
- ! 字符串
- ! =======
-
- character :: a_char = 'i'
- character (len = 6) :: a_str = "qwerty"
- character (len = 30) :: str_b
- character (len = *), parameter :: a_long_str = "This is a long string."
- !可以通过使用 (len=*) 来自动判断长度,但只对常量有效
-
- str_b = a_str // " keyboard" !通过 // 操作符来连接字符串
-
-
- ! 任务与计算
- ! =======================
-
- Z = 1 !向之前声明的变量 z 赋值 (大小写不敏感).
- j = 10 + 2 - 3
- a = 11.54 / (2.3 * 3.1)
- b = 2**3 !幂
-
-
- ! 控制流程语句 与 操作符
- ! ===================================
-
- !单行 if 语句
- if (z == a) b = 4 !判别句永远需要放在圆括号内
-
- if (z /= a) then !z 不等于 a
- ! 其他的比较运算符: < > <= >= == /=
- b = 4
- else if (z .GT. a) then !z 大于(Greater) a
- ! 文本形式的比较运算符: .LT. .GT. .LE. .GE. .EQ. .NE.
- b = 6
- else if (z < a) then !'then' 必须放在该行
- b = 5 !执行部分必须放在新的一行里
- else
- b = 10
- end if !结束语句需要 'if' (也可以用 'endif').
-
-
- if (.NOT. (x < c .AND. v >= a .OR. z == z)) then !布尔操作符
- inner: if (.TRUE.) then !可以为 if 结构命名
- b = 1
- endif inner !接下来必须命名 endif 语句.
- endif
-
-
- i = 20
- select case (i)
- case (0) !当 i == 0
- j=0
- case (1:10) !当 i 为 1 到 10 之内 ( 1 <= i <= 10 )
- j=1
- case (11:) !当 i>=11
- j=2
- case default
- j=3
- end select
-
-
- month = 'jan'
- ! 状态值可以为整数、布尔值或者字符类型
- ! Select 结构同样可以被命名
- monthly: select case (month)
- case ("jan")
- j = 0
- case default
- j = -1
- end select monthly
-
- do i=2,10,2 !从2到10(包含2和10)以2为步进值循环
- innerloop: do j=1,3 !循环同样可以被命名
- exit !跳出循环
- end do innerloop
- cycle !重复跳入下一次循环
- enddo
-
-
- ! Goto 语句是存在的,但强烈不建议使用
- goto 10
- stop 1 !立即停止程序 (返回一个设定的状态码).
-10 j = 201 !这一行被标注为 10 行 (line 10)
-
-
- ! 数组
- ! ======
- array = (/1,2,3,4,5,6/)
- array = [1,2,3,4,5,6] !当使用 Fortran 2003 版本.
- arrayb = [10.2,3e3,0.41,4e-5]
- array2d = reshape([1.0,2.0,3.0,4.0,5.0,6.0], [3,2])
-
- ! Fortran 数组索引起始于 1
- ! (默认下如此,也可以为数组定义不同的索引起始)
- v = array(1) !获取数组的第一个元素
- v = array2d(2,2)
-
- print *, array(3:5) !打印从第3到第五5之内的所有元素
- print *, array2d(1,:) !打印2维数组的第一列
-
- array = array*3 + 2 !可为数组设置数学表达式
- array = array*array !数组操作支持元素级(操作) (element-wise)
- !array = array*array2d !这两类数组并不是同一个维度的
-
- ! 有很多内置的数组操作函数
- c = dot_product(array,array) !点乘 (点积)
- ! 用 matmul() 来进行矩阵运算.
- c = sum(array)
- c = maxval(array)
- print *, minloc(array)
- c = size(array)
- print *, shape(array)
- m = count(array > 0)
-
- ! 遍历一个数组 (一般使用 Product() 函数).
- v = 1
- do i = 1, size(array)
- v = v*array(i)
- end do
-
- ! 有条件地执行元素级操作
- array = [1,2,3,4,5,6]
- where (array > 3)
- array = array + 1
- elsewhere (array == 2)
- array = 1
- elsewhere
- array = 0
- end where
-
- ! 隐式DO循环可以很方便地创建数组
- array = [ (i, i = 1,6) ] !创建数组 [1,2,3,4,5,6]
- array = [ (i, i = 1,12,2) ] !创建数组 [1,3,5,7,9,11]
- array = [ (i**2, i = 1,6) ] !创建数组 [1,4,9,16,25,36]
- array = [ (4,5, i = 1,3) ] !创建数组 [4,5,4,5,4,5]
-
-
- ! 输入/输出
- ! ============
-
- print *, b !向命令行打印变量 'b'
-
- ! 我们可以格式化输出
- print "(I6)", 320 !打印 ' 320'
- print "(I6.4)", 3 !打印 ' 0003'
- print "(F6.3)", 4.32 !打印 ' 4.320'
-
-
- ! 该字母与数值规定了给定的数值与字符所用于打印输出的类型与格式
- ! 字母可为 I (整数), F (浮点数), E (工程格式),
- ! L (逻辑/布尔值), A (字符) ...
- print "(I3)", 3200 !如果数值无法符合格式将打印 '***'
-
- ! 可以同时设定多种格式
- print "(I5,F6.2,E6.2)", 120, 43.41, 43.41
- print "(3I5)", 10, 20, 30 !连续打印3个整数 (字段宽度 = 5).
- print "(2(I5,F6.2))", 120, 43.42, 340, 65.3 !连续分组格式
-
- ! 我们也可以从终端读取输入
- read *, v
- read "(2F6.2)", v, x !读取2个数值
-
- ! 读取文件
- open(unit=11, file="records.txt", status="old")
- ! 文件被引用带有一个单位数 'unit', 为一个取值范围在9-99的整数
- ! 'status' 可以为 {'old','replace','new'} 其中之一
- read(unit=11, fmt="(3F10.2)") a, b, c
- close(11)
-
- ! 写入一个文件
- open(unit=12, file="records.txt", status="replace")
- write(12, "(F10.2,F10.2,F10.2)") c, b, a
- close(12)
- ! 在讨论范围之外的还有更多的细节与可用功能,并于老版本的 Fortran 保持兼容
-
-
- ! 内置函数
- ! ==================
-
- ! Fortran 拥有大约 200 个内置函数/子程序
- ! 例子
- call cpu_time(v) !以秒为单位设置时间
- k = ior(i,j) !2个整数的位或运算
- v = log10(x) !以10为底的log运算
- i = floor(b) !返回一个最接近的整数小于或等于x (地板数)
- v = aimag(w) !复数的虚数部分
-
-
- ! 函数与子程序
- ! =======================
-
- ! 一个子程序会根据输入值运行一些代码并会导致副作用 (side-effects) 或修改输入值
- ! (译者注: 副作用是指对子程序/函数外的环境产生影响,如修改变量)
-
- call routine(a,c,v) !调用子程序
-
- ! 一个函数会根据输入的一系列数值来返回一个单独的值
- ! 但输入值仍然可能被修改以及产生副作用
-
- m = func(3,2,k) !调用函数
-
- ! 函数可以在表达式内被调用
- Print *, func2(3,2,k)
-
- ! 一个纯函数不会去修改输入值或产生副作用
- m = func3(3,2,k)
-
-
-contains ! 用于定义程序内部的副程序(sub-programs)的区域
-
- ! Fortran 拥有一些不同的方法去定义函数
-
- integer function func(a,b,c) !一个返回一个整数的函数
- implicit none !最好也在函数内将含蓄模式关闭 (implicit none)
- integer :: a,b,c !输入值类型定义在函数内部
- if (a >= 2) then
- func = a + b + c !返回值默认为函数名
- return !可以在函数内任意时间返回当前值
- endif
- func = a + c
- ! 在函数的结尾不需要返回语句
- end function func
-
-
- function func2(a,b,c) result(f) !将返回值声明为 'f'
- implicit none
- integer, intent(in) :: a,b !可以声明让变量无法被函数修改
- integer, intent(inout) :: c
- integer :: f !函数的返回值类型在函数内声明
- integer :: cnt = 0 !注意 - 隐式的初始化变量将在函数的多次调用间被存储
- f = a + b - c
- c = 4 !变动一个输入变量的值
- cnt = cnt + 1 !记录函数的被调用次数
- end function func2
-
-
- pure function func3(a,b,c) !一个没有副作用的纯函数
- implicit none
- integer, intent(in) :: a,b,c
- integer :: func3
- func3 = a*b*c
- end function func3
-
-
- subroutine routine(d,e,f)
- implicit none
- real, intent(inout) :: f
- real, intent(in) :: d,e
- f = 2*d + 3*e + f
- end subroutine routine
-
-
-end program example ! 函数定义完毕 -----------------------
-
-! 函数与子程序的外部声明对于生成程序清单来说,需要一个接口声明(即使它们在同一个源文件内)(见下)
-! 使用 'contains' 可以很容易地在模块或程序内定义它们
-
-elemental real function func4(a) result(res)
-! 一个元函数(elemental function) 为一个纯函数使用一个标量输入值
-! 但同时也可以用在一个数组并对其中的元素分别处理,之后返回一个新的数组
- real, intent(in) :: a
- res = a**2 + 1.0
-end function func4
-
-
-! 模块
-! =======
-
-! 模块十分适合于存放与复用相关联的一组声明、函数与子程序
-
-module fruit
- real :: apple
- real :: pear
- real :: orange
-end module fruit
-
-
-module fruity
-
- ! 声明必须按照顺序: 模块、接口、变量
- ! (同样可在程序内声明模块和接口)
-
- use fruit, only: apple, pear ! 使用来自于 fruit 模块的 apple 和 pear
- implicit none !在模块导入后声明
-
- private !使得模块内容为私有(private)(默认为公共 public)
- ! 显式声明一些变量/函数为公共
- public :: apple,mycar,create_mycar
- ! 声明一些变量/函数为私有(在当前情况下没必要)(译注: 因为前面声明了模块全局 private)
- private :: func4
-
- ! 接口
- ! ==========
- ! 在模块内显式声明一个外部函数/程序
- ! 一般最好将函数/程序放进 'contains' 部分内
- interface
- elemental real function func4(a) result(res)
- real, intent(in) :: a
- end function func4
- end interface
-
- ! 重载函数可以通过已命名的接口来定义
- interface myabs
- ! 可以通过使用 'module procedure' 关键词来包含一个已在模块内定义的函数
- module procedure real_abs, complex_abs
- end interface
-
- ! 派生数据类型
- ! ==================
- ! 可创建自定义数据结构
- type car
- character (len=100) :: model
- real :: weight !(公斤 kg)
- real :: dimensions(3) !例: 长宽高(米)
- character :: colour
- end type car
-
- type(car) :: mycar !声明一个自定义类型的变量
- ! 用法具体查看 create_mycar()
-
- ! 注: 模块内没有可执行的语句
-
-contains
-
- subroutine create_mycar(mycar)
- ! 展示派生数据类型的使用
- implicit none
- type(car),intent(out) :: mycar
-
- ! 通过 '%' 操作符来访问(派生数据)类型的元素
- mycar%model = "Ford Prefect"
- mycar%colour = 'r'
- mycar%weight = 1400
- mycar%dimensions(1) = 5.0 !索引默认起始值为 1 !
- mycar%dimensions(2) = 3.0
- mycar%dimensions(3) = 1.5
-
- end subroutine
-
- real function real_abs(x)
- real :: x
- if (x<0) then
- real_abs = -x
- else
- real_abs = x
- end if
- end function real_abs
-
- real function complex_abs(z)
- complex :: z
- ! 过长的一行代码可通过延续符 '&' 来换行
- complex_abs = sqrt(real(z)**2 + &
- aimag(z)**2)
- end function complex_abs
-
-
-end module fruity
-
-```
-
-### 更多资源
-
-了解更多的 Fortran 信息:
-
-+ [wikipedia](https://en.wikipedia.org/wiki/Fortran)
-+ [Fortran_95_language_features](https://en.wikipedia.org/wiki/Fortran_95_language_features)
-+ [fortranwiki.org](http://fortranwiki.org)
-+ [www.fortran90.org/](http://www.fortran90.org)
-+ [list of Fortran 95 tutorials](http://www.dmoz.org/Computers/Programming/Languages/Fortran/FAQs%2C_Help%2C_and_Tutorials/Fortran_90_and_95/)
-+ [Fortran wikibook](https://en.wikibooks.org/wiki/Fortran)
-+ [Fortran resources](http://www.fortranplus.co.uk/resources/fortran_resources.pdf)
-+ [Mistakes in Fortran 90 Programs That Might Surprise You](http://www.cs.rpi.edu/~szymansk/OOF90/bugs.html)
diff --git a/zh-cn/go-cn.html.markdown b/zh-cn/go-cn.html.markdown
index 0123c0a6..a2b71761 100644
--- a/zh-cn/go-cn.html.markdown
+++ b/zh-cn/go-cn.html.markdown
@@ -78,7 +78,7 @@ func learnTypes() {
// 非ascii字符。Go使用UTF-8编码。
g := 'Σ' // rune类型,int32的别名,使用UTF-8编码
- f := 3.14195 // float64类型,IEEE-754 64位浮点数
+ f := 3.14159 // float64类型,IEEE-754 64位浮点数
c := 3 + 4i // complex128类型,内部使用两个float64表示
// var变量可以直接初始化。
@@ -392,15 +392,15 @@ func requestServer() {
## 更进一步
-关于Go的一切你都可以在[Go官方网站](http://golang.org/)找到。
+关于Go的一切你都可以在[Go官方网站](https://go.dev/)找到。
在那里你可以获得教程参考,在线试用,和更多的资料。
-在简单的尝试过后,在[官方文档](https://golang.org/doc/)那里你会得到你所需要的所有资料、关于编写代码的规范、库和命令行工具的文档与Go的版本历史。
+在简单的尝试过后,在[官方文档](https://go.dev/doc/)那里你会得到你所需要的所有资料、关于编写代码的规范、库和命令行工具的文档与Go的版本历史。
强烈推荐阅读语言定义部分,很简单而且很简洁!(赶时髦!)
-你还可以前往[Go在线体验中心](https://play.golang.org/p/tnWMjr16Mm)进,在浏览器里修改并运行这些代码,一定要试一试哦!你可以将[https://play.golang.org](https://play.golang.org)当作一个[REPL](https://en.wikipedia.org/wiki/Read-eval-print_loop),在那里体验语言特性或运行自己的代码,连环境都不用配!
+你还可以前往[Go在线体验中心](https://go.dev/play/p/tnWMjr16Mm)进,在浏览器里修改并运行这些代码,一定要试一试哦!你可以将[https://go.dev/play/](https://go.dev/play/)当作一个[REPL](https://en.wikipedia.org/wiki/Read-eval-print_loop),在那里体验语言特性或运行自己的代码,连环境都不用配!
-学习Go还要阅读Go[标准库的源代码](http://golang.org/src/),全部文档化了,可读性非常好,可以学到go,go style和go idioms。在[文档](http://golang.org/pkg/)中点击函数名,源代码就出来了!
+学习Go还要阅读Go[标准库的源代码](https://go.dev/src/),全部文档化了,可读性非常好,可以学到go,go style和go idioms。在[文档](https://go.dev/pkg/)中点击函数名,源代码就出来了!
[Go by example](https://gobyexample.com/)也是一个学习的好地方。
diff --git a/zh-cn/json-cn.html.markdown b/zh-cn/json-cn.html.markdown
index 73d3eb57..f5842c07 100644
--- a/zh-cn/json-cn.html.markdown
+++ b/zh-cn/json-cn.html.markdown
@@ -8,24 +8,30 @@ filename: learnjson-cn.json
lang: zh-cn
---
-因为JSON是一个极其简单的数据交换格式,本教程最有可能成为有史以来最简单的
-Learn X in Y Minutes。
+JSON是一个极其简单的数据交换格式。按[json.org](https://json.org)说的,它对人类易读易写,对机器易解析易生成。
-纯正的JSON实际上没有注释,但是大多数解析器都
-接受C-风格(//, /\* \*/)的注释。为了兼容性,最好不要在其中写这样形式的注释。
+一段JSON可以是下文列出的类型的任意值,但实际一般按以下两种方式之一呈现:
+
+* 一个键值对的集合(`{ }`)。按不同语言,这可能被理解为对象/记录/结构体/字典/哈希表/有键列表/关联数组
+* 一个有序的值列表(`[ ]`)。按不同语言,这可能被理解为数组/向量/列表/序列
+
+纯正的JSON实际上没有注释,但是大多数解析器都接受C-风格(//, /\* \*/)的注释。一些解析器还容许trailing comma,即最后一个数组元素或最后一个对象属性之后的逗号。不过为了兼容性最好避免。
因此,本教程的一切都会是100%有效的JSON。幸亏,它的表达能力很丰富。
支持的数据类型:
-- 字符串: "hello", "\"A quote.\"", "\u0abe", "Newline.\n"
-- 数字: 23, 0.11, 12e10, 3.141e-10, 1.23e+4
-- 对象: { "key": "value" }
-- 数组: ["Values"]
-- 其他: true, false, null
+* 字符串:`"hello"`、`"\"A quote.\""`、`"\u0abe"`、`"Newline.\n"`
+* 数字:`23`、`0.11`、`12e10`、`3.141e-10`、`1.23e+4`
+* 对象:`{ "key": "value" }`
+* 数组:`["Values"]`
+* 其它:`true`、`false`、`null`
```json
{
+ "key": "value",
+
+ "keys": "must always be enclosed in double quotes",
"numbers": 0,
"strings": "Hellø, wørld. All unicode is allowed, along with \"escaping\".",
"has bools?": true,
@@ -55,6 +61,23 @@ Learn X in Y Minutes。
]
],
- "that was short": "And, you're done. You now know everything JSON has to offer."
+ "alternative style": {
+ "comment": "check this out!"
+ , "comma position": "doesn't matter, if it's before the next key, it's valid"
+ , "another comment": "how nice"
+ },
+
+
+
+ "whitespace": "Does not matter.",
+
+
+
+ "that was short": "And done. You now know everything JSON has to offer."
}
```
+
+## 进一步阅读
+
+* [JSON.org](https://www.json.org/json-zh.html) 完美图解JSON的一切
+* [JSON Tutorial](https://www.youtube.com/watch?v=wI1CWzNtE-M) 简要介绍
diff --git a/zh-cn/nim-cn.html.markdown b/zh-cn/nim-cn.html.markdown
index dc662b1e..fa7d8259 100644
--- a/zh-cn/nim-cn.html.markdown
+++ b/zh-cn/nim-cn.html.markdown
@@ -3,7 +3,7 @@ language: Nim
filename: learnNim-cn.nim
contributors:
- ["Jason J. Ayala P.", "http://JasonAyala.com"]
- - ["Dennis Felsing", "http://felsin9.de/nnis/"]
+ - ["Dennis Felsing", "https://dennis.felsing.org"]
translators:
- ["lzw-723", "https://github.com/lzw-723"]
lang: zh-cn
diff --git a/zh-cn/ruby-cn.html.markdown b/zh-cn/ruby-cn.html.markdown
index 63adab64..b0b8b58c 100644
--- a/zh-cn/ruby-cn.html.markdown
+++ b/zh-cn/ruby-cn.html.markdown
@@ -430,7 +430,7 @@ def guests(*array)
array.each { |guest| puts guest }
end
-# 结构
+# 解构
# 如果函数返回一个数组,在赋值时可以进行拆分:
def foods
@@ -449,7 +449,7 @@ end
best *ranked_competitors.first(3) #=> Winners are John, Sally, and Dingus.
-# 结构操作符也可放在参数里面
+# 解构操作符也可放在参数里面
def best(first, second, third, *others)
puts "Winners are #{first}, #{second}, and #{third}."
puts "There were #{others.count} other participants."