diff options
51 files changed, 7780 insertions, 665 deletions
diff --git a/ansible.html.markdown b/ansible.html.markdown index 2b61cc8e..41a8c9b5 100644 --- a/ansible.html.markdown +++ b/ansible.html.markdown @@ -49,7 +49,7 @@ environments, it may be noticable amount. 'on-demand' - there is no built-in mechanism that would warn you about some change automatically (this can be achieved with reasonable effort) * Official GUI - Ansible Tower - is great but expensive. -* There is no 'small enterprice' payment plan, however Ansible AWX is the free +* There is no 'small enterprise' payment plan, however Ansible AWX is the free open source version we were all waiting for. #### Neutral diff --git a/awk.html.markdown b/awk.html.markdown index 1ef6b8d5..3ff3f937 100644 --- a/awk.html.markdown +++ b/awk.html.markdown @@ -382,3 +382,5 @@ Further Reading: * [Awk man page](https://linux.die.net/man/1/awk) * [The GNU Awk User's Guide](https://www.gnu.org/software/gawk/manual/gawk.html) GNU Awk is found on most Linux systems. * [AWK one-liner collection](http://tuxgraphics.org/~guido/scripts/awk-one-liner.html) +* [Awk alpinelinux wiki](https://wiki.alpinelinux.org/wiki/Awk) a technical summary and list of "gotchas" (places where different implementations may behave in different or unexpected ways). +* [basic libraries for awk](https://github.com/dubiousjim/awkenough) diff --git a/bc.html.markdown b/bc.html.markdown new file mode 100644 index 00000000..9d63acfb --- /dev/null +++ b/bc.html.markdown @@ -0,0 +1,98 @@ +--- +language: bc +contributors: + - ["Btup"] +filename: learnbc.bc +--- +```c +/*This is a multi- +line comment.*/ +# This is also a (one-line) comment! (in GNU bc). + + /*1. Variables and control structures*/ +num = 45 /*All variables save only doubles, and you cannot save + string constants directly.*/ +num = 45; /*You can choose to add a semicolon after + every statement. This is optional.*/ +/*Blocks are denoted using the {} operators(similar to C):*/ +while(num < 50) { + num += 1 /*equivalent to num=num+1. + a = a op b is equivalent to a op= b.*/ +} +/*And there are ++(increment) and --(decrement) operators.*/ +/*There are 3 special variables: +scale: defines the scale of the double numbers. +ibase: defines the base of input. +obase: defines the base of output.*/ +/*If clauses:*/ +hour = read() /*Input a number*/ + +if(hour < 12) { /*Operators are exactly like C.*/ + print "Good morning\n" /*"print" outputs strings or variables + separated by commas.*/ +} else if(hour == 12) { + print "Hello\n" + /*Escaping sequences start with a \ in a string. + In order to make the escaping sequences clearer, here + is a simplified list of them that will work in bc: + \b: backspace + \c: carriage return + \n: newline + \t: tab + \\: backslash*/ +} else { + /*Variables are global by default.*/ + thisIsGlobal = 5 + /*You can make a variable local. Use the "auto" keyword in a function.*/ +} + +/*Every variable is pre-set to 0.*/ +num = blankVariable /*num is set to 0.*/ + +/*Like C, only 0 is falsy.*/ +if(!num) {print "false\n"} + +/*Unlike C, bc does not have the ?: operators. For example, + this block of code will cause an error: +a = (num) ? 1 : 0 +However, you can simulate one:*/ +a = (num) && (1) || (0) /*&& is and, || is or*/ + +/*For loops*/ +num = 0 +for(i = 1; i <= 100; i++) {/*Similar to the C for loop.*/ + num += i +} + + /*2.Functions and Arrays*/ +define fac(n) { /*define a function using define.*/ + if(n == 1 || n == 0) { + return 1 /*return a value*/ + } + return n * fac(n - 1) /*recursion is possible*/ +} + +/*Closures and anonymous functions are impossible.*/ + +num = fac(4) /*24*/ + +/*This is an example of local variables:*/ +define x(n) { + auto x + x = 1 + return n + x +} +x(3) /*4*/ +print x /*It turns out that x is not accessible out of the function.*/ +/*Arrays are equivalent to the C array.*/ +for(i = 0; i <= 3; i++) { + a[i] = 1 +} +/*Access it like this:*/ +print a[0], " ", a[1], " ", a[2], " ", a[3], "\n" +quit /*Add this line of code to make sure +that your program exits. This line of code is optional.*/ +``` +Enjoy this simple calculator! (Or this programming language, to be exact.) + +This whole program is written in GNU bc. To run it, use ```bc learnbc.bc```. diff --git a/c++.html.markdown b/c++.html.markdown index 80ad3a6c..176ea1a8 100644 --- a/c++.html.markdown +++ b/c++.html.markdown @@ -72,7 +72,7 @@ void func(); // function which may accept any number of arguments int* ip = nullptr; // C standard headers are available in C++. -// C headers end in .h, while +// C headers end in .h, while // C++ headers are prefixed with "c" and have no ".h" suffix. // The C++ standard version: @@ -553,10 +553,14 @@ Point Point::operator+(const Point& rhs) const return Point(x + rhs.x, y + rhs.y); } +// It's good practice to return a reference to the leftmost variable of +// an assignment. `(a += b) == c` will work this way. Point& Point::operator+=(const Point& rhs) { x += rhs.x; y += rhs.y; + + // `this` is a pointer to the object, on which a method is called. return *this; } @@ -757,7 +761,7 @@ failure: // things are a little cleaner, but still sub-optimal. void doSomethingWithAFile(const char* filename) { - FILE* fh = fopen(filename, "r"); // Open the file in read mode + FILE* fh = fopen(filename, "r"); // Open the file in shared_ptrread mode if (fh == nullptr) throw std::runtime_error("Could not open the file."); @@ -811,6 +815,57 @@ void doSomethingWithAFile(const std::string& filename) ///////////////////// +// Smart Pointer +///////////////////// + +// Generally a smart pointer is a class, which wraps a "raw pointer" (usage of "new" +// respectively malloc/calloc in C). The goal is to be able to +// manage the lifetime of the object being point to without explicitly deleting +// the object. The term itself simply describes a set of pointers with the +// mentioned abstraction. +// Basically smart pointers should preferred over raw pointers, to prevent +// risky memory leaks, which happens if you forget to delete the object. + +// Usage of a raw pointer: +Dog* ptr = new Dog(); +ptr->bark(); +delete ptr; + +// With the usage of smart pointers you dont have to worry about the deletion +// of a object anymore. +// A smart pointer describes a policy, to count the references on the +// pointer. As matter of fact the objects gets destroyed when the last +// reference on the object gets destroyed. + +// Usage of "std::shared_ptr": +void foo() +{ +// Its not longer necessary to delete the Dog. +std::shared_ptr<Dog> doggo(new Dog()); +doggo->bark(); +} + +// Beware of possible circular references!!! +// There will be always a reference, so it will be never destroyed! +std::shared_ptr<Dog> doggo_one (new Dog()); +std::shared_ptr<Dog> doggo_two (new Dog()); +doggo_one = doggo_two; // p1 references p2 +doggo_two = doggo_one; // p2 references p1 + +// As mentioned before there is a set of smart pointers. The way you have to +// use it, is always the same. +// This leads us to question, when to use which one? +// std::unique_ptr - use it when you just want to hold one reference on +// the same object. +// std::shared_ptr - use it when you want to hold multiple references on the +// same object and want to make sure that it´s de-allocated +// when all refences are gone. +// std::weak_ptr - use it when you want to hold multiple references from +// different places for references for which it´s no problem +// tp de-allocate. + + +///////////////////// // Containers ///////////////////// @@ -873,7 +928,7 @@ cout << ST.size(); // will print the size of set ST // Output: 0 // NOTE: for duplicate elements we can use multiset -// NOTE: For hash sets, use unordered_set. They are more efficient but +// NOTE: For hash sets, use unordered_set. They are more efficient but // do not preserve order. unordered_set is available since C++11 // Map @@ -902,7 +957,7 @@ cout << it->second; // Output: 26 -// NOTE: For hash maps, use unordered_map. They are more efficient but do +// NOTE: For hash maps, use unordered_map. They are more efficient but do // not preserve order. unordered_map is available since C++11. // Containers with object keys of non-primitive values (custom classes) require diff --git a/chapel.html.markdown b/chapel.html.markdown index 354cd832..7e8fc41a 100644 --- a/chapel.html.markdown +++ b/chapel.html.markdown @@ -708,7 +708,7 @@ class MyClass { // We also get the compiler-generated initializer, with one argument per field. // Note that soon there will be no compiler-generated initializer when we // define any initializer(s) explicitly. - proc MyClass(val : real) { + proc init(val : real) { this.memberInt = ceil(val): int; } diff --git a/csharp.html.markdown b/csharp.html.markdown index f27adf18..df6544d3 100644 --- a/csharp.html.markdown +++ b/csharp.html.markdown @@ -344,7 +344,7 @@ on a new line! ""Wow!"", the masses cried"; tryInt.ToString(); // Casting - // Cast decimal 15 to a int + // Cast decimal 15 to an int // and then implicitly cast to long long x = (int) 15M; } diff --git a/cypher.html.markdown b/cypher.html.markdown index acd44733..32868354 100644 --- a/cypher.html.markdown +++ b/cypher.html.markdown @@ -50,7 +50,7 @@ Relationships (or Edges) **Connects two nodes** `[:KNOWS]` -It's a *relationship* with the *label* **KNOWS**. It's a *label* as the node's label. It begins with uppercase and use UPPER_SNAKE_CASE. +It's a *relationship* with the *label* **KNOWS**. It's a *label* as the node's label. It begins with uppercase and use UPPER\_SNAKE\_CASE. `[k:KNOWS]` The same *relationship*, referred by the variable **k**, reusable in the query, but it's not necessary. diff --git a/de-de/asciidoc-de.html.markdown b/de-de/asciidoc-de.html.markdown index 24100e0b..e3f64a00 100644 --- a/de-de/asciidoc-de.html.markdown +++ b/de-de/asciidoc-de.html.markdown @@ -88,7 +88,7 @@ Abteilungstitel Listen -Um eine Aufzählung zu erstellen verwendest du Sternchen. +Um eine Aufzählung zu erstellen, verwendest du Sternchen. ``` * foo @@ -96,7 +96,7 @@ Um eine Aufzählung zu erstellen verwendest du Sternchen. * baz ``` -Um eine nummerierte Liste zu erstellen verwendest du Punkte. +Um eine nummerierte Liste zu erstellen, verwendest du Punkte. ``` . item 1 @@ -104,7 +104,7 @@ Um eine nummerierte Liste zu erstellen verwendest du Punkte. . item 3 ``` -Um Listen zu verschachteln musst du zusätzliche Sternchen beziehungsweise Punkte hinzufügen. Dies ist bis zu fünf Mal möglich. +Um Listen zu verschachteln, musst du zusätzliche Sternchen beziehungsweise Punkte hinzufügen. Dies ist bis zu fünf Mal möglich. ``` * foo 1 diff --git a/de-de/c++-de.html.markdown b/de-de/c++-de.html.markdown new file mode 100644 index 00000000..cef7514b --- /dev/null +++ b/de-de/c++-de.html.markdown @@ -0,0 +1,1157 @@ +--- +language: c++ +filename: learncpp-de.cpp +contributors: + - ["Steven Basart", "http://github.com/xksteven"] + - ["Matt Kline", "https://github.com/mrkline"] + - ["Geoff Liu", "http://geoffliu.me"] + - ["Connor Waters", "http://github.com/connorwaters"] + - ["Ankush Goyal", "http://github.com/ankushg07"] + - ["Jatin Dhankhar", "https://github.com/jatindhankhar"] + - ["Maximilian Sonnenburg", "https://github.com/LamdaLamdaLamda"] +lang: de-de +--- + +C++ ist eine Systemprogrammiersprache die, + +[laut dem Begründer Bjarne Stroustrup](http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Keynote) +entworfen wurde um, + +- "besseres C" zu sein +- Datenabstraktion zu unterstützen +- Objektorientierung zu unterstützen +- generische Programmierung zu unterstützen + +Durch seinen Syntax kann sie durchaus schwieriger und komplexer als neuere Sprachen sein. + +Sie ist weit verbreitet, weil sie in Maschinen-Code kompiliert, welches direkt vom Prozessor ausgeführt +werden kann und somit eine strikte Kontrolle über die Hardware bietet und gleichzeitig +High-Level-Features wie generics, exceptions und Klassen enthält. + +Diese Kombination aus Geschwindigkeit und Funktionalität bildet C++ und ist eine der +weitverbreitesten Programmiersprachen. + +```c++ +////////////////// +// Vergleich zu C +////////////////// + +// C ist fast eine Untermenge von C++ und teilt sich grundsätzlich den +// Syntax für Variablen Deklarationen, primitiven Typen und Funktionen. + +// Wie in C ist der Programmeinsprungpunkt eine Funktion, welche "main" genannt wird und +// einen Integer als Rückgabetyp besitzt. + +// Dieser Wert fungiert als Beendigungsstatus des Programms. +// Siehe: https://de.wikipedia.org/wiki/Return_Code für weitere Informationen +int main(int argc, char** argv) +{ + // Kommandozeilen Argumente werden genauso wie in C über argc und argv übergeben + // argc entspricht der Anzahl von Argumenten und argv ist ein Array von C-style + // strings (char*), welche die Argumente repräsentieren. + // Das erste Argument ist der Name des Programms, welches aufgerufen wird. + // Argc und argv können, wenn nicht benötigt, weg gelassen werden, indem + // die Funktionssignatur "int main()" verwendet wird. + + // Ein Rückgabewert von 0 repräsentiert die erfolgreiche Ausführung. + return 0; +} + +// C++ unterscheidet sich in einigen Punkten von C: + +// In C++ sind Zeichen-Literale char´s +sizeof('c') == sizeof(char) == 1 + +// In C sind Zeichen-Literale int´s +sizeof('c') == sizeof(int) + +// C++ verwendet striktes prototyping +void func(); // Funktion ohne Argumente + +// In C +void func(); // Funktion mit beliebiger Anzahl von Argumenten + +// Verwende nullptr, anstatt von NULL!!! +int* ip = nullptr; + +// C standard header sind in C++ verfügbar. +// C header enden mit .h, während +// C++ header das Präfix "c" besitzen und kein ".h" Suffix verwenden. + +// Die C++ Standard Version: +#include <cstdio> + +// Die C Standard Version: +#include <stdio.h> + +int main() +{ + printf("Hello, world!\n"); + return 0; +} + +/////////////////////// +// Funktionsüberladung +/////////////////////// + +// C++ unterstützt Funktionsüberladung +// Jede Funktion kann unterschiedliche Parameter erhalten. +void print(char const* myString) +{ + printf("String %s\n", myString); +} + +void print(int myInt) +{ + printf("My int is %d", myInt); +} + +int main() +{ + print("Hello"); // Wird aufgelöst zu "void print(const char*)" + print(15); // Wird aufgelöst zu "void print(int)" +} + +///////////////////////////// +// Standard Funktionsargumente +///////////////////////////// + +// Argumente können per Standard für eine Funktion gesetzt werden, +// wenn diese beim Aufruf nicht bereitgestellt werden. +void doSomethingWithInts(int a = 1, int b = 4) +{ + // führe Anweisungen mit "int´s" aus. +} + +int main() +{ + doSomethingWithInts(); // a = 1, b = 4 + doSomethingWithInts(20); // a = 20, b = 4 + doSomethingWithInts(20, 5); // a = 20, b = 5 +} + +// Standard-Argumente müssen am Ende der Liste der Argumente stehen. +void invalidDeclaration(int a = 1, int b) // Fehler! +{ +} + + +///////////// +// Namespaces (Namesräume) +///////////// + +// Namespaces stellen einen getrennten Gültigkeitsbereich für Variablen, +// Funktionen und andere Deklarationen zur Verfügung. +// Namespaces können geschachtelt werden. +namespace First +{ + namespace Nested + { + void foo() + { + printf("This is First::Nested::foo\n"); + } + } // Ende des Namespace "Nested" +} // Ende des Namespace "First" + +namespace Second +{ + void foo() + { + printf("This is Second::foo\n"); + } +} + +void foo() +{ + printf("This is global foo\n"); +} + +int main() +{ + // Fügt all Symbole aus dem namespace Second in den aktuellen Gültigkeitsbereich (scope). + // "foo()" wird nun nicht länger funktionieren, da es nun doppeldeutig ist, ob foo aus + // dem namespace foo oder darüberliegenden aufgerufen wird. + using namespace Second; + + Second::foo(); // Gibt "This is Second::foo" aus. + First::Nested::foo(); // Gibt "This is First::Nested::foo" aus. + ::foo(); // Gibt "This is global foo" aus. +} + +/////////////// +// Eingabe/Ausgabe +/////////////// + +// C++ verwendet für die Eingabe und Ausgabe streams. +// cin, cout und cerr repräsentieren stdin, stdout und stderr. +// << ist der Einfügeoperator und >> ist der Extraktionsoperator. + +#include <iostream> // Include für Eingabe/Ausgabe (I/O) streams + +using namespace std; // Streams befinden sich im std namespace (standard library) + +int main() +{ + int myInt; + + // Ausgabe auf stdout (oder Terminal/Bildschirm) + cout << "Enter your favorite number:\n"; + + // Empfängt Eingabe + cin >> myInt; + + // cout kann ebenfalls formatiert werden + cout << "Your favorite number is " << myInt << "\n"; + // Gibt "Your favorite number is <myInt>" aus + + cerr << "Used for error messages"; +} + +////////// +// Zeichenketten (Strings) +////////// + +// Strings in C++ sind Objekte und haben diverse member-functions +#include <string> + +using namespace std; // Strings sind ebenfalls im namespace std (Standard Bibliothek) + +string myString = "Hello"; +string myOtherString = " World"; + +// + wird für das Anhängen von strings verwendet. +cout << myString + myOtherString; // "Hello World" + +cout << myString + " You"; // "Hello You" + +// C++ strings sind mutable. +myString.append(" Dog"); +cout << myString; // "Hello Dog" + + +///////////// +// Referenzen +///////////// + +// Zusätzlich zu Pointern, wie jene in C. +// C++ besitzt _Referenzen_. +// Diese sind Pointer-Typen, welche nicht erneut zugewiesen werden können +// und nicht Null sein können. +// Sie besitzen den selben Syntax wie Variablen. +// Für die Dereferenzierung ist kein * notwendig und +// & (die Adresse) wird nicht für die Zuweisung verwendet. + +using namespace std; + +string foo = "I am foo"; +string bar = "I am bar"; + + +string& fooRef = foo; // Erzeugt eine Referenz auf foo. +fooRef += ". Hi!"; // Verändert foo durch die Referenz +cout << fooRef; // Gibt "I am foo. Hi!" aus. + + +// Weist "fooRef" nicht erneut zu. Dies ist dasselbe, wie "foo = bar" und +// foo == "I am bar" +// nach dieser Zeile +cout << &fooRef << endl; // Gibt die Adresse von foo aus +fooRef = bar; +cout << &fooRef << endl; // Gibt ebenfalls die Adresse von foo aus +cout << fooRef; // Gibt "I am bar" aus + +// Die Adresse von fooRef verbleibt die selbe, sie verweist immer noch auf foo + +const string& barRef = bar; // Erzeugt konstante Referenz auf bar. +// Wie in C, können konstante Werte ( und Pointer bzw. Referenzen) nicht verändert werden. + +barRef += ". Hi!"; // Fehler: konstante Referenzen können nicht verändert werden. + +// Hinweis: bevor wir genauer Referenzen besprechen, schauen wir uns zuerst ein Konzept an, +// welches als "temporäres Objekt" bezeichnet wird. Gehen wir von folgenden Code aus: +string tempObjectFun() { ... } +string retVal = tempObjectFun(); + +// Was passiert nun in der zweiten Zeile: +// - ein String Objekt wird von "tempObjectFun" zurückgegeben +// - ein neuer String wird mit dem zurückgegebenen Objekt als Argument für den Konstruktor erzeugt. +// - das zurückgegebene Objekt wird zerstört +// Das zurückgegbene Objekt wird temporäres Objekt genannt. Temporäre Objekte werden erzeugt +// wann immer eine Funktion ein Objekt zurückgibt. Zerstört werden diese am Ende der Auswertung des Ausdrucks +// (dies schreibt der Standard vor, aber Compiler sind berechtigt dieses Verhalten zu ändern. Siehe "return value optimization" +// für Details). Wie in diesem Code: +foo(bar(tempObjectFun())) + +// Nehmen wir an foo und bar existieren. Das Objekt wird von "tempObjectFun" zurückgegeben, +// wird an bar übergeben und ist zerstört bevor foo aufgerufen wird. + +// Zurück zu Referenzen. Die Annahme, dass die "am Ende des Ausdrucks" Regel gültig ist, +// wenn das temporäre Objekt an eine konstante Referenz gebunden ist, ist der Fall, wenn die Lebensdauer +// auf den aktuellen Gültigkeitsbereich erweitert wird. + +void constReferenceTempObjectFun() { + // constRef erhält das temporäre Objekt und ist gültig bis ans Ende der Funktion + const string& constRef = tempObjectFun(); + ... +} + +// Eine andere Art von Referenzen wurde in C++11 eingeführt und ist speziell für +// temporäre Objekte. Es ist nicht möglich Variablen des Typs zu besitzen, aber +// Vorrechte bei der Auflösung zu besitzen. + +void someFun(string& s) { ... } // Reguläre Referenz +void someFun(string&& s) { ... } // Referenz auf ein temporäres Objekt + +string foo; +someFun(foo); // Ruft die Funktion mit der regulären Referenz auf +someFun(tempObjectFun()); // Ruft die Funktion mit der temporären Referenz auf + +// Zum Beispiel existieren diese zwei Varianten von Konstruktoren für +// std::basic_string: +basic_string(const basic_string& other); +basic_string(basic_string&& other); + +// Nehmen wir an, wir erzeugen einen neuen String eines temporären Objekts (welches später +// zerstört wird), hierbei existiert ein effizienterer Konstruktor. Dieses Konzept wird +// als "move semantics" bezeichnet (bewegen eines Objekts in ein anderes in C++). + +///////////////////// +// Enumerations (Aufzählungstypen) +///////////////////// + +// Enums sind eine einfachere Art und Weise einen Wert einer Konstante zu zuweisen. +// Häufig wird dies verwendet, um den Code lesbarer zu gestalten bzw. zu visualisieren. +enum ECarTypes +{ + Sedan, + Hatchback, + SUV, + Wagon +}; + +ECarTypes GetPreferredCarType() +{ + return ECarTypes::Hatchback; +} + +// Mit C++11 existiert eine einfache Möglichkeit einem Typ dem Enum zu zuweisen. Dies +// kann durchaus sinnvoll bei der Serialisierung von Daten sein, oder bei der Konvertierung +// zwischen Typen bzw. Konstanten. +enum ECarTypes : uint8_t +{ + Sedan, // 0 + Hatchback, // 1 + SUV = 254, // 254 + Hybrid // 255 +}; + +void WriteByteToFile(uint8_t InputValue) +{ + // Serialisierung von "InputValue" in eine Datei +} + +void WritePreferredCarTypeToFile(ECarTypes InputCarType) +{ + // Das enum wird implizit zu einem "uint8_t" konvertiert. Bedingt dadurch, dass + // es sich um ein "enum" handelt. + WriteByteToFile(InputCarType); +} + +// Nicht immer ist es gewünscht, dass enum´s zu einem Integer oder zu einem anderen +// enum umgewandelt werden. Daher ist es möglich eine enum-Klasse zu erzeugen, welche +// nicht implizit umgewandelt wird. +enum class ECarTypes : uint8_t +{ + Sedan, // 0 + Hatchback, // 1 + SUV = 254, // 254 + Hybrid // 255 +}; + +void WriteByteToFile(uint8_t InputValue) +{ + // Serialisierung von InputValue in eine Datei +} + +void WritePreferredCarTypeToFile(ECarTypes InputCarType) +{ + // Wird nicht kompilieren, da "ECarTypes" ein "uint8_t" ist, da das enum + // als "enum class" deklariert wurde! + WriteByteToFile(InputCarType); +} + +////////////////////////////////////////// +// Klassen und objekorientierte Programmierung +////////////////////////////////////////// + +// Erstes Beispiel einer Klasse +#include <iostream> + +// Deklaration einer Klasse. +// Klassen werden üblicherweise im header (.h oder .hpp) deklariert. +class Dog +{ + // Member Variablen und Funktionen sind private per default (standard). + std::string name; + int weight; + +// Alle nachfolgenden member sind "public" bis +// "private:" oder "protected:" auftritt. +public: + + // Standard Konstruktor + Dog(); + + // Member-Funktionsdeklaration (Implementierung folgt). + // Bemerkung: std::string statt der Verwendung von namespace std; + // "using namespace" sollte niemals in einem header verwendet werden. + void setName(const std::string& dogsName); + + void setWeight(int dogsWeight); + + // Funktionen, die Objekte nicht ändern, sollten mit const deklariert werden. + // Funktionen müssen explizit als "virtual" deklariert werden, um in einer + // abgeleiteten Klassen überschrieben zu werden. + // Aus performance Gründen sind Funktionen nicht per default virtual. + virtual void print() const; + + // Funktionen können ebenfalls im class body definiert werden. + // Derart definierte Funktionen sind automatisch "inline". + void bark() const { std::cout << name << " barks!\n"; } + + // Neben Konstruktoren, bietet C++ Destruktoren. + // Diese werden aufgerufen, wenn ein Objekt freigegeben wird oder + // seinen Wertebereich verlässt. + // Dies ermöglicht mächtige Paradigmen, wie auch RAII. + // Destruktoren sollten virtual sein, wenn eine Klasse von ihr + // abgeleitet wird. Ist dieser nicht virtual, dann wird der + // Destruktor der abgeleiteten Klasse nicht aufgerufen, insofern + // das Objekt durch eine Referenz/Pointer der Basisklasse entfernt wird. + virtual ~Dog(); + +}; // Ein Semikolon schließt die Definition der Klasse ab. + +// Klassen-Member-Funktionen sind üblicherweise in der .cpp Datei implementiert. +Dog::Dog() +{ + std::cout << "A dog has been constructed\n"; +} + +// Objekte sollten als Referenz übergeben werden und wenn diese nicht +// verändert werden sollen, sollte das Objekt als const Referenz übergeben werden. +void Dog::setName(const std::string& dogsName) +{ + name = dogsName; +} + +void Dog::setWeight(int dogsWeight) +{ + weight = dogsWeight; +} + +// "Virtual" wird nur bei der Deklaration benötigt und nicht bei der Definition. +void Dog::print() const +{ + std::cout << "Dog is " << name << " and weighs " << weight << "kg\n"; +} + +Dog::~Dog() +{ + std::cout << "Goodbye " << name << "\n"; +} + +int main() +{ + Dog myDog; // Ausgabe: "A dog has been constructed" + myDog.setName("Barkley"); + myDog.setWeight(10); + myDog.print(); // Ausgabe: "Dog is Barkley and weighs 10 kg" + return 0; +} // Ausgabe: "Goodbye Barkley" + +// Diese Klasse erbt alles was public bzw. protected ist von der Dog-Klasse +// und darüber hinaus auch private Methoden/Attribute, jedoch kann auf diese +// nicht direkt zugegriffen werden. Lediglich über public/procted getter/setter. +class OwnedDog : public Dog { + +public: + void setOwner(const std::string& dogsOwner); + + // Überschreibt das Verhalten der "print" Funktion für alle "OwnedDogs". + // Siehe: http://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Subtyping + // für eine grundlegende Einführung in "Subtype Polymorphismus". + // Das "override" Schlüsselwort ist optional, aber stellt sicher, dass die + // Methode der Basisklasse tatsächlich überschrieben wurde. + void print() const override; + +private: + std::string owner; +}; + +// Die zugehörige .cpp Datei +void OwnedDog::setOwner(const std::string& dogsOwner) +{ + owner = dogsOwner; +} + +void OwnedDog::print() const +{ + Dog::print(); // Ruft die "print" Funktion der Basisklasse auf. + std::cout << "Dog is owned by " << owner << "\n"; + // Ausgaben: "Dog is <name> and weights <weight>" + // "Dog is owned by <owner>" +} + +////////////////////////////////////////// +// Initialisierung und Operatorüberladung +////////////////////////////////////////// + +// In C++ können Operatoren wie: +, -, *, / etc. überladen werden. +// Dies wird umgesetzt, indem eine entsprechende Funktion definiert wird, +// welche immer dann aufgerufen wird, sobald der Operator verwendet wird. +#include <iostream> +using namespace std; + +class Point +{ +public: + // Member Variablen können mit einem default Wert initialisiert werden. + double x = 0; + double y = 0; + + // Definition des Standard Konstruktor, welcher nichts tut + // außer den Punkt auf den default Wert (0,0) zu setzen. + Point() { }; + + // Die nachfolgende Syntax ist bekannt als "initialization list" + // und ist eine gängige Art Klassen-Member zu initialisieren. + Point (double a, double b) : + x(a), + y(b) + { /* Außschließliche Initialisierung der Werte */ } + + // Überladung des "+" Operator. + Point operator+(const Point& rhs) const; + + // Überladung des "+=" Operator + Point& operator+=(const Point& rhs); + + // Sinnhaft wäre es an dieser Stelle den "-" und "-=" Operator + // ebenfalls zu überladen. +}; + +Point Point::operator+(const Point& rhs) const +{ + // Erzeugung eines neuen Punkts, welcher die Summe aus sich + // selbst und "rhs" bildet + return Point(x + rhs.x, y + rhs.y); +} + +Point& Point::operator+=(const Point& rhs) +{ + x += rhs.x; + y += rhs.y; + return *this; +} + +int main () +{ + Point up (0,1); + Point right (1,0); + + // Ruft den + Operator mit den entsprechenden Parametern auf. + Point result = up + right; + // Ausgabe: "Result is upright (1,1)" + cout << "Result is upright (" << result.x << ',' << result.y << ")\n"; + return 0; +} + +///////////////////// +// Templates +///////////////////// + +// Templates in C++ werden in erster Linie dafür verwendet generisch zu programmieren. +// Sie unterstützen explizite und partielle Spezialisierung und darüber hinaus können +// sie für funktionale Klassen verwendet werden. +// Tatsächlich bilden templates die Turing-Vollständigkeit +// (universelle Programmierbarkeit) ab. + + +// Zu Beginn ein einführendes Beispiel der generischen Programmierung. +// Die Definition einer Klasse bzw. Funktion, welche mit dem Typ T parametriert wird. +template<class T> +class Box +{ +public: + // T repräsentiert an dieser Stelle einen beliebigen Typen. + void insert(const T&) { ... } +}; + +// Während der Kompilierung generiert der Compiler Kopien für jedes template, wobei +// hierbei die Parameter substituiert werden. Somit muss bei jedem Aufruf die gesamte +// Definition der Klasse zur Verfügung stehen. Aus diesem Grund wird ein Template +// komplett im header definiert. + +// Erzeugung einer Template-Klasse auf dem stack: +Box<int> intBox; + +// eine der zu erwartenden Verwendungen: +intBox.insert(123); + +// Verschachtelungen von Templates sind möglich. +Box<Box<int> > boxOfBox; +boxOfBox.insert(intBox); + +// Bis C++11 war es erforderlich ein Leerzeichen zwischen '>' einzufügen, +// andernfalls wurde es als '>>' geparsed (right shift). + +// Manchmal ist folgende Notation anzutreffen: +// template<typename T> +// Das 'class' Schlüsselwort und das 'typename' Schlüsselwort +// sind fast identisch hinsichtlich der Funktionalität. Weitere +// Informationen auf: http://en.wikipedia.org/wiki/Typename + +// Eine template-Funktion: +template<class T> +void barkThreeTimes(const T& input) +{ + input.bark(); + input.bark(); + input.bark(); +} + +// Hierbei ist zu beachten, dass an dieser Stelle nichts über den Typen des Parameters +// definiert wurde. Der Kompiler wird bei jedem Aufruf bzw. jeder Erzeugung den Typen +// prüfen. Somit funktioniert die zuvor definierte Funktion für jeden Typ 'T', die die +// const Methode 'bark' implementiert hat. + +Dog fluffy; +fluffy.setName("Fluffy") +barkThreeTimes(fluffy); // Gibt "Fluffy barks" dreimal aus. + +// Template Parameter müssen keine Klassen sein. +template<int Y> +void printMessage() +{ + cout << "Learn C++ in " << Y << " minutes!" << endl; +} + +// Des Weiteren können templates aus Effizienzgründen genauer spezifiziert werden. +// Selbstverständlich sind reale-Problemen, welche genauer spezifiziert werden nicht +// derart trivial. Auch wenn alle Parameter explizit definiert wurden, muss die +// Funktion oder Klasse als template deklariert werden. +template<> +void printMessage<10>() +{ + cout << "Learn C++ faster in only 10 minutes!" << endl; +} + +printMessage<20>(); // Gibt "Learn C++ in 20 minutes!" aus. +printMessage<10>(); // Gibt "Learn C++ faster in only 10 minutes!" aus. + + +///////////////////// +// Ausnahme Behandlungen (Exception-Handling) +///////////////////// + +// Die Standard Bibliothek bietet einige exceptions. +// Siehe: http://en.cppreference.com/w/cpp/error/exception. +// Grundsätzlich können alle Typen als exception geworfen werden. +#include <exception> +#include <stdexcept> + +// Alle exceptions, die in dem "try" Block geworfen werden, können mittels +// "catch" abgefangen werden. +try +{ + // exceptions sollten nicht auf dem heap mithilfe + // von "new" allokiert werden. + throw std::runtime_error("A problem occurred"); +} + +// Exceptions sollten als const Referenz abgefangen werden +// insofern diese Objekte sind. +catch (const std::exception& ex) +{ + std::cout << ex.what(); +} + +// Abfangen aller Exceptions, welche zuvor nicht abgefangen wurden. +catch (...) +{ + std::cout << "Unknown exception caught"; + throw; // Erneutes werfen der exception +} + +/////// +// RAII +/////// + +// RAII steht für "Resource Acquisition Is Initialization". +// Oft wird dies als eines der wichtigsten Paradigmen in C++ betrachtet. +// RAII beschreibt das Konzept, dass der Konstruktor für ein Objekt +// die Ressourcen akquiriert und der Destruktor diese freigibt. + +// Zum Verständnis, warum dies sinnvoll ist, nachfolgend +// ein einführendes Beispiel: +void doSomethingWithAFile(const char* filename) +{ + // Wir nehmen an, dass nichts schiefgehen wird. + FILE* fh = fopen(filename, "r"); // Öffnen der Datei im read-mode. + + doSomethingWithTheFile(fh); + doSomethingElseWithIt(fh); + + fclose(fh); // Schließen des file-handle. +} + +// Unglücklicherweise ist die Fehlerbehandlung äußerst kompliziert. +// Sollte fopen fehlschlagen und "doSomethingWithTheFile" bzw. +// "doSomethingElseWithIt", geben diese einen Fehlercode zurück. +// (Exceptions sind eine bevorzugte Möglichkeit Fehler abzufangen +// , allerdings bei einigen Programmierern, besonders solchen die einen C +// background besitzen, ein unbeliebtes Mittel zur Fehlerbehandlung). +// Nun müssen wir jeden Aufruf auf mögliche auftretende Fehler überprüfen. +bool doSomethingWithAFile(const char* filename) +{ + FILE* fh = fopen(filename, "r"); // Öffnet die Datei im read-mode + if (fh == nullptr) // Der Pointer ist bei einem Fehler NULL . + return false; // Benachrichtigt den Aufrufer über den Fehler. + + // Wir nehmen an, dass jede Funktion false zurückgibt, in einem Fehlerfall + if (!doSomethingWithTheFile(fh)) + { + fclose(fh); // File handle schließen. + return false; // Fehler "melden". + } + + if (!doSomethingElseWithIt(fh)) + { + fclose(fh); // File handle schließen. + return false; // Fehler "melden". + } + + fclose(fh); // File handle schließen. + return true; // Erfolg "melden". +} + +// C-Programmierer handhaben dies häufig durch goto-Anweisungen: +bool doSomethingWithAFile(const char* filename) +{ + FILE* fh = fopen(filename, "r"); + if (fh == nullptr) + return false; + + if (!doSomethingWithTheFile(fh)) + goto failure; + + if (!doSomethingElseWithIt(fh)) + goto failure; + + fclose(fh); // File handle schließen. + return true; // Erfolg "melden". + +failure: + fclose(fh); + return false; // Fehler "melden". +} + +// Insofern Funktionen Fehler durch exceptions indizieren, +// ist dies "sauberer", aber immer noch suboptimal. +void doSomethingWithAFile(const char* filename) +{ + FILE* fh = fopen(filename, "r"); // Öffnet die Datei im read-mode + if (fh == nullptr) + throw std::runtime_error("Could not open the file."); + + try + { + doSomethingWithTheFile(fh); + doSomethingElseWithIt(fh); + } + catch (...) + { + // Im Fehlerfall sollte sichergestellt sein, dass die + // Datei geschlossen wird. + fclose(fh); + throw; // Erneutes werfen der exception + } + + fclose(fh); // Schließen der Datei +} + +// Folgendes ist mit der C++ file stream Klasse (fstream) zu vergleichen. +// fstream verwendet den Destruktor, um die Datei zu schließen. +// Der obige Destruktor wird automatisch aufgerufen, sobald das Objekt +// den Gültigkeitsbereich verlässt. +void doSomethingWithAFile(const std::string& filename) +{ + // ifstream entspricht der Kurzform von "input file stream". + std::ifstream fh(filename); // Öffnen der Datei + + doSomethingWithTheFile(fh); + doSomethingElseWithIt(fh); + +} // Die Datei wird automatisch vom Destruktor geschlossen. + +// Diese Vorgehensweise bietet massive Vorteile: +// 1. Egal was passiert, die Ressource (das Datei-Handle) wird aufgelöst, +// insofern der Destruktor korrekt beschrieben wurde. Es ist möglich +// zu vergessen das Datei-Handle zu schließen, was zu einem "leak" der +// entsprechenden Ressource führt. +// 2. Der Code selbst ist wesentlich "sauberer". +// Der Destruktor wird das Datei-Handle im Hintergrund schließen und der +// Programmierer muss sich darum keinerlei Sorgen machen. +// 3. Der Code ist "exception sicher". +// Egal wo die exception geworfen wird, das Aufräumen wird definitiv vollzogen. + +// Der gesamte idiomatische C++ Code verwendet RAII für alle Ressourcen. +// Weitere Beispiele: +// - Speicher verwenden "unique_ptr" und "shared_ptr". +// - Container - verkettete Listen (linked list), vector (selbst organisierende +// Arrays), hash maps, etc., entfernen deren Inhalt, wenn diese außerhalb des +// Gültigkeitsbereichs laufen. +// - Mutex´s verwenden lock_guard und unique_lock. + +///////////////////// +// Container +///////////////////// + +// Die Container der Standard template Bibliothek beinhaltet einige vordefinierter templates. +// Diese verwalten die Speicherbereiche für die eigenen Elemente und stellen Member-Funktionen +// für den Zugriff und die Maniplulation bereit. + +// Beispielhafte Container: + +// Vector (dynamisches array) +// Erlaubt das Definieren von Arrays oder Listen zur Laufzeit +#include <vector> +string val; +vector<string> my_vector; // Initialisierung des Vectors. +cin >> val; +my_vector.push_back(val); // Fügt den Wert "val" zum Vektor "my_vector" hinzu. +my_vector.push_back(val); // Fügt den Wert "val" zum Vektor "my_vector" hinzu (nun zwei Elemente). + +// Für die Iteration über Vektoren stehen zwei Methodiken zu Verfügung: +// Entweder die klassische Iteration über den Index: +for (int i = 0; i < my_vector.size(); i++) +{ + cout << my_vector[i] << endl; // Zugriff auf die Elemente des Vektors über den [] Operator +} + +// Oder die Verwendung von Iteratoren: +vector<string>::iterator it; // Initialisierng des Iterators. +for (it = my_vector.begin(); it != my_vector.end(); ++it) +{ + cout << *it << endl; +} + +// Set (Mengen) +// Sets sind Container, welche einzigartige Elemente beinhalten die einer +// spezifischen Ordnung folgen. + +#include<set> +set<int> ST; // Initialisierung des Sets mit einem Integer Datentyp. +ST.insert(30); // Einfügen des Werts 30 in das Set ST +ST.insert(10); // Einfügen des Werts 10 in das Set ST +ST.insert(20); // Einfügen des Werts 20 in das Set ST +ST.insert(30); // Einfügen des Werts 30 in das Set ST +// Folgende Elemente befinden sich nun in dem Set: +// 10 20 30 + +// Entfernen eines Elements: +ST.erase(20); + +// Set ST: 10 30 +// Für das iterieren verwenden wir Iteratoren: +set<int>::iterator it; + +for(it=ST.begin();it<ST.end();it++) +{ + cout << *it << endl; +} + +// Ausgabe: +// 10 +// 30 + +// Zum leeren des gesamten Container wird die Methode +// Container._name.clear() verwendet. +ST.clear(); +cout << ST.size(); // Ausgabe der Set-Größe + +// Ausgabe: 0 + +// Bemerkung: für mehrdeutige Elemente werden multisets verwendet. +// Für hash-Sets sollten unordered_set´s verwendet werden, da diese +// wesentlich effizienter sind, allerdings keiner Ordnung folgen. +// Verfügbar sind diese Features ab C++11. + +// Map +// Maps speichern Elemente, welche einer Kombination aus "Key" +// und "Value" folgen. + +#include<map> +map<char, int> mymap; // Initialisierung der Map: char -> Key, int -> Value. + +mymap.insert(pair<char,int>('A',1)); // Einfügen des Werts "1" für den Key "A". + +mymap.insert(pair<char,int>('Z',26)); // Einfügen des Werts "26" für den Key "Z". + +// Das Iterieren über Maps: +map<char,int>::iterator it; +for (it=mymap.begin(); it!=mymap.end(); ++it) + std::cout << it->first << "->" << it->second << '\n'; + +// Ausgabe: +// A->1 +// Z->26 + +// Für das Finden des dazugehörigen Value des Keys. +it = mymap.find('Z'); +cout << it->second; + +// Ausabe: 26 + +// Bemerkung: für "hash maps" sollten die "unordered_map´s" verwendet werden. Diese +// sind effizienter und benötigen keine Reihenfolge. "unordered_maps" sind ab +// C++11 verfügbar. + +// Container für nicht-primitive Datentypen benötigen Vergleichsfunktionen im Objekt selbst, +// oder als Funktionspointer. Primitive Datentypen besitzen default-Vergleichsfunktionen. +// Allerdings können diese überschrieben werden. +class Foo +{ +public: + int j; + Foo(int a) : j(a) {} +}; + +struct compareFunction +{ + bool operator()(const Foo& a, const Foo& b) const + { + return a.j < b.j; + } +}; + +// Folgender Code ist nicht valide, könnte aber von einigen Compilern +// als valide angesehen werden: +// std::map<Foo, int> fooMap; +std::map<Foo, int, compareFunction> fooMap; +fooMap[Foo(1)] = 1; +fooMap.find(Foo(1)); // Wahr + + +/////////////////////////////////////// +// Lambda Ausdrücke (C++11 und höher) +/////////////////////////////////////// + +// Lambdas sind eine gängige Methodik um anonyme Funktionen an dem +// Ort der Verwendung zu definieren. Darüber hinaus auch bei der +// Verwendung von Funktionen als Argument einer Funktion. + +// Nehmen wir an es soll ein Vektor von "pairs" (Paaren) mithilfe +// des zweiten Werts des "pairs" sortiert werden. + +vector<pair<int, int> > tester; +tester.push_back(make_pair(3, 6)); +tester.push_back(make_pair(1, 9)); +tester.push_back(make_pair(5, 0)); + +// Übergabe des Lambda-Ausdrucks als drittes Argument für die nachfolgende Sortierfunktion. +sort(tester.begin(), tester.end(), [](const pair<int, int>& lhs, const pair<int, int>& rhs) +{ + return lhs.second < rhs.second; +}); + +// Beachte den Syntax von Lambda-Ausdrücken. +// Die [] im Lambda Ausdruck werden für die Variablen verwendet. +// Diese so genannte "capture list" definiert, was außerhalb des Lambdas, +// innerhalb der Funktion verfügbar sein soll und in welcher Form. +// Dies kann folgendes sein: +// 1. ein Wert [x] +// 2. eine Referenz [&x] +// 3. eine beliebige Variable, welche sich im Gültigkeitsbereich durch +// die Referenz [&] befindet. +// 4. wie bei 3. aber mithilfe des Werts [=] +// Beispiel: + +vector<int> dog_ids; + +for(int i = 0; i < 3; i++) +{ + dog_ids.push_back(i); +} + +int weight[3] = {30, 50, 10}; + +// Nehmen wir an wir möchten die "dog_ids" gemäß des Gewichts des Hundes sortieren. +// So sollten sich die "dog_ids" wie folgt verhalten: [2, 0, 1] + +// Hier werden Lambdas praktisch: +sort(dog_ids.begin(), dog_ids.end(), [&weight](const int &lhs, const int &rhs) +{ + return weight[lhs] < weight[rhs]; +}); + + +// Weiterführender Link über Lambda-Ausdrücke: +// http://stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11 + +/////////////////////////////// +// Range For (C++11 und höher) +/////////////////////////////// + +// Range-For Schleifen können verwendet werden, um über Container zu iterieren. +int arr[] = {1, 10, 3}; + +for(int elem: arr) +{ + cout << elem << endl; +} + +// Insofern "auto" verwendet wird, muss der Typ nicht weiter beachtet werden. +for(auto elem: arr) +{ + // Anweisungen ... +} + +///////////////////// +// Weiteres: +///////////////////// + +// Einige Aspekte von C++ sind für Neueinsteiger häufig überraschend (aber auch für +// C++ Veteranen). +// Der nachfolgende Abschnitt ist leider nicht vollständig: +// C++ ist eine der Sprachen, bei der es ein leichtes ist sich selbst ins Bein zu schießen. + +// Private-Methoden können überschrieben werden +class Foo +{ + virtual void bar(); +}; + +class FooSub : public Foo +{ + virtual void bar(); // Überschreibt Foo::bar! +}; + +// 0 == false == NULL +bool* pt = new bool; +*pt = 0; // Setzt den Wert des Pointers 'pt' auf false. +pt = 0; // Setzt 'pt' auf den "null-pointer". Keine Compiler-Warnung. + +// nullptr sollte dieses Problem nicht lösen: +int* pt2 = new int; +*pt2 = nullptr; // Kompiliert nicht. +pt2 = nullptr; // Setzt pt2 auf null. + +// Eine Ausnahme bilden bool´s. +// Dies erlaubt es "null-pointer" zu testen: if(!ptr) +// Die Konsequenz ist jedoch, dass dem nullptr ein bool zugewiesen werden kann. +*pt = nullptr; // Kompiliert auch, wenn '*pt' ein bool ist! + +// '=' != '=' != '='! +// Ruft Foo::Foo(const Foo&) auf, oder den Kopierkonstruktor +Foo f2; +Foo f1 = f2; + +// Ruft Foo::Foo(const Foo&) auf, aber kopiert lediglich den "Foo" Teil von +// "fooSub". Alle zusätzlichen Member werden verworfen. Diese eigenartige Verhalten +// wird auch "object slicing" genannt. +FooSub fooSub; +Foo f1 = fooSub; + +// Ruft Foo::operator=(Foo&) oder eine andere Variante auf. +Foo f1; +f1 = f2; + +/////////////////////////////////////// +// Tuple (C++11 und höher) +/////////////////////////////////////// + +#include<tuple> + +// Konzeptionell sind Tuple´s alten Datenstrukturen sehr ähnlich, allerdings haben diese keine +// bezeichneten Daten-Member, sondern werden durch die Reihenfolge angesprochen. + +// Erstellen des Tuples und das Einfügen eines Werts. +auto first = make_tuple(10, 'A'); +const int maxN = 1e9; +const int maxL = 15; +auto second = make_tuple(maxN, maxL); + +// Ausgabe der Elemente des "first" Tuple. +cout << get<0>(first) << " " << get<1>(first) << "\n"; // Ausgabe : 10 A + +// Ausgabe der Elemente des "second" Tuple. +cout << get<0>(second) << " " << get<1>(second) << "\n"; // Ausgabe: 1000000000 15 + +int first_int; +char first_char; +tie(first_int, first_char) = first; +cout << first_int << " " << first_char << "\n"; // Ausgabe : 10 A + +// Tuple können auch wie folgt erzeugt werden: + +tuple<int, char, double> third(11, 'A', 3.14141); +// tuple_size gibt die Anzahl der Elemente in einem Tuple zurück. +// Als "constexpr". + +cout << tuple_size<decltype(third)>::value << "\n"; // prints: 3 + +// tuple_cat fügt die Elemente eines Tuples aneinander (in der selben Reihenfolge). + +auto concatenated_tuple = tuple_cat(first, second, third); +// concatenated_tuple wird zu = (10, 'A', 1e9, 15, 11, 'A', 3.14141) + +cout << get<0>(concatenated_tuple) << "\n"; // Ausgabe: 10 +cout << get<3>(concatenated_tuple) << "\n"; // Ausgabe: 15 +cout << get<5>(concatenated_tuple) << "\n"; // Ausgabe: 'A' + + +/////////////////////////////////// +// Logische- und Bitoperatoren +////////////////////////////////// + +// Die meisten Operatoren in C++ entsprechen denen aus anderen Sprachen + +// Logische Operatoren. +// C++ verwendet so genannte "Short-circuit" Evaluierung für Boolean-Ausdrücke. +// Das zweite Argument wird ausgeführt bzw. evaluiert, wenn das erste Argument genügt, +// um den Ausdruck zu bestimmen. + +true && false // Führt **logisches und** aus. +true || false // Führt **logisches oder** aus. +! true // Führt **logisches nicht** aus. + +// Anstelle von Symbolen können auch Schlüsselwörter verwendet werden. +true and false // Führt **logisches und** aus. +true or false // Führt **logisches oder** aus. +not true // Führt **logisches nicht** aus. + +// Bitoperationen + +// **<<** Links-Shift +// **>>** Rechts-Shift + +~4 // Führt bitweises nicht aus. +4 | 3 // Führt bitweises oder aus. +4 & 3 // Führt bitweises und aus. +4 ^ 3 // Führt bitweises xor aus. + +// Gleichwertige Schlüsselwörter: +compl 4 // Führt bitweises nicht aus. +4 bitor 3 // Führt bitweises oder aus. +4 bitand 3 // Führt bitweises und aus. +4 xor 3 // Führt bitweises xor aus. + + +``` +Weiterführende Literatur: + +* Aktuelle Sprachen-Referenz [CPP Reference](http://cppreference.com/w/cpp). +* Zusätzliches: [CPlusPlus](http://cplusplus.com). +* Grundlagen Tutorial: [TheChernoProject - C++](https://www.youtube.com/playlist?list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb). diff --git a/de-de/python-de.html.markdown b/de-de/python-de.html.markdown index d3e0fc26..ee77683e 100644 --- a/de-de/python-de.html.markdown +++ b/de-de/python-de.html.markdown @@ -386,25 +386,73 @@ filter(lambda x: x > 5, [3, 4, 5, 6, 7]) #=> [6, 7] [add_10(i) for i in [1, 2, 3]] #=> [11, 12, 13] [x for x in [3, 4, 5, 6, 7] if x > 5] #=> [6, 7] + +#################################################### +## 5. Module +#################################################### + +# Wir können Module importieren +import math +print math.sqrt(16) #=> 4.0 + +# Wir können auch nur spezielle Funktionen eines Moduls importieren +from math import ceil, floor +print ceil(3.7) #=> 4.0 +print floor(3.7) #=> 3.0 + +# Wir können auch alle Funktionen eines Moduls importieren +# Warnung: Dies wird nicht empfohlen +from math import * + +# Wir können Modulnamen abkürzen +import math as m +math.sqrt(16) == m.sqrt(16) #=> True + +# Module sind in Python nur gewöhnliche Dateien. Wir +# können unsere eigenen schreiben und importieren. Der Name des +# Moduls ist der Dateiname. + +# Wir können herausfinden, welche Funktionen und Attribute in einem +# Modul definiert sind. +import math +dir(math) + +# Wenn Sie ein Python-Skript namens math.py im selben Ordner +# wie Ihr aktuelles Skript haben, wird die Datei math.py +# anstelle des integrierten Python-Moduls geladen. +# Dies geschieht, weil der lokale Ordner Vorrang +# vor den in Python integrierten Bibliotheken hat. + + #################################################### -## 5. Klassen +## 6. Klassen #################################################### -# Wir bilden die Unterklasse eines Objekts, um Klassen zu erhalten. +# Wir verwenden das Schlüsselwort "class" um eine Klasse zu erzeugen. class Human(object): # Ein Klassenattribut. Es wird von allen Instanzen einer Klasse geteilt species = "H. sapiens" - # Ein simpler Konstruktor + # Ein simpler Konstruktor, wird aufgerufen, wenn diese Klasse instanziiert wird. + # Beachten Sie, dass die doppelten vorangestellten und nachgestellten + # Unterstriche Objekte oder Attribute bezeichnen, die von Python verwendet werden, + # aber in benutzergesteuerten Namespaces leben. + # Methoden (oder Objekte oder Attribute) wie: __init__, __str__, __repr__ usw. + # werden als Sondermethoden (oder manchmal als Dundermethoden bezeichnet) bezeichnet. + # Sie sollten solche Namen nicht selbst erfinden. def __init__(self, name): # Wir weisen das Argument name dem name-Attribut der Instanz zu self.name = name - # Eine Instanzmethode. Alle Methoden erhalten self als erstes Argument. + # Eine Instanzmethode. Alle Methoden erhalten "self" als erstes Argument. def say(self, msg): return "%s: %s" % (self.name, msg) + # Eine weitere Instanzmethode + def sing(self): + return 'yo... yo... microphone check... one two... one two...' + # Eine Klassenmethode wird von allen Instanzen geteilt. # Sie werden mit der aufrufenden Klasse als erstem Argument aufgerufen @classmethod @@ -416,56 +464,287 @@ class Human(object): def grunt(): return "*grunt*" + # Eine Eigenschaft (Property) ist wie ein Getter. + # Es verwandelt die Methode age() in ein schreibgeschütztes Attribut mit demselben Namen. + # Es ist jedoch nicht nötig, triviale Getter und Setter in Python zu schreiben. + @property + def age(self): + return self._age + + # Damit kann die Eigenschaft festgelegt werden + @age.setter + def age(self, age): + self._age = age + + # Damit kann die Eigenschaft gelöscht werden + @age.deleter + def age(self): + del self._age + +# Wenn ein Python-Interpreter eine Quelldatei liest, führt er den gesamten Code aus. +# Diese __name__-Prüfung stellt sicher, dass dieser Codeblock nur ausgeführt wird, +# wenn dieses Modul das Hauptprogramm ist. +if __name__ == '__main__': + # Eine Instanz einer Klasse erstellen + i = Human(name="Ian") + i.say("hi") # "Ian: hi" + j = Human("Joel") + j.say("hello") # "Joel: hello" + # i und j sind Instanzen des Typs Mensch, oder anders ausgedrückt: Sie sind Objekte des Menschen + + # Rufen wir unsere Klassenmethode auf + i.say(i.get_species()) # "Ian: H. sapiens" + + # Ändern wir das gemeinsame Attribut + Human.species = "H. neanderthalensis" + i.say(i.get_species()) # => "Ian: H. neanderthalensis" + j.say(j.get_species()) # => "Joel: H. neanderthalensis" + + # Aufruf der statischen Methode + print(Human.grunt()) # => "*grunt*" + + # Kann keine statische Methode mit Instanz des Objekts aufrufen, + # da i.grunt () automatisch "self" (das Objekt i) als Argument verwendet + print(i.grunt()) # => TypeError: grunt() takes 0 positional arguments but 1 was given + + # Die Eigenschaft für diese Instanz aktualisieren + i.age = 42 + # die Eigenschaft auslesen + i.say(i.age) # => "Ian: 42" + j.say(j.age) # => "Joel: 0" + # die Eigenschaft löschen + del i.age + # i.age # => würde einen AttributeError werfen + +#################################################### +## 6.1 Inheritance +#################################################### + +# Vererbung ermöglicht die Definition neuer untergeordneter Klassen, +# die Methoden und Variablen von ihrer übergeordneten Klasse erben. + +# Wenn Sie die oben definierte Human-Klasse als Basis- oder Elternklasse verwenden, +# können Sie eine untergeordnete Klasse, Superhero, definieren, die die Klassenvariablen +# wie "species", "name" und "age" sowie Methoden wie "sing" und "grunzen" aus der Klasse Human erbt. +# Die Untergeordnete Klasse kann aber auch eigene Eigenschaften haben. + +# Um von der Modularisierung per Datei zu profitieren, können Sie die Klassen +# in ihren eigenen Dateien platzieren, z. B. human.py + +# Um Funktionen aus anderen Dateien zu importieren, verwenden Sie das folgende Format +# from "Dateiname-ohne-Erweiterung" impotr "Funktion-oder-Klasse" + +from human import Human + +# Geben Sie die übergeordnete(n) Klasse(n) als Parameter für die Klassendefinition an +class Superhero(Human): + + # Wenn die untergeordnete Klasse alle Definitionen des übergeordneten Elements + # ohne Änderungen erben soll, können Sie einfach das Schlüsselwort "pass" + # (und nichts anderes) verwenden. In diesem Fall wird jedoch auskommentiert, + # um eine eindeutige untergeordnete Klasse zuzulassen: + # pass + + # Kindklassen können die Attribute ihrer Eltern überschreiben + species = 'Superhuman' + + # Kinder erben automatisch den Konstruktor ihrer übergeordneten Klasse + # einschließlich ihrer Argumente, können aber auch zusätzliche Argumente oder + # Definitionen definieren und ihre Methoden zB den Klassenkonstruktor überschreiben. + # Dieser Konstruktor erbt das Argument "name" von der Klasse "Human" und + # fügt die Argumente "superpowers" und "movie" hinzu: + def __init__(self, name, movie=False, + superpowers=["super strength", "bulletproofing"]): + + # zusätzliche Klassenattribute hinzufügen: + self.fictional = True + self.movie = movie + # Beachten Sie die veränderlichen Standardwerte, da die Standardwerte gemeinsam genutzt werden + self.superpowers = superpowers + + # Mit der Funktion "super" können Sie auf die Methoden der übergeordneten Klasse + # zugreifen, die vom untergeordneten Objekt überschrieben werden, + # in diesem Fall die Methode __init__. + # Dies ruft den Konstruktor der übergeordneten Klasse auf: + super().__init__(name) + + # überschreiben der "sing" Methode + def sing(self): + return 'Dun, dun, DUN!' + + # eine zusätzliche Instanzmethode hinzufügen + def boast(self): + for power in self.superpowers: + print("I wield the power of {pow}!".format(pow=power)) + +if __name__ == '__main__': + sup = Superhero(name="Tick") + + # Instanztypprüfungen + if isinstance(sup, Human): + print('I am human') + if type(sup) is Superhero: + print('I am a superhero') + + # Die Reihenfolge der Methodenauflösung (MRO = Method Resolution Order) anzeigen, die sowohl von getattr() als auch von super() verwendet wird. + # Dieses Attribut ist dynamisch und kann aktualisiert werden. + print(Superhero.__mro__) # => (<class '__main__.Superhero'>, + # => <class 'human.Human'>, <class 'object'>) + + # Ruft die übergeordnete Methode auf, verwendet jedoch das eigene Klassenattribut + print(sup.get_species()) # => Superhuman + + # Ruft die überschriebene Methode auf + print(sup.sing()) # => Dun, dun, DUN! + + # Ruft die Methode von Human auf + sup.say('Spoon') # => Tick: Spoon + + # Aufruf einer Methode, die nur in Superhero existiert + sup.boast() # => I wield the power of super strength! + # => I wield the power of bulletproofing! + + # Vererbtes Klassenattribut + sup.age = 31 + print(sup.age) # => 31 + + # Attribut, das nur in Superhero existiert + print('Am I Oscar eligible? ' + str(sup.movie)) + +#################################################### +## 6.2 Multiple Inheritance +#################################################### -# Eine Instanz einer Klasse erstellen -i = Human(name="Ian") -print i.say("hi") # gibt "Ian: hi" aus +# Eine weitere Klassendefinition +# bat.py -j = Human("Joel") -print j.say("hello") #gibt "Joel: hello" aus +class Bat: -# Rufen wir mal unsere Klassenmethode auf -i.get_species() #=> "H. sapiens" + species = 'Baty' -# Ändern wir mal das gemeinsame Attribut -Human.species = "H. neanderthalensis" -i.get_species() #=> "H. neanderthalensis" -j.get_species() #=> "H. neanderthalensis" + def __init__(self, can_fly=True): + self.fly = can_fly -# Aufruf der statischen Methode -Human.grunt() #=> "*grunt*" + # This class also has a say method + def say(self, msg): + msg = '... ... ...' + return msg + # And its own method as well + def sonar(self): + return '))) ... (((' +if __name__ == '__main__': + b = Bat() + print(b.say('hello')) + print(b.fly) + +# Und noch eine andere Klassendefinition, die von Superhero und Bat erbt +# superhero.py +from superhero import Superhero +from bat import Bat + +# Definieren Sie Batman als eine Kindklasse, das von Superheld und Bat erbt +class Batman(Superhero, Bat): + + def __init__(self, *args, **kwargs): + # In der Regel müssen Sie super aufrufen, um Attribute zu erben: + # super (Batman, selbst) .__ init__ (* args, ** kwargs) + # Allerdings handelt es sich hier um Mehrfachvererbung, und super() + # funktioniert nur mit der nächsten Basisklasse in der MRO-Liste. + # Stattdessen rufen wir explizit __init__ für alle Vorfahren auf. + # Die Verwendung von *args und **kwargs ermöglicht die saubere Übergabe von + # Argumenten, wobei jedes übergeordnete Element eine Schicht der Zwiebel "abschält". + Superhero.__init__(self, 'anonymous', movie=True, + superpowers=['Wealthy'], *args, **kwargs) + Bat.__init__(self, *args, can_fly=False, **kwargs) + # überschreibt den Wert für das Namensattribut + self.name = 'Sad Affleck' + + def sing(self): + return 'nan nan nan nan nan batman!' + +if __name__ == '__main__': + sup = Batman() + + # Die Reihenfolge der Methodenauflösung (MRO = Method Resolution Order) anzeigen, + # die sowohl von getattr() als auch von super() verwendet wird. + # Dieses Attribut ist dynamisch und kann aktualisiert werden. + print(Batman.__mro__) # => (<class '__main__.Batman'>, + # => <class 'superhero.Superhero'>, + # => <class 'human.Human'>, + # => <class 'bat.Bat'>, <class 'object'>) + + # Ruft die übergeordnete Methode auf, verwendet jedoch das eigene Klassenattribut + print(sup.get_species()) # => Superhuman + + # Ruft die überschriebene Methode auf + print(sup.sing()) # => nan nan nan nan nan batman! + + # Ruft die Methode von Human auf, weil die Reihenfolge der Vererbung wichtig ist + sup.say('I agree') # => Sad Affleck: I agree + + # Aufrufmethode, die nur im 2. Vorfahren existiert + print(sup.sonar()) # => ))) ... ((( + + # Vererbtes Klassenattribut + sup.age = 100 + print(sup.age) # => 100 + + # Vererbtes Attribut vom 2. Vorfahren, dessen Standardwert überschrieben wurde. + print('Can I fly? ' + str(sup.fly)) # => Can I fly? False + + #################################################### -## 6. Module -#################################################### - -# Wir können Module importieren -import math -print math.sqrt(16) #=> 4.0 +## 7. Fortgeschrittenes +#################################################### + +# Generatoren helfen Ihnen, lazy Code zu erstellen. +def double_numbers(iterable): + for i in iterable: + yield i + i + +# Generatoren sind speichereffizient, da sie nur die Daten laden, +# die zur Verarbeitung des nächsten Werts in der iterierbaren Komponente +# erforderlich sind. Dadurch können sie ansonsten unzulässig große Wertebereiche ausführen. +# HINWEIS: `range` ersetzt` xrange` in Python 3. +for i in double_numbers(range(1, 900000000)): # `range` ist ein Generator. + print(i) + if i >= 30: + break + +# Genauso wie Sie ein 'list comprehension' (Listen Abstraktion) erstellen können, können Sie auch 'generator comprehension' (Generator Abstraktion) erstellen. +values = (-x for x in [1,2,3,4,5]) +for x in values: + print(x) # prints -1 -2 -3 -4 -5 to console/terminal + +# Sie können eine Generator Abstraktion auch direkt in eine Liste umwandeln (casten). +values = (-x for x in [1,2,3,4,5]) +gen_to_list = list(values) +print(gen_to_list) # => [-1, -2, -3, -4, -5] -# Wir können auch nur spezielle Funktionen eines Moduls importieren -from math import ceil, floor -print ceil(3.7) #=> 4.0 -print floor(3.7) #=> 3.0 +# Decorators +# In diesem Beispiel umschliesst "beg" "say". Wenn say_please True ist, wird die zurückgegebene Nachricht geändert. +from functools import wraps -# Wir können auch alle Funktionen eines Moduls importieren -# Warnung: Dies wird nicht empfohlen -from math import * +def beg(target_function): + @wraps(target_function) + def wrapper(*args, **kwargs): + msg, say_please = target_function(*args, **kwargs) + if say_please: + return "{} {}".format(msg, "Please! I am poor :(") + return msg -# Wir können Modulnamen abkürzen -import math as m -math.sqrt(16) == m.sqrt(16) #=> True + return wrapper -# Module sind in Python nur gewöhnliche Dateien. Wir -# können unsere eigenen schreiben und importieren. Der Name des -# Moduls ist der Dateiname. +@beg +def say(say_please=False): + msg = "Can you buy me a beer?" + return msg, say_please -# Wir können auch die Funktionen und Attribute eines -# Moduls herausfinden. -import math -dir(math) +print(say()) # Can you buy me a beer? +print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :( ``` diff --git a/dhall.html.markdown b/dhall.html.markdown new file mode 100644 index 00000000..21126c8a --- /dev/null +++ b/dhall.html.markdown @@ -0,0 +1,362 @@ +--- +language: Dhall +filename: learndhall.dhall +contributors: + - ["Gabriel Gonzalez", "http://www.haskellforall.com/"] +--- + +Dhall is a programmable configuration language that provides a non-repetitive +alternative to YAML. + +You can think of Dhall as: JSON + functions + types + imports + +Note that while Dhall is programmable, Dhall is not Turing-complete. Many +of Dhall's features take advantage of this restriction to provider stronger +safety guarantees and more powerful tooling. + +```haskell +-- Single-line comment + +{- Multi-line comment + + Unicode is fine 🙂 + + This file is a valid Dhall expression that evaluates to a large record + collecting the results of each step. + + You can view the results by interpreting the file: + + $ dhall --file learndhall.dhall + + {- Comments can be nested -} +-} + +let greeting = "Hello, world!" + +let fruits = "🍋🍓🍍🍉🍌" + +let interpolation = "Enjoy some delicious fruit: ${fruits}" + +let multilineText {- Inline comments work, too -} = + '' + Leading whitespace is stripped from multi-line text literals. + + That means you can freely indent or dedent a text literal without + changing the result. + + Relative indentation within the literal is still preserved. + + Other than that, the text literal is preserved verbatim, similar to a + "literal" YAML multiline string. + '' + +let bool = True + +-- Type annotations on bindings are optional, but helpful, so we'll use them +let annotation : Bool = True + +let renderedBool : Text = if bool then "True" else "False" + +-- Natural numbers are non-negative and are unsigned +let naturalNumber : Natural = 42 + +-- Integers may be negative, but require an explicit sign, even if positive +let positiveInteger : Integer = +1 + +let negativeInteger : Integer = -12 + +let pi : Double = 3.14159265359 + +{- You can use a wider character range for identifiers (such as quotation + marks and whitespace) if you quote them using backticks +-} +let `Avogadro's Number` : Double = 6.0221409e+23 + +let origin : { x : Double, y : Double } = { x = 0.0, y = 0.0 } + +let somePrimes : List Natural = [ 2, 3, 5, 7, 11 ] + +{- A schema is the same thing as a type + + Types begin with an uppercase letter by convention, but this convention is + not enforced +-} +let Profile : Type + = { person : + { name : Text + , age : Natural + } + , address : + { country : Text + , state : Text + , city : Text + } + } + +let john : Profile = + { person = + { name = "John Doe" + , age = 67 + } + , address = + { country = "United States" + , state = "Pennsylvania" + , city = "Philadelphia" + } + } + +let philadelphia : Text = john.address.city + +{- Enum alternatives also begin with an uppercase letter by convention. This + convention is not enforced +-} +let DNA : Type = < Adenine | Cytosine | Guanine | Thymine > + +let dnaSequence : List DNA = [ DNA.Thymine, DNA.Guanine, DNA.Guanine ] + +let compactDNASequence : List DNA = + let a = DNA.Adenine + let c = DNA.Cytosine + let g = DNA.Guanine + let t = DNA.Thymine + in [ c, t, t, a, t, c, g, g, c ] + +-- You can transform enums by providing a record with one field per alternative +let theLetterG : Text = + merge + { Adenine = "A" + , Cytosine = "C" + , Guanine = "G" + , Thymine = "T" + } + DNA.Guanine + +let presentOptionalValue : Optional Natural = Some 1 + +let absentOptionalValue : Optional Natural = None Natural + +let points : List { x : Double, y : Double } = + [ { x = 1.1, y = -4.2 } + , { x = 4.4, y = -3.0 } + , { x = 8.2, y = -5.5 } + ] + +{- `Natural -> List Natural` is the type of a function whose input type is a + `Natural` and whose output type is a `List Natural` + + All functions in Dhall are anonymous functions (a.k.a. "lambdas"), + which you can optionally give a name + + For example, the following function is equivalent to this Python code: + + lambda n : [ n, n + 1 ] + + ... and this JavaScript code: + + function (n) { return [ n, n + 1 ]; } +-} +let exampleFunction : Natural -> List Natural = + \(n : Natural) -> [ n, n + 1 ] + +-- Dhall also supports Unicode syntax, but this tutorial will stick to ASCII +let unicodeFunction : Natural → List Natural = + λ(n : Natural) → [ n, n + 1 ] + +-- You don't need to parenthesize function arguments +let exampleFunctionApplication : List Natural = + exampleFunction 2 + +let functionOfMultipleArguments : Natural -> Natural -> List Natural = + \(x : Natural) -> \(y : Natural) -> [ x, y ] + +let functionAppliedToMultipleArguments : List Natural = + functionOfMultipleArguments 2 3 + +{- Same as `exampleFunction` except we gave the function's input type a + name: "n" +-} +let namedArgumentType : forall (n : Natural) -> List Natural = + \(n : Natural) -> [ n, n + 1 ] + +{- If you name a function's input type, you can use that name later within the + same type + + This lets you write a function that works for more than one type of input + (a.k.a. a "polymorphic" function) +-} +let duplicate : forall (a : Type) -> a -> List a = + \(a : Type) -> \(x : a) -> [ x, x ] + +let duplicatedNumber : List Natural = + duplicate Natural 2 + +let duplicatedBool : List Bool = + duplicate Bool False + +{- The language also has some built-in polymorphic functions, such as: + + List/head : forall (a : Type) -> List a -> Optional a +-} +let firstPrime : Optional Natural = List/head Natural somePrimes + +let functionOfARecord : { x : Natural, y : Natural } -> List Natural = + \(args : { x : Natural, y : Natural }) -> [ args.x, args.y ] + +let functionAppliedToARecord : List Natural = + functionOfARecord { x = 2, y = 5 } + +{- All type conversions are explicit + + `Natural/show` is a built-in function of the following type: + + Natural/show : Natural -> Text + + ... that converts `Natural` numbers to their `Text` representation +-} +let typeConversion : Natural -> Text = + \(age : Natural) -> "I am ${Natural/show age} years old!" + +-- A template is the same thing as a function whose output type is `Text` +let mitLicense : { year : Natural, copyrightHolder : Text } -> Text = + \(args : { year : Natural, copyrightHolder : Text }) -> +'' +Copyright ${Natural/show args.year} ${args.copyrightHolder} + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +'' + +-- Template instantiation is the same thing as function application +let templatedLicense : Text = + mitLicense { year = 2019, copyrightHolder = "Jane Smith" } + +{- You can import expressions by URL + + Also, like Bash, you can import code from your local filesystem (not shown) + + Security-conscious users can pin remotely-imported expressions by adding a + semantic integrity check. The interpreter rejects any attempt to tamper with + an expression pinned in this way. However, behavior-preserving refactors + of imported content will not perturb the hash. + + Imported expressions pinned in this way are also locally cached in a + content-addressable store (typically underneath `~/.cache/dhall`) +-} +let Natural/sum : List Natural -> Natural = + https://prelude.dhall-lang.org/Natural/sum + sha256:33f7f4c3aff62e5ecf4848f964363133452d420dcde045784518fb59fa970037 + +let twentyEight : Natural = Natural/sum somePrimes + +-- A package is the same thing as a (possibly nested) record that you can import +let Prelude = https://prelude.dhall-lang.org/package.dhall + +let false : Bool = Prelude.Bool.not True + +-- You can import the raw contents of a file by adding `as Text` to an import +let sourceCode : Text = https://prelude.dhall-lang.org/Bool/not as Text + +-- You can import environment variables, too: +let presentWorkingDirectory = env:PWD as Text + +-- You can provide a fallback expression if an import fails +let home : Optional Text = Some env:HOME ? None Text + +-- Fallback expressions can contain alternative imports of their own +let possiblyCustomPrelude = + env:DHALL_PRELUDE + ? https://prelude.dhall-lang.org/package.dhall + +{- Tie everything together by auto-generating configurations for 10 build users + using the `generate` function: + + Prelude.List.generate + : Natural -> forall (a : Type) -> (Natural -> a) -> List a +-} +let buildUsers = + let makeUser = \(user : Text) -> + let home = "/home/${user}" + let privateKey = "${home}/.ssh/id_ed25519" + let publicKey = "${privateKey}.pub" + in { home = home + , privateKey = privateKey + , publicKey = publicKey + } + + let buildUser = + \(index : Natural) -> makeUser "build${Natural/show index}" + + let Config = + { home : Text + , privateKey : Text + , publicKey : Text + } + + in Prelude.List.generate 10 Config buildUser + +-- Present all of the results in a final record +in { greeting = greeting + , fruits = fruits + , interpolation = interpolation + , multilineText = multilineText + , bool = bool + , annotation = annotation + , renderedBool = renderedBool + , naturalNumber = naturalNumber + , positiveInteger = positiveInteger + , negativeInteger = negativeInteger + , pi = pi + , `Avogadro's Number` = `Avogadro's Number` + , origin = origin + , somePrimes = somePrimes + , john = john + , philadelphia = philadelphia + , dnaSequence = dnaSequence + , compactDNASequence = compactDNASequence + , theLetterG = theLetterG + , presentOptionalValue = presentOptionalValue + , absentOptionalValue = absentOptionalValue + , points = points + , exampleFunction = exampleFunction + , unicodeFunction = unicodeFunction + , exampleFunctionApplication = exampleFunctionApplication + , functionOfMultipleArguments = functionOfMultipleArguments + , functionAppliedToMultipleArguments = functionAppliedToMultipleArguments + , namedArgumentType = namedArgumentType + , duplicate = duplicate + , duplicatedNumber = duplicatedNumber + , duplicatedBool = duplicatedBool + , firstPrime = firstPrime + , functionOfARecord = functionOfARecord + , functionAppliedToARecord = functionAppliedToARecord + , typeConversion = typeConversion + , mitLicense = mitLicense + , templatedLicense = templatedLicense + , twentyEight = twentyEight + , false = false + , sourceCode = sourceCode + , presentWorkingDirectory = presentWorkingDirectory + , home = home + , buildUsers = buildUsers + } +``` + +To learn more, visit the official website, which also lets you try the +language live in your browser: + +* [https://dhall-lang.org](http://dhall-lang.org/) diff --git a/el-gr/html-gr.html.markdown b/el-gr/html-gr.html.markdown new file mode 100644 index 00000000..0ca6e326 --- /dev/null +++ b/el-gr/html-gr.html.markdown @@ -0,0 +1,193 @@ +--- +language: html +filename: learnhtml-gr.html +contributors: + - ["Dimitri Kokkonis", "https://github.com/kokkonisd"] +lang: el-gr +--- + +Το ακρώνυμο HTML σημαίνει HyperText Markup Language. + +Είναι μια γλώσσα που μας επιτρέπει να δημιουργήσουμε σελίδες για το διαδίκτυο. +Είναι μια γλώσσα σήμανσης (markup), και μας επιτρέπει να γράψουμε ιστοσελίδες +χρησιμοποιώντας κώδικα για να υποδείξουμε πώς πρέπει να εμφανίζεται το κείμενο +και τα δεδομένα στη σελίδα. Στην πραγματικότητα, τα αρχεία HTML είναι απλά +αρχεία κειμένου. + +Τι σημαίνει όμως «γλώσσα σήμανσης»; Είναι μια μέθοδος οργάνωσης των δεδομένων +της σελίδας, που λειτουργεί μέσω ετικετών (tags) που «ανοίγουν» ή «κλείνουν». +Αυτή η σήμανση έχει ως σκοπό να δώσει κάποια συγκεκριμένη σημασία στο κείμενο +που περιβάλλει. Όπως και οι περισσότερες γλώσσες υπολογιστών, η HTML έχει +πολλές διαφορετικές εκδοχές. Εδώ θα μιλήσουμε για την HTML5. + +**ΣΗΜΕΙΩΣΗ :** Μπορείτε να δοκιμάσετε τις ετικέτες και τα στοιχεία που +παρουσιάζονται εδώ σε ένα σάιτ όπως το [codepen](http://codepen.io/pen/), ούτως +ώστε να δείτε τα αποτελέσματα που παράγουν, να καταλάβετε πώς δουλεύουν και να +εξοικιωθείτε με την γλώσσα. Αυτό το άρθρο ασχολείται κυρίως με την σύνταξη της +HTML και κάποιες χρήσιμες συμβουλές σχετικά με αυτήν. + + +```html +<!-- Τα σχόλια είναι περικυκλωμένα όπως αυτή η γραμμή! --> + +<!-- + Τα + σχόλια + μπορούν + να + επεκταθούν + σε + πολλαπλές + γραμμές! +--> + +<!-- #################### Οι ετικέτες #################### --> + +<!--Ορίστε ένα παράδειγμα αρχείου HTML, το οποίο θα αναλύσουμε. --> + + +<!doctype html> + <html> + <head> + <title>Η σελίδα μου</title> + </head> + <body> + <h1>Καλημέρα, κόσμε!</h1> + <a href="http://codepen.io/anon/pen/xwjLbZ"> + Δείτε τι κάνει αυτό + </a> + <p>Αυτή είναι μια παράγραφος.</p> + <p>Αυτή είναι μια άλλη παράγραφος.</p> + <ul> + <li>Αυτό είναι ένα αντικείμενο μέσα σε μια μη-αριθμημένη λίστα + (bullet list)</li> + <li>Αυτό είναι ένα άλλο αντικείμενο</li> + <li>Και αυτό είναι το τελευταίο αντικείμενο της λίστας</li> + </ul> + </body> + </html> + +<!-- + Ένα αρχείο HTML πάντα ξεκινά υποδεικνύοντας στον περιηγητή πως η σελίδα + είναι γραμμένη με HTML. +--> +<!doctype html> + +<!-- Μετά από αυτό, ξεκινά ανοίγοντας μια ετικέτα <html>. --> +<html> + +<!-- την οποία πρέπει να κλείσουμε στο τέλος της σελίδας γράφοντας </html>. --> +</html> + +<!-- Τίποτα δεν πρέπει να βρίσκεται μετά από αυτη την τελευταία ετικέτα. --> + + +<!-- Ανάμεσα από τις ετικέτες <html> και </html>, βρίσκουμε: --> + +<!-- Μια επικεφαλίδα ορισμένη από την ετικέτα <head> (πρέπει να την κλείσουμε +με την ετικέτα </head>) --> +<!-- + Η επικεφαλίδα περιέχει κάποια περιγραφή και επιπρόσθετες πληροφορίες που δεν + εμφανίζονται· είναι τα λεγόμενα μεταδεδομένα (metadata). +--> + +<head> + <!-- + Η ετικέτα <title> υποδεικνύει στον περιηγητή τον τίτλο που πρέπει να + εμφανιστεί στην μπάρα τίτλου και στο όνομα της καρτέλας. + --> + <title>Η σελίδα μου</title> +</head> + +<!-- Μετά την ενότητα <head>, βρίσκουμε την ετικέτα <body> --> +<!-- Μέχρι αυτό το σημείο, τίποτα απ' όσα έχουμε περιγράψει δεν θα εμφανιστούν +στο παράθυρο του περιηγητή. --> +<!-- Πρέπει να συμπληρώσουμε το «σώμα» της σελίδας με το περιεχόμενο που +θέλουμε να εμφανίζεται. --> + +<body> + <!-- Η ετικέτα h1 δημιουργεί έναν τίτλο/επικεφαλίδα. --> + <h1>Καλημέρα, κόσμε!</h1> + <!-- + Υπάρχουν επίσης υπότιτλοι/υποκεφαλίδες, από την πιο σημαντική (h2) + μέχρι την πιο μικρή και ειδική (h6). + --> + + <!-- Ένας υπερσύνδεσμος προς την διεύθυνση που δίνεται από την παράμετρο + href="": --> + <a href="http://codepen.io/anon/pen/xwjLbZ"> + Δείτε τι κάνει αυτό + </a> + + <!-- Η ετικέτα <p> μας επιτρέπει να εισάγουμε κείμενο στην σελίδα μας. --> + <p>Αυτή είναι μια παράγραφος.</p> + <p>Αυτή είναι μια άλλη παράγραφος.</p> + + <!-- Η ετικέτα <ul> δημιουργεί μια μη-αριθμημένη λίστα. --> + <!-- + Για μια αριθμημένη λίστα χρησιμοποιούμε την ετικέτα <ol>, που θα μας + δώσει 1. για το πρώτο στοιχείο, 2. για το δεύτερο κτλ. + --> + <ul> + <li>Αυτό είναι ένα αντικείμενο μέσα σε μια μη-αριθμημένη λίστα (bullet + list)</li> + <li>Αυτό είναι ένα άλλο αντικείμενο</li> + <li>Και αυτό είναι το τελευταίο αντικείμενο της λίστας</li> + </ul> +</body> + +<!-- Αυτό ήταν όλο, είναι εύκολο να δημιουργήσουμε αρχεία HTML. --> + +<!-- Ωστόσο έχουμε την δυνατότητα να επιλέξουμε ανάμεσα σε πολλές ακόμη +ετικέτες HTML. --> + +<!-- Η ετικέτα <img /> χρησιμοποιείται για να εισάγουμε μια εικόνα. --> +<!-- + Η πηγή της εικόνας υποδεικνύεται μέσω της παραμέτρου src="". + Η πηγή μπορεί να είναι μια διεύθυνση (URL) ή ακόμα και μια τοπική διεύθυνση + ενός αρχείου που βρίσκεται στον υπολογιστή μας. +--> +<img src="http://i.imgur.com/XWG0O.gif"/> + +<!-- Υπάρχει επίσης η δυνατότητα να δημιουργήσουμε πίνακες. --> + +<!-- Ανοίγουμε μια ετικέτα <table>. --> +<table> + + <!-- Η ετικέτα <tr> μας επιτρέπει να δημιουργήσουμε μια γραμμή + στον πίνακα. --> + <tr> + + <!-- Η ετικέτα <th> μας επιτρέπει να δώσουμε έναν τίτλο σε μια στήλη + του πίνακα --> + <th>Πρώτος τίτλος</th> + <th>Δεύτερος τίτλος</th> + </tr> + + <tr> + + <!-- Η ετικέτα <td> μας επιτρέπει να δημιουργήσουμε ένα κελί μέσα στον + πίνακα. --> + <td>Πρώτη γραμμή, πρώτη στήλη</td> + <td>Πρώτη γραμμή, δεύτερη στήλη</td> + </tr> + + <tr> + <td>Δεύτερη γραμμή, πρώτη στήλη</td> + <td>Δεύτερη γραμμή, δεύτερη στήλη</td> + </tr> +</table> + +``` + +## Χρήση + +Η HTML γράφεται σε αρχεία με την κατάληξη `.html` ή `.htm`. Ο τύπος MIME της +HTML είναι +`text/html`. +**H HTML ΔΕΝ είναι γλώσσα προγραμματισμού.** +## Μάθετε περισσότερα + +* [βικιπαίδεια](https://el.wikipedia.org/wiki/HTML) +* [Μάθημα HTML](https://developer.mozilla.org/en-US/docs/Web/HTML) +* [W3School](http://www.w3schools.com/html/html_intro.asp) diff --git a/emacs.html.markdown b/emacs.html.markdown new file mode 100644 index 00000000..ff4d3c03 --- /dev/null +++ b/emacs.html.markdown @@ -0,0 +1,320 @@ +--- +category: tool +tool: emacs +filename: emacs.txt +contributors: + - ["Joseph Riad", "https://github.com/Joseph-Riad"] +--- + +Emacs started its life as ["the extensible, customizable display +editor"](https://www.gnu.org/software/emacs/emacs-paper.html) and grew +over the years into a full-blown ecosystem. Many tasks, usually +relegated to a diverse set of tools can be accomplished from within +Emacs in a consistent, familiar interface. Examples include directory +management, viewing PDF documents, editing files over SSH, managing git +repos,… (the list is quite long). In short, Emacs is yours to make of it +what you will: the spectrum of users varies from those who use it to +edit text files to extreme purists who use it to virtually replace their +operating system. + +Emacs is extensible via a specialized dialect of Lisp known as Emacs +Lisp (Elisp) which has a lot of macros geared towards editing text and +managing text buffers. Any key (combination) you use in Emacs is bound +to an Emacs Lisp function and may be remapped to any other function, +including ones you write +yourself. + +# Key Notation + +``` text +The Emacs manual and the community in general uses a convention to refer to different key combinations used within Emacs. Specifically, Emacs has the notion of a "modifier key" that is pressed along with another key to modify its action. + +An example of this notation is "C-c". In this key combination "C" is the modifier and stands for the "Ctrl" key and "c" is the key whose action is being modified (the literal character "c"). + +The modifier shorthand: +"C-" --> The "CTRL" key +"M-" --> The "Meta" key (usually, the "Alt" key) +"s-" --> The "Super" key (the "Cmd" key on Macs and the "Windows" key on PCs) + +There are other, less commonly used modifiers that I will not get into here. + +The key combination "C-x C-s" means you press "Ctrl+x" followed by "Ctrl+s" + +In addition to the above modifiers, the special keys "Esc", "Return (Enter)" and "Shift" are denoted by "ESC", "RET" and "S", respectively. +``` + +# Basic Emacs Concepts + +Here, I discuss some basic Emacs concepts and terminology that may be +confusing to newcomers (especially to people used to Vim terminology) + + - A bunch of text that Emacs is editing is known as a **buffer** + - A buffer does not necessarily correspond to an actual file on disk. + It may be just a bunch of text in memory. + - When a buffer corresponds to a file on disk, we say that the buffer + is **visiting** that file. + - Emacs typically has many buffers open at once. + - The display of Emacs may be split into different **windows** (not to + be confused with your operating system's windows: the operating + system window for Emacs can have multiple Emacs windows inside it). + - An operating system window for Emacs is called an Emacs **frame**. + Thus, when the Emacs manual talks about opening a new frame, this + essentially means opening a new OS *window* containing an(other) + instance of Emacs. + - The concepts conventionally known as cutting and pasting are + referred to as **killing** and **yanking**, respectively in Emacs + parlance. + - The current position of the cursor is called the **point** in Emacs. + Technically, **point** is defined as the position right before the + character where the cursor currently is. + - Finally, each buffer may have several **modes** associated with it: + a **major mode** and possibly several **minor modes**. + - The **major mode** defines the main behavior of Emacs in the + currently selected buffer. This can be roughly thought of as the + file type. For example, if you're editing a Python file, the major + mode is (by default) `python-mode` which causes Emacs to highlight + Python syntax and automatically indent and outdent your code blocks + as syntactically required by your Python code. + - **Minor modes** define subtle changes in behavior and several minor + modes may be active at once in the same buffer. An example minor + mode is `flyspell-mode` which automatically highlights spelling + errors in your +buffer. + +# Navigation Basics + +``` text +The GUI version of Emacs can be navigated with the mouse like you would expect from a conventional GUI text editor. + +The aim here is to focus on navigation solely using the keyboard as this enhances productivity immensely. + + +* Line movement + +C-n --> Next line +C-p --> Previous line + +* Character movement + +C-f --> Go forward one character +C-b --> Go backward one character + +* Word movement + +M-f --> Go forward one word +M-b --> Go backward one word + +* Sentence movement + +M-a --> Move to the beginning of the sentence +M-e --> Move to the end of the sentence + +* Beginning and end of line + +C-a --> Move to the beginning of the line +C-e --> Move to the end of the line + +* Beginning and end of buffer + +M-< ("Meta+Shift+,") --> Go to the beginning of the buffer +M-> ("Meta+Shift+.") --> Go to the end of the buffer + +* Screen movement + +C-v --> Scroll down by one screen-full (the last two lines of the previous screen are kept as overlap for a smoother transition) +M-v --> Scroll up by one screen-full (same as above but with the first two lines) + +* Centering the screen + +C-l --> Move current line to the screen's center + +The above key combination actually cycles through different states depending on how many times it's been pressed. + +C-l --> Move current line to the screen's center +C-l C-l --> Move current line to the top of the screen +C-l C-l C-l --> Restore the position of the current line to where it was before the first C-l was pressed + +If you press "C-l" a 4th time, it cycles back to centering the current line. + +* Repeating movement commands + +Most movement commands take a numerical prefix argument that says "repeat the following command that many times". + +Example: + +C-u 3 C-p --> Go up 3 lines +C-u 5 C-f --> Go forward 5 characters + +One notable exception are the screen scrolling commands: + +C-u 3 C-v --> Scroll downward 3 lines (maintaining the position of the cursor) +``` + +Bonus: many of the above navigation commands are the default navigation +commands in Bash (e.g. pressing "C-b" while entering a Bash command +takes you back one +character). + +# File editing basics + +``` text +* Quitting Emacs [ Now you can't say you don't know how to quit Emacs :-) ] + +C-x C-c --> Quit Emacs and get prompted to save any unsaved files (buffers not visiting a file will simply be discarded unless you're running in client-server mode) + +* Saving a buffer + +C-x C-s --> Save the current buffer. If not visiting a file, it will prompt you for a file name to use to save the buffer. + +* Searching within a buffer + +C-s --> Search forwards within the buffer. Search is incremental and case-insensitive by default. + Press C-s to move to the next match. + If you press "RET", point is moved to the currently highlighted word and the search ends. +C-r --> Same as C-s except it searches backward + +C-_ or C-/ --> Undo the last action. Keep pressing it to move up the undo tree. +C-? or M-_ --> Redo the previous change + +The "undo" and "redo" commands can take prefix numerical arguments to undo or redo that many actions: + +C-u 3 C-_ --> Undo the last 3 changes. +``` + +# Executing Elisp Functions + +``` text +You can execute any currently loaded Elisp functions (including ones you have written yourself) via "M-x" + +M-x RET --> Prompts you for name of function to execute (Tab completion is available). + +Example: + +M-x RET search-forward-regexp RET --> Prompts you for a regular expression and searches forward in the buffer for it +``` + +# Emacs Configuration + +Emacs is configured using Elisp. On startup, it looks for a +configuration file either in `~/.emacs` or `~/.emacs.d/init.el` where +`~` refers to your home directory. If you're on Windows, consult [this +article](https://www.gnu.org/software/emacs/manual/html_node/efaq-w32/Location-of-init-file.html) +for the appropriate location of your configuration file. + +# Vim inside Emacs + +If you are considering the transition from Vim to Emacs and you're put +off by the non-modal nature of Emacs editing, there is an Emacs +extension known as `evil-mode` which lets you have many Vim concepts +inside Emacs. Here are some things added to Emacs by `evil-mode`: + + - Modal editing: you get normal, insert, visual and block visual modes + like Vim. In addition, you get an "Emacs" mode where movement and + navigation follow the Emacs bindings. + - Same movement keys as Vim in normal mode + - Leader key combinations + - Pressing ":" in normal mode allows you to execute commands + (including system commands) + +In my own experience, `evil-mode` helps make the transition seamless and +allows you to blend the arguably more intuitive and ergonomic +keybindings of Vim with the unbridled power of Emacs for a truly +superior editing experience. + +# Discoverable Help + +Emacs features a pretty powerful help system that allows you to discover +new functionality all the +time. + +``` text +Obtaining help on specific topics. Tab completion is available for function and variable names. + +C-h f RET --> Prompts you for the name of an elisp function and + displays help text on it along with a clickable link + to its source code. +C-h v RET --> Same as above with variables + +C-h k RET --> Allows you to enter a key combination and displays the + name of the elisp function bound to it. + +Searching for help: + +C-h a --> Prompts you for a string to search for a command in the + help system. Similar to the 'apropos' or 'man -k' + commands in Unix systems. + +Starting a tutorial: + +C-h C-t --> Starts a tutorial designed to familiarize you with + basic Emacs functionality. +``` + +# Emacs "Killer Apps" + +As I hinted above, Emacs functionality goes way beyond being a mere text +editor. I will list here a couple of Emacs "apps" that are fairly +powerful and popular and may interest you in and of themselves. + +## Org + +Technnically, `org-mode`, a major mode for buffer editing that provides +organizational tools. It is very difficult to succinctly describe what +Org can do because it's a behemoth of a tool that has many diverse uses +to different people. I will attempt to describe the main features I use +briefly. + + - Divide your file into sections and sub-sections for easy outlining + and organizing of concepts. + - Different headings in the outline are foldable/expandable so that + you can focus on what you need to focus on and eliminate + distractions. + - You can maintain a TODO list within Org + - You can compile TODO lists from many files into an agenda + - Track the time you spend on each TODO task + - Manage tables in plain text (including spreadsheet-like + capabilities) + - Using the extension `org-babel`, write and execute code blocks in + your file. The results are captured and are re-usable within the + file itself. Think Jupyter notebook for any language. + - Display inline images and LaTeX formulas as images within your file + (makes for a great note-taking system and/or personal wiki) + - Export your file into many different formats (LaTeX, PDF, html,…) + +Org mode is a very powerful tool to add to your productivity arsenal +and, on a personal note, was the reason that caused me to start using +Emacs after years of using Vim. + +## Magit + +This is a frontend to `git` from within Emacs. It features a very +intuitive and discoverable interface, yet exposes very powerful +functionality that allows you to manage commits at the chunk level, +inspect diffs, rebase, cherry-pick, … all from within the comfort of +your own editor. + +# A Word of Advice + +If you are considering using Emacs, a common trap that beginning users +fall into is to copy someone else's configuration file and use it as is. +I highly recommend against doing this for several reasons: + + - It will discourage you from learning and finding things out for + yourself + - Someone else's configuration will probably contain many things + relevant to them that you won't need or ever use. + - It defeats the purpose of having a customizable text editor that can + fit your own needs. + +What I encourage you to do is to look at other people's configurations +and seek to understand them and adapt only what makes sense to you. You +can find out about new features of Emacs through many YouTube videos, +screencasts or blog posts and then learn for yourself how to add them to +your configuration and workflow. This way, you grow your configuration +incrementally while increasing your knowledge of Emacs along the way. + +# Additional Resources + + - [The GNU Emacs Manual](https://www.gnu.org/software/emacs/manual/emacs.html) + - [Emacs Stack Exchange](https://emacs.stackexchange.com/) + - [Emacs Wiki](https://www.emacswiki.org/emacs/EmacsWiki) diff --git a/es-es/dart-es.html.markdown b/es-es/dart-es.html.markdown new file mode 100644 index 00000000..d0f57b95 --- /dev/null +++ b/es-es/dart-es.html.markdown @@ -0,0 +1,529 @@ +--- +language: dart +contributors: + - ["Joao Pedrosa", "https://github.com/jpedrosa/"] +translators: + - ["Jorge Antonio Atempa", "http://www.twitter.com/atempa09"] +filename: dart-es.md +lang: es-es +--- + +Dart es un recién llegado al ámbito de los lenguajes de programación. +Toma prestado mucho de otros lenguajes principales, con el objetivo de no desviarse demasiado de +su hermano JavaScript. Tal como JavaScript, Dart tiene como objetivo una gran integración en el navegador. + +La característica más controvertida de Dart debe ser su escritura opcional. + +```dart +import "dart:collection"; +import "dart:math" as DM; + +// Bienvenido a Aprende Dart en 15 minutos. http://www.dartlang.org/ +// Este es un tutorial ejecutable. Puedes ejecutarlo con Dart o en +// el sitio de ¡Try Dart! solo copiando y pegando en http://try.dartlang.org/ + +// La declaración de función y de método tienen el mismo aspecto. +// Las funciones pueden estar anidadas. +// La declaración toma la forma name() {} o name() => expresionEnUnaLinea; +// La declaración de la función de flecha gorda, tiene un retorno implícito +// para el resultado de la expresión. +example1() { + nested1() { + nested2() => print("example1 anidado 1 anidado 2"); + nested2(); + } + nested1(); +} + +// Las funciones anónimas no incluyen un nombre. +example2() { + nested1(fn) { + fn(); + } + nested1(() => print("example2 anidado 1")); +} + +// Cuando se declara un parámetro de función, la declaración puede incluir el +// número de parámetros que toma la función especificando los nombres de los +// parámetros que lleva. +example3() { + planA(fn(informSomething)) { + fn("example3 plan A"); + } + planB(fn) { // O no declarar el número de parámetros. + fn("example3 plan B"); + } + planA((s) => print(s)); + planB((s) => print(s)); +} + +// Las funciones tienen acceso de cierre a variables externas. +var example4Something = "Example4 anidado 1"; +example4() { + nested1(fn(informSomething)) { + fn(example4Something); + } + nested1((s) => print(s)); +} + +// La declaración de la clase con un método sayIt, el cual también tiene acceso de cierre +// a la variable exterior como si fuera una función como se ha visto antes. +var example5method = "example5 sayIt"; +class Example5Class { + sayIt() { + print(example5method); + } +} +example5() { + // Crear una instancia anónima de Example5Class y la llamada del método sayIt + new Example5Class().sayIt(); +} + +// La declaración de clase toma la forma NombreDeClase { [cuerpoDeClase] }. +// Donde cuerpoDeClase puede incluir métodos de instancia y variables, pero también +// métodos y variables de clase. +class Example6Class { + var instanceVariable = "Example6 variable de instancia"; + sayIt() { + print(instanceVariable); + } +} +example6() { + new Example6Class().sayIt(); +} + +// Los métodos y variables de clase son declarados con términos "static". +class Example7Class { + static var classVariable = "Example7 variable de clase"; + static sayItFromClass() { + print(classVariable); + } + sayItFromInstance() { + print(classVariable); + } +} +example7() { + Example7Class.sayItFromClass(); + new Example7Class().sayItFromInstance(); +} + +// Las literales son geniales, pero hay una restricción para lo que pueden ser las literales +// fuera de los cuerpos de función/método. Literales en el ámbito exterior de clase +// o fuera de clase tienen que ser constantes. Las cadenas de caracteres y los números +// son constantes por defecto. Pero los arreglos y mapas no lo son. +// Ellos pueden hacerse constante anteponiendo en la declaración el término "const". +var example8Array = const ["Example8 arreglo constante"], + example8Map = const {"algunaKey": "Example8 mapa constante"}; +example8() { + print(example8Array[0]); + print(example8Map["algunaKey"]); +} + +// Los bucles en Dart toman la forma estándar para for () {} o ciclos while () {} , +// ligeramente más moderno for (.. in ..) {}, o llamadas funcionales con muchas +// características soportadas, comenzando con forEach. +var example9Array = const ["a", "b"]; +example9() { + for (var i = 0; i < example9Array.length; i++) { + print("example9 ciclo for '${example9Array[i]}'"); + } + var i = 0; + while (i < example9Array.length) { + print("example9 ciclo while '${example9Array[i]}'"); + i++; + } + for (var e in example9Array) { + print("example9 ciclo for-in '${e}'"); + } + example9Array.forEach((e) => print("example9 ciclo forEach '${e}'")); +} + +// Para recorrer los caracteres de una cadena o para extraer una subcadena. +var example10String = "ab"; +example10() { + for (var i = 0; i < example10String.length; i++) { + print("example10 Recorrido de caracteres en la cadena '${example10String[i]}'"); + } + for (var i = 0; i < example10String.length; i++) { + print("example10 ciclo de subcadena '${example10String.substring(i, i + 1)}'"); + } +} + +// Formato de números Int y double son soportados. +example11() { + var i = 1 + 320, d = 3.2 + 0.01; + print("example11 int ${i}"); + print("example11 double ${d}"); +} + +// DateTime ofrece aritmética de fecha/hora. +example12() { + var now = new DateTime.now(); + print("example12 ahora '${now}'"); + now = now.add(new Duration(days: 1)); + print("example12 manana '${now}'"); +} + +// Expresiones regulares son soportadas. +example13() { + var s1 = "alguna cadena", s2 = "alguna", re = new RegExp("^s.+?g\$"); + match(s) { + if (re.hasMatch(s)) { + print("example13 regexp embona '${s}'"); + } else { + print("example13 regexp no embona '${s}'"); + } + } + match(s1); + match(s2); +} + +// Las expresiones booleanas admiten conversiones implícitas y tipos dinámicos. +example14() { + var a = true; + if (a) { + print("true, a is $a"); + } + a = null; + if (a) { + print("true, a es $a"); + } else { + print("false, a es $a"); // corre aquí + } + + // el tipado dinámico null puede convertirse a bool + var b; // b es de tipo dinámico + b = "abc"; + try { + if (b) { + print("true, b es $b"); + } else { + print("false, b es $b"); + } + } catch (e) { + print("error, b es $b"); // esto podría ser ejecutado pero consiguió error + } + b = null; + if (b) { + print("true, b es $b"); + } else { + print("false, b es $b"); // corre aquí + } + + // tipado estático null no puede ser convertido a bool + var c = "abc"; + c = null; + // compilación fallida + // if (c) { + // print("true, c is $c"); + // } else { + // print("false, c is $c"); + // } +} + +// try/catch/finally y throw son utilizados para el manejo de excepciones. +// throw toma cualquier objeto como parámetro; +example15() { + try { + try { + throw "Algun error inesperado."; + } catch (e) { + print("example15 una excepcion: '${e}'"); + throw e; // Re-throw + } + } catch (e) { + print("example15 atrapa la excepcion que ha sido relanzada: '${e}'"); + } finally { + print("example15 aún ejecuta finally"); + } +} + +// Para ser eficiente cuando creas una cadena larga dinámicamente, usa +// StringBuffer. O podrías unir un arreglo de cadena de caracteres. +example16() { + var sb = new StringBuffer(), a = ["a", "b", "c", "d"], e; + for (e in a) { sb.write(e); } + print("example16 cadena de caracteres dinamica creada con " + "StringBuffer '${sb.toString()}'"); + print("example16 union de arreglo de cadena de caracteres '${a.join()}'"); +} + +// Las cadenas de caracteres pueden ser concatenadas contando solo +// con literales una después de la otra sin algún otro operador necesario. +example17() { + print("example17 " + "concatenar " + "cadenas " + "asi"); +} + +// Las cadenas de caracteres utilizan comilla simple o comillas dobles como delimitadores +// sin ninguna diferencia entre ambas. Esto proporciona flexibilidad que puede ser efectiva +// para evitar la necesidad de 'escapar' el contenido. Por ejemplo, +// las dobles comillas de los atributos HTML. +example18() { + print('Example18 <a href="etc">' + "Don't can't I'm Etc" + '</a>'); +} + +// Las cadenas de caracteres con triple comilla simple o triple comillas dobles +// dividen múltiples lineas e incluyen como delimitador el salto de línea. +example19() { + print('''Example19 <a href="etc"> +Example19 Don't can't I'm Etc +Example19 </a>'''); +} + +// Las cadenas de caracteres cuentan con una extraordinaria característica +// para la interpolación de caracteres utilizando el operador $ +// Con $ { [expresion] }, devolvemos la expresion interpolada. +// $ seguido por el nombre de una variable interpola el contenido de dicha variable. +// $ puede ser escapado con \$ para solo agregarlo a la cadena. +example20() { + var s1 = "'\${s}'", s2 = "'\$s'"; + print("Example20 \$ interpolation ${s1} or $s2 works."); +} + +// Hasta ahora no hemos declarado ningún tipo de dato y los programas +// han funcionado bien. De hecho, los tipos no se toman en cuenta durante +// el tiempo de ejecución. +// Los tipos incluso pueden estar equivocados y al programa todavía se le dará +// el beneficio de la duda y se ejecutará como si los tipos no importaran. +// Hay un parámetro de tiempo de ejecución que comprueba los errores de tipo que es +// el modo de verificación, el cuál es útil durante el tiempo de desarrollo, +// pero que también es más lento debido a la comprobación adicional y, por lo tanto +// se evita durante el tiempo de ejecución de la implementación. +class Example21 { + List<String> _names; + Example21() { + _names = ["a", "b"]; + } + List<String> get names => _names; + set names(List<String> list) { + _names = list; + } + int get length => _names.length; + void add(String name) { + _names.add(name); + } +} +void example21() { + Example21 o = new Example21(); + o.add("c"); + print("example21 nombres '${o.names}' y longitud '${o.length}'"); + o.names = ["d", "e"]; + print("example21 nombres '${o.names}' y longitud '${o.length}'"); +} + +// La herencia de clases toma la forma NombreDeClase extends OtraClase {}. +class Example22A { + var _name = "¡Algun Nombre!"; + get name => _name; +} +class Example22B extends Example22A {} +example22() { + var o = new Example22B(); + print("example22 herencia de clase '${o.name}'"); +} + +// La mezcla de clases también esta disponible y toman la forma de +// NombreDeClase extends AlgunaClase with OtraClase {}. +// Es necesario extender de alguna clase para poder mezclar con otra. +// La clase de plantilla de mixin no puede en este momento tener un constructor. +// Mixin se utiliza principalmente para compartir métodos con clases distantes, +// por lo que la herencia única no interfiere con el código reutilizable. +// Mixins se colocan despues de la palabra "with" durante la declaración de la clase. +class Example23A {} +class Example23Utils { + addTwo(n1, n2) { + return n1 + n2; + } +} +class Example23B extends Example23A with Example23Utils { + addThree(n1, n2, n3) { + return addTwo(n1, n2) + n3; + } +} +example23() { + var o = new Example23B(), r1 = o.addThree(1, 2, 3), + r2 = o.addTwo(1, 2); + print("Example23 addThree(1, 2, 3) results in '${r1}'"); + print("Example23 addTwo(1, 2) results in '${r2}'"); +} + +// El método constructor de la clase utiliza el mismo nombre de la clase +// y toma la forma de AlgunaClase() : super() {}, donde la parte ": super()" +// es opcional y es utilizado para delegar parametros constantes +// al método constructor de la clase padre o super clase. +class Example24A { + var _value; + Example24A({value: "algunValor"}) { + _value = value; + } + get value => _value; +} +class Example24B extends Example24A { + Example24B({value: "algunOtroValor"}) : super(value: value); +} +example24() { + var o1 = new Example24B(), + o2 = new Example24B(value: "aunMas"); + print("example24 llama al método super desde el constructor '${o1.value}'"); + print("example24 llama al método super desde el constructor '${o2.value}'"); +} + +// Hay un atajo para configurar los parámetros del constructor en el caso de clases más simples. +// Simplemente use el prefijo this.nombreParametro y establecerá el parámetro +// en una variable de instancia del mismo nombre. +class Example25 { + var value, anotherValue; + Example25({this.value, this.anotherValue}); +} +example25() { + var o = new Example25(value: "a", anotherValue: "b"); + print("example25 atajo para el constructor '${o.value}' y " + "'${o.anotherValue}'"); +} + +// Los parámetros con nombre están disponibles cuando se declaran entre {}. +// El orden de los parámetros puede ser opcional cuando se declara entre {}. +// Los parámetros pueden hacerse opcionales cuando se declaran entre []. +example26() { + var _name, _surname, _email; + setConfig1({name, surname}) { + _name = name; + _surname = surname; + } + setConfig2(name, [surname, email]) { + _name = name; + _surname = surname; + _email = email; + } + setConfig1(surname: "Doe", name: "John"); + print("example26 name '${_name}', surname '${_surname}', " + "email '${_email}'"); + setConfig2("Mary", "Jane"); + print("example26 name '${_name}', surname '${_surname}', " + "email '${_email}'"); +} + +// Las variables declaradas con final solo se pueden establecer una vez. +// En el caso de las clases, las variables de instancia final se pueden establecer +// a través de la constante del parámetro constructor. +class Example27 { + final color1, color2; + // Un poco de flexibilidad para establecer variables de instancia finales con la sintaxis + // que sigue a : + Example27({this.color1, color2}) : color2 = color2; +} +example27() { + final color = "orange", o = new Example27(color1: "lilac", color2: "white"); + print("example27 color es '${color}'"); + print("example27 color es '${o.color1}' y '${o.color2}'"); +} + +// Para importar una librería utiliza la palabra reservada import "rutaLibrería" o si es una biblioteca central, +// import "dart:NombreLibrería". También está el "pub" administrador de paquetes con +// su propia convensión import "package:NombrePaquete". +// Ve import "dart:collection"; al inicio. Las importaciones deben venir antes +// de la delcaración de algún otro código. IterableBase proviene de dart:collection. +class Example28 extends IterableBase { + var names; + Example28() { + names = ["a", "b"]; + } + get iterator => names.iterator; +} +example28() { + var o = new Example28(); + o.forEach((name) => print("example28 '${name}'")); +} + +// Para el control de flujo tenemos: +// * estandard switch +// * if-else if-else y el operador ternario ..?..:.. +// * closures y funciones anonimas +// * sentencias break, continue y return +example29() { + var v = true ? 30 : 60; + switch (v) { + case 30: + print("example29 sentencia switch"); + break; + } + if (v < 30) { + } else if (v > 30) { + } else { + print("example29 sentencia if-else"); + } + callItForMe(fn()) { + return fn(); + } + rand() { + v = new DM.Random().nextInt(50); + return v; + } + while (true) { + print("example29 callItForMe(rand) '${callItForMe(rand)}'"); + if (v != 30) { + break; + } else { + continue; + } + // Nunca llega aquí. + } +} + +// La sentencia int.parse, convierte de tipo double a int, o simplemente mantener int cuando se dividen los números +// utilizando ~/ como operación. Vamos a jugar un juego de adivinanzas también. +example30() { + var gn, tooHigh = false, + n, n2 = (2.0).toInt(), top = int.parse("123") ~/ n2, bottom = 0; + top = top ~/ 6; + gn = new DM.Random().nextInt(top + 1); // +1 porque nextInt top es exclusivo + print("example30 Adivina un número entre 0 y ${top}"); + guessNumber(i) { + if (n == gn) { + print("example30 ¡Adivinaste correctamente! El número es ${gn}"); + } else { + tooHigh = n > gn; + print("example30 Número ${n} es demasiado " + "${tooHigh ? 'high' : 'low'}. Intenta nuevamente"); + } + return n == gn; + } + n = (top - bottom) ~/ 2; + while (!guessNumber(n)) { + if (tooHigh) { + top = n - 1; + } else { + bottom = n + 1; + } + n = bottom + ((top - bottom) ~/ 2); + } +} + +// Los programas tienen un solo punto de entrada en la función principal. +// No se espera que se ejecute nada en el ámbito externo antes de que un programa +// comience a funcionar con su función principal. +// Esto ayuda con una carga más rápida e incluso con una carga lenta +// de lo que necesita el programa para iniciar. +main() { + print("Learn Dart in 15 minutes!"); + [example1, example2, example3, example4, example5, example6, example7, + example8, example9, example10, example11, example12, example13, example14, + example15, example16, example17, example18, example19, example20, + example21, example22, example23, example24, example25, example26, + example27, example28, example29, example30 + ].forEach((ef) => ef()); +} + +``` + +## Lecturas adicionales + +Dart tiene un sitio web muy completo. Cubre referencias de API, tutoriales, artículos y más, incluyendo una +útil sección en línea Try Dart. +[https://www.dartlang.org](https://www.dartlang.org) +[https://try.dartlang.org](https://try.dartlang.org) diff --git a/es-es/kotlin-es.html.markdown b/es-es/kotlin-es.html.markdown index 045f92d1..80d7a4bb 100644 --- a/es-es/kotlin-es.html.markdown +++ b/es-es/kotlin-es.html.markdown @@ -2,6 +2,7 @@ language: kotlin contributors: - ["S Webber", "https://github.com/s-webber"] +- ["Aitor Escolar", "https://github.com/aiescola"] translators: - ["Ivan Alburquerque", "https://github.com/AlburIvan"] lang: es-es @@ -40,6 +41,12 @@ fun main(args: Array<String>) { Podemos declarar explícitamente el tipo de una variable así: */ val foo: Int = 7 + + /* + A diferencia de JavaScript, aunque el tipo se infiera, es tipado, por lo que no se puede cambiar el tipo a posteriori + */ + var fooInt = 14 // Se infiere tipo Int + fooInt = "Cadena" // ERROR en tiempo de compilación: Type mismatch /* Las cadenas pueden ser representadas de la misma manera que Java. @@ -84,7 +91,6 @@ fun main(args: Array<String>) { println(fooNullable?.length) // => null println(fooNullable?.length ?: -1) // => -1 - /* Las funciones pueden ser declaras usando la palabra clave "fun". Los argumentos de las funciones son especificados entre corchetes despues del nombre de la función. @@ -122,6 +128,40 @@ fun main(args: Array<String>) { fun even(x: Int) = x % 2 == 0 println(even(6)) // => true println(even(7)) // => false + + /* + Kotlin permite el uso de lambdas, o funciones anónimas + */ + + // Sin lambda: + interface MyListener { + fun onClick(foo: Foo) + } + + fun listenSomething(listener: MyListener) { + listener.onClick(Foo()) + } + + listenSomething(object: MyListener { + override fun onClick(foo: Foo) { + //... + } + }) + + // Con lambda: + fun listenSomethingLambda(listener: (Foo) -> Unit) { + listener(Foo()) + } + + listenSomethingLambda { + //Se recibe foo + } + + // el operador typealias permite, entre otras cosas, simplificar las expresiones con lambdas + typealias MyLambdaListener = (Foo) -> Unit + fun listenSomethingLambda(listener: MyLambdaListener) { + listener(Foo()) + } // Las funciones pueden tomar funciones como argumentos y // retornar funciones. @@ -219,6 +259,11 @@ fun main(args: Array<String>) { val fooMap = mapOf("a" to 8, "b" to 7, "c" to 9) // Se puede acceder a los valores del mapa por su llave. println(fooMap["a"]) // => 8 + + // Tanto Map como cualquier colección iterable, tienen la función de extensión forEach + fooMap.forEach { + println("${it.key} ${it.value}") + } /* Las secuencias representan colecciones evaluadas diferidamente. @@ -245,7 +290,7 @@ fun main(args: Array<String>) { val y = fibonacciSequence().take(10).toList() println(y) // => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] - // Kotlin provee funciones de Orden-Mayor para trabajar con colecciones. + // Kotlin provee funciones de orden superior para trabajar con colecciones. val z = (1..9).map {it * 3} .filter {it < 20} .groupBy {it % 2 == 0} @@ -305,17 +350,11 @@ fun main(args: Array<String>) { ese tipo sin convertido de forma explícita. */ fun smartCastExample(x: Any) : Boolean { - if (x is Boolean) { - // x es automaticamente convertido a Boolean - return x - } else if (x is Int) { - // x es automaticamente convertido a Int - return x > 0 - } else if (x is String) { - // x es automaticamente convertido a String - return x.isNotEmpty() - } else { - return false + return when (x) { + is Boolean -> x // x es automaticamente convertido a Boolean + is Int -> x > 0 // x es automaticamente convertido a Int + is String -> x.isNotEmpty() // x es automaticamente convertido a String + else -> false } } println(smartCastExample("Hola, mundo!")) // => true @@ -345,7 +384,8 @@ enum class EnumExample { /* La palabra clave "object" se puede utilizar para crear objetos únicos. No podemos asignarlo a una variable, pero podemos hacer referencia a ella por su nombre. -Esto es similar a los objetos únicos de Scala +Esto es similar a los objetos únicos de Scala. +En la mayoría de ocasiones, los objetos únicos se usan como alternativa a los Singleton. */ object ObjectExample { fun hello() : String { diff --git a/es-es/scala-es.html.markdown b/es-es/scala-es.html.markdown new file mode 100644 index 00000000..2dcb9e7f --- /dev/null +++ b/es-es/scala-es.html.markdown @@ -0,0 +1,741 @@ +--- +language: Scala +filename: learnscala-es.scala +contributors: + - ["George Petrov", "http://github.com/petrovg"] + - ["Dominic Bou-Samra", "http://dbousamra.github.com"] + - ["Geoff Liu", "http://geoffliu.me"] + - ["Ha-Duong Nguyen", "http://reference-error.org"] +translators: + - ["Pablo Arranz Ropero", "http://arranzropablo.com"] +lang: es-es +--- + +Scala - El lenguaje escalable + +```scala + +///////////////////////////////////////////////// +// 0. Básicos +///////////////////////////////////////////////// +/* + Configurar Scala: + + 1) Descarga Scala - http://www.scala-lang.org/downloads + 2) Unzip/untar a tu carpeta elegida y pon la subcarpeta bin en tu variable de entorno `PATH` +*/ + +/* + Prueba REPL + + Scala tiene una herramienta llamada REPL (Read-Eval-Print Loop, en español: Bucle de lectura-evaluación-impresión) que es analogo a interpretes de la linea de comandos en muchos otros lenguajes. + Puedes escribir cualquier expresión en Scala y el resultado será evaluado e impreso. + + REPL es una herramienta muy práctica para testear y verificar código. + Puedes usarla mientras lees este tutorial para explorar conceptos por tu cuenta. +*/ + +// Inicia Scala REPL ejecutando `scala` en tu terminal. Deberías ver: +$ scala +scala> + +// Por defecto cada expresión que escribes es guardada como un nuevo valor numerado: +scala> 2 + 2 +res0: Int = 4 + +// Los valores por defecto pueden ser reusados. Fíjate en el tipo del valor mostrado en el resultado... +scala> res0 + 2 +res1: Int = 6 + +// Scala es un lenguaje fuertemente tipado. Puedes usar REPL para comprobar el tipo sin evaluar una expresión. +scala> :type (true, 2.0) +(Boolean, Double) + +// Las sesiones REPL pueden ser guardadas +scala> :save /sites/repl-test.scala + +// Se pueden cargar archivos en REPL +scala> :load /sites/repl-test.scala +Loading /sites/repl-test.scala... +res2: Int = 4 +res3: Int = 6 + +// Puedes buscar en tu historial reciente +scala> :h? +1 2 + 2 +2 res0 + 2 +3 :save /sites/repl-test.scala +4 :load /sites/repl-test.scala +5 :h? + +// Ahora que sabes como jugar, aprendamos un poco de Scala... + +///////////////////////////////////////////////// +// 1. Básicos +///////////////////////////////////////////////// + +// Los comentarios de una linea comienzan con dos barras inclinadas + +/* + Los comentarios de varias lineas, como ya has visto arriba, se hacen de esta manera. +*/ + +// Así imprimimos forzando una nueva linea en la siguiente impresión +println("Hola mundo!") +println(10) +// Hola mundo! +// 10 + +// Así imprimimos sin forzar una nueva linea en la siguiente impresión +print("Hola mundo") +print(10) +// Hola mundo10 + +// Para declarar valores usamos var o val. +// Valores decalrados con val son inmutables, mientras que los declarados con var son mutables. +// La inmutabilidad es algo bueno. +val x = 10 // x es 10 +x = 20 // error: reassignment to val +var y = 10 +y = 20 // y es 20 + +/* + Scala es un lenguaje tipado estáticamente, aunque se puede ver en las expresiones anteriores que no hemos especificado un tipo. + Esto es debido a una funcionalidad del lenguaje llamada inferencia. En la mayoría de los casos, el compilador de Scala puede adivinar cual es el tipo de una variable, así que no hace falta escribirlo siempre. + Podemos declarar explicitamente el tipo de una variable de la siguiente manera: +*/ +val z: Int = 10 +val a: Double = 1.0 + +// Observa la conversión automática de Int a Double, el resultado será 10.0, no 10 +val b: Double = 10 + +// Valores Booleanos +true +false + +// Operaciones Booleanas +!true // false +!false // true +true == false // false +10 > 5 // true + +// Las operaciones matemáticas se realizan como siempre +1 + 1 // 2 +2 - 1 // 1 +5 * 3 // 15 +6 / 2 // 3 +6 / 4 // 1 +6.0 / 4 // 1.5 +6 / 4.0 // 1.5 + + +// Evaluar una expresión en REPL te da el tipo y valor del resultado + +1 + 7 + +/* La linea superior tienen como resultado: + + scala> 1 + 7 + res29: Int = 8 + + Esto quiere decir que el resultado de evaluar 1 + 7 es un objeto de tipo Int con valor 8 + + Observa que "res29" es un nombre de variable secuencialmente generado para almacenar los resultados de las expresiones escritas, la salida que observes puede diferir en este sentido. +*/ + +"Las cadenas en Scala están rodeadas por comillas dobles" +'a' // Un caracter en Scala +// 'Las cadenas con comillas simples no existen' <= Esto causa un error + +// Las cadenas tienen los los típicos metodos de Java definidos +"hello world".length +"hello world".substring(2, 6) +"hello world".replace("C", "3") + +// También tienen algunos métodos extra de Scala. Ver: scala.collection.immutable.StringOps +"hello world".take(5) +"hello world".drop(5) + +// Interpolación de cadenas: Observa el prefijo "s" +val n = 45 +s"Tengo $n manzanas" // => "Tengo 45 manzanas" + +// Es posible colocar expresiones dentro de cadenas interpoladas +val a = Array(11, 9, 6) +s"Mi segunda hija tiene ${a(0) - a(2)} años." // => "Mi segunda hija tiene 5 años." +s"Hemos doblado la cantidad de ${n / 2.0} manzanas." // => "Hemos doblado la cantidad de 22.5 manzanas." +s"Potencia de 2: ${math.pow(2, 2)}" // => "Potencia de 2: 4" + +// Podemos formatear cadenas interpoladas con el prefijo "f" +f"Potencia de 5: ${math.pow(5, 2)}%1.0f" // "Potencia de 5: 25" +f"Raiz cuadrada de 122: ${math.sqrt(122)}%1.4f" // "Raiz cuadrada de 122: 11.0454" + +// Las cadenas puras ignoran caracteres especiales. +raw"Nueva linea: \n. Retorno: \r." // => "Nueva linea: \n. Retorno: \r." + +// Algunos caracteres necesitn ser escapados, por ejemplo unas comillas dobles dentro de una cadena: +"Se quedaron fuera de \"Rose and Crown\"" // => "Se quedaron fuera de "Rose and Crown"" + +// Las triples comillas dobles dejan que las cadenas se expandan por multiples filas y contengan comillas dobles o simples +val html = """<form id="daform"> + <p>Press belo', Joe</p> + <input type="submit"> + </form>""" + + +///////////////////////////////////////////////// +// 2. Funciones +///////////////////////////////////////////////// + +// Las funciones se definen de la siguiente manera: +// +// def nombreFuncion(argumentos...): TipoRetorno = { cuerpo... } +// +// Si estás acostumbrado a lenguajes más tradicionales, observa la omisión de la palabra return. +// En Scala, la última expresión en el bloque de función es el valor de retorno. +def sumaDeCuadrados(x: Int, y: Int): Int = { + val x2 = x * x + val y2 = y * y + x2 + y2 +} + +// Los { } pueden omitirse si el cuerpo de la función es una única expresión: +def sumaDeCuadradosCorta(x: Int, y: Int): Int = x * x + y * y + +// La sintaxis para llamar funciones es familiar: +sumaDeCuadrados(3, 4) // => 25 + +// Puedes usar los nombres de los parámetros para llamarlos en orden diferente +def restar(x: Int, y: Int): Int = x - y + +restar(10, 3) // => 7 +restar(y=10, x=3) // => -7 + +// En la mayoría de los casos (siendo las funciones recursivas la excepción más notable), +// el tipo de retorno de la función puede ser omitido, y la misma inferencia de tipos que vimos con las variables +// funcionará con los valores de retorno de las funciones: +def sq(x: Int) = x * x // El compilador puede adivinar que el tipo de retorno es Int + +// Las funciones pueden tener parametros por defecto: +def sumarConDefecto(x: Int, y: Int = 5) = x + y +sumarConDefecto(1, 2) // => 3 +sumarConDefecto(1) // => 6 + + +// Las funciones anónimas se escriben así: +(x: Int) => x * x + +// Al contrario que los defs, incluso el tipo de entrada de las funciones anónimas puede ser omitido si +// el contexto lo deja claro. Observa el tipo "Int => Int" que significa que es una función +// que recibe Int y retorna Int. +val sq: Int => Int = x => x * x + +// Las funciones anónimas pueden ser llamadas como las demás: +sq(10) // => 100 + +// Si cada argumento en tu función anónima es usado solo una vez, +// Scala te da una manera incluso más corta de definirlos. +// Estas funciones anónimas son extremadamente comunes, +// como será obvio en la sección de estructuras de datos. +val sumarUno: Int => Int = _ + 1 +val sumaRara: (Int, Int) => Int = (_ * 2 + _ * 3) + +sumarUno(5) // => 6 +sumaRara(2, 4) // => 16 + + +// La palabra return existe en Scala, pero solo retorna desde la función más interna que la rodea. +// ADVERTENCIA: Usar return en Scala puede inducir a errores y debe ser evitado +// No tiene efecto en funciones anónimas. Por ejemplo: +def foo(x: Int): Int = { + val funcAnon: Int => Int = { z => + if (z > 5) + return z // Esta línea hace que z sea el valor de retorno de foo! + else + z + 2 // Esta línea es el valor de retorno de funcAnon + } + anonFunc(x) // Esta línea es el valor de retorno de foo +} + + +///////////////////////////////////////////////// +// 3. Control del flujo +///////////////////////////////////////////////// + +1 to 5 +val r = 1 to 5 +r.foreach(println) + +r foreach println +// Nota: Scala es un lenguaje muy permisivo cuando se trata de puntos y parentesis - estudia las +// reglas separadamente. Esto ayuda a escribir DSLs y APIs que se lean en lenguaje natural. + +// Por qué `println` no necesita parámetros aquí? +// Presta atención a las funciones de primera clase en la sección de Programación Funcional más abajo! +(5 to 1 by -1) foreach (println) + +// Un bucle while +var i = 0 +while (i < 10) { println("i " + i); i += 1 } + +while (i < 10) { println("i " + i); i += 1 } // Si, de nuevo. Qué ocurrió? Por qué? + +i // Muestra el valor de i. Observa que while es un loop en el sentido clásico - + // se ejecuta secuencialmente mientras cambia la variable del bucle. while es muy + // rápido, pero los combinadores y comprensiones anteriores son más sencillos + // de entender y paralelizar + +// Un bucle do-while +i = 0 +do { + println("i es aún menor que 10") + i += 1 +} while (i < 10) + +// La recursion es la manera idiomática de repetir una acción en Scala (como en la mayoría de +// lenguajes funcionales). +// Las funciones recursivas necesitan un tipo de retorno explicito, el compilador no puede inferirlo. +// En Scala tenemos Unit, que es análogo al tipo de retorno `void` en Java +def enseñaNumerosEnUnRango(a: Int, b: Int): Unit = { + print(a) + if (a < b) + enseñaNumerosEnUnRango(a + 1, b) +} +enseñaNumerosEnUnRango(1, 14) + + +// Condicionales + +val x = 10 + +if (x == 1) println("yeah") +if (x == 10) println("yeah") +if (x == 11) println("yeah") +if (x == 11) println("yeah") else println("nay") + +println(if (x == 10) "yeah" else "nope") +val text = if (x == 10) "yeah" else "nope" + + +///////////////////////////////////////////////// +// 4. Estructuras de datos +///////////////////////////////////////////////// + +val a = Array(1, 2, 3, 5, 8, 13) +a(0) // Int = 1 +a(3) // Int = 5 +a(21) // Lanza una excepción + +val m = Map("fork" -> "tenedor", "spoon" -> "cuchara", "knife" -> "cuchillo") +m("fork") // java.lang.String = tenedor +m("spoon") // java.lang.String = cuchara +m("bottle") // Lanza una excepción + +val mapaSeguro = m.withDefaultValue("no lo se") +mapaSeguro("bottle") // java.lang.String = no lo se + +val s = Set(1, 3, 7) +s(0) // Boolean = false +s(1) // Boolean = true + +/* Hecha un vistazo a la documentación de Map aquí - + * http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Map + * y asegúrate de que puedes leerla + */ + + +// Tuplas + +(1, 2) + +(4, 3, 2) + +(1, 2, "three") + +(a, 2, "three") + +// Por qué tener esto? +val dividirEnteros = (x: Int, y: Int) => (x / y, x % y) + +// La función dividirEnteros te da el resultado y el resto +dividirEnteros(10, 3) // (Int, Int) = (3,1) + +// Para acceder a los elementos de una tupla, usa _._n donde n es el indice (comenzando por 1) +// del elemento +val d = dividirEnteros(10, 3) // (Int, Int) = (3,1) + +d._1 // Int = 3 +d._2 // Int = 1 + +// Alternativamente puedes asignar multiples variables desde una tupla, lo que +// resulta más conveniente y legible en muchos casos. +val (div, mod) = dividirEnteros(10, 3) + +div // Int = 3 +mod // Int = 1 + + +///////////////////////////////////////////////// +// 5. Programación Orientada a Objetos +///////////////////////////////////////////////// + +/* + Nota: Todo lo que hemos hecho hasta ahora en este tutorial han sido + simples expresiones (valores, funciones, etc). Estas expresiones son validas + para hacer pruebas rapidas en el interprete de la linea de comandos, + pero no pueden existir por si solas en un archivo de Scala. Por ejemplo, + no puedes tener simplemente "val x = 5" en un archivo Scala. En lugar de eso, + las únicas construcciones de alto nivel en Scala son: + + - Objetos + - Clases + - Case clases + - Traits + + Y ahora explicaremos lo que son estas. +*/ + +// Las clases son similares a las clases de otros lenguajes. Los argumentos del constructor +// son declarados despues del nombre de la clase, y la inicialización se hace en el cuerpo de la clase. +class Perro(r: String) { + // Código del constructor aquí + var raza: String = r + + // Define un método llamado ladrar, que devuelva un String + def ladrar = "Woof, woof!" + + // Los valores y métodos son asumidos como públicos. + // Las palabras "protected" y "private" también son válidas. + private def dormir(horas: Int) = + println(s"Estoy durmiendo $horas horas") + + // Los métodos abstractos son simplemente métodos sin cuerpo. + // Si descomentamos la linea de debajo, la clase Perro necesitaría ser abstracta: + // abstract class Perro(...) { ... } + // def perseguir(algo: String): String +} + +val miperro = new Dog("greyhound") +println(mydog.raza) // => "greyhound" +println(mydog.ladrar) // => "Woof, woof!" + + +// La palabra "object" crea un tipo y una instancia singleton de ese tipo. +// Es común que las clases en Scala tengan un "companion object", de manera que +// el comportamiento por instancia es controlado por las clases y el comportamiento +// relacionado a todas las instancias de esa clase es controlado por el objeto +// La relación es similar a los métodos de las clases con los métodos estáticos +// en otros lenguajes. Observa que los objetos y clases pueden tener el mismo nombre. +object Perro { + def todasLasRazasConocidas = List("pitbull", "shepherd", "retriever") + def crearPerro(raza: String) = new Dog(breed) +} + + +// Case clases son clases que tienen funcionalidad extra añadida. Una pregunta +// común para los principiantes en Scala es cuando usar case clases y cuando usar +// clases. La linea no está bien definida, pero en general, las clases tienden a +// enfocarse en la encapsulación, polimorfismo y comportamiento. Los valores en +// estas clases tienden a ser privados, y solo se exponen los métodos. +// El propósito principal de las case clases es tener datos inmutables. +// A menudo tienen pocos métodos, y los métodos raramente tienen efectos secundarios. +case class Persona(nombre: String, telefono: String) + +// Para crear instancia nuevas, observa que las case clases no necesitan "new" +val george = Persona("George", "1234") +val kate = Persona("Kate", "4567") + +// Con las case clases tienes unas pocas ventajas, como el acceso a los campos: +george.telefono // => "1234" + +// Para la igualdad de campos no necesitas sobreescribir el método equals +Persona("George", "1234") == Persona("Kate", "1236") // => false + +// Manera fácil de copiar +// otroGeorge == Persona("George", "9876") +val otroGeorge = george.copy(telefono = "9876") + +// Y muchas otras. Las case clases también tienen comparación de patrones, que veremos más abajo. + +// Traits +// De manera similar a las interfaces Java, los traits definen un tipo de objeto y métodos. +// Scala permite la implementación parcial de dichos métodos. +// No se permiten parámetros de constructor. Los traits pueden heredar de otros traits o +// clases sin parámetros. + +trait Perro { + def raza: String + def color: String + def ladra: Boolean = true + def muerde: Boolean +} +class SanBernardo extends Perro { + val raza = "San Bernardo" + val color = "marrón" + def muerde = false +} + +scala> b +res0: SanBernardo = SanBernardo@3e57cd70 +scala> b.raza +res1: String = San Bernardo +scala> b.ladra +res2: Boolean = true +scala> b.muerde +res3: Boolean = false + +// Un trait tambien puede ser usado mezclado con otros traits. +// La clase extiende el primer trait, pero la palabra "with" +// puede añadir traits adicionales. + +trait Ladra { + def ladra: String = "Guau" +} +trait Perro { + def raza: String + def color: String +} +class SanBernardo extends Perro with Ladra { + val raza = "San Bernardo" + val color = "marrón" +} + +scala> val b = new SanBernardo +b: SanBernardo = SanBernardo@7b69c6ba +scala> b.ladra +res0: String = Guau + + +///////////////////////////////////////////////// +// 6. Comparación de patrones +///////////////////////////////////////////////// + +// La comparación de patrones es una poderosa función de Scala. +// Ahora veremos como comparar patrones en una case clase. +// Nota: A diferencia de otros lenguajes, Scala "cases" no necesitan +// "break", porque no ejecuta los "case" posteriores. + +def comparaPersona(persona: Persona): String = persona match { + // Aqui especificas los patrones: + case Persona("George", telefono) => "Hemos encontrado a George! Su número es " + telefono + case Persona("Kate", telefono) => "Hemos encontrado a Kate! Su número es " + telefono + case Persona(nombre, telefono) => "Hemos encontrado alguien : " + nombre + ", teléfono : " + telefono +} + +// Las expresiones regulares también están incorporadas. +// Creas una expresión regular con el método `r` en una cadena: +val email = "(.*)@(.*)".r + +// La comparación de patrones puede parecerse al bloque switch en la familia de lenguajes de C, +// pero aquí es mucho más poderosa. En Scala, puedes hacer más comparaciones: +def comparaTodo(obj: Any): String = obj match { + // Puedes comparar valores: + case "Hola mundo" => "Tengo la cadena Hola mundo" + + // Puedes comparar tipos: + case x: Double => "Tengo un double: " + x + + // Puedes especificar condiciones: + case x: Int if x > 10000 => "Tengo un número muy grande!" + + // Puedes comparar case clases como antes: + case Persona(nombre, telefono) => s"Tengo la información de contacto de $nombre!" + + // Puedes comparar expresiones regulares: + case email(nombre, dominio) => s"Tengo la dirección de correo $nombre@$dominio" + + // Puedes comparar tuplas: + case (a: Int, b: Double, c: String) => s"Tengo la tupla: $a, $b, $c" + + // Puedes comparar estructuras: + case List(1, b, c) => s"Tengo un alista con tres elementos que empieza con 1: 1, $b, $c" + + // Puedes anidar patrones: + case List(List((1, 2, "YAY"))) => "Tengo una lista de listas de tuplas" + + // Comparar cualquier case (default) si todos los anteriores no han coincido + case _ => "Tengo un objeto desconocido" +} + +// De hecho puedes comparar un patrón con cualquier objeto con el método "unapply". +// Esta función es tan poderosa que Scala te deja definir funciones enteras como patrones: +val funcPatron: Person => String = { + case Persona("George", telefono) => s"Teléfono de George: $telefono" + case Persona(nombre, telefono) => s"Teléfono de una persona aleatoria: $telefono" +} + + +///////////////////////////////////////////////// +// 7. Programación funcional +///////////////////////////////////////////////// + +// Scala permite a los métodos y funciones devolver o +// recibir como parámetros otras funciones o métodos + +val suma10: Int => Int = _ + 10 // Una función que recibe y devuelve un Int +List(1, 2, 3) map suma10 // List(11, 12, 13) - suma10 es aplicado a cada elemento + +// Las funciones anónimas pueden ser usadas en vez de funciones con nombre: +List(1, 2, 3) map (x => x + 10) + +// Y la barra baja puede ser usada si solo hay un argumento en la función anónima. +// Se usa como la variable. +List(1, 2, 3) map (_ + 10) + +// Si el bloque anónimo Y la función que estás usando usan los dos un argumento, +// puedes incluso omitir la barra baja. +List("Dom", "Bob", "Natalia") foreach println + + +// Combinadores +// Usando s de arriba: +// val s = Set(1, 3, 7) + +s.map(sq) + +val sCuadrado = s. map(sq) + +sSquared.filter(_ < 10) + +sSquared.reduce (_+_) + +// La función filter toma un predicado (una función A -> Boolean) y +// selecciona todos los elementos que satisfacen el predicado. +List(1, 2, 3) filter (_ > 2) // List(3) +case class Persona(nombre: String, edad: Int) +List( + Persona(nombre = "Dom", edad = 23), + Persona(nombre = "Bob", edad = 30) +).filter(_.edad > 25) // List(Persona("Bob", 30)) + + +// Ciertas colecciones (como List) en Scala tienen un método `foreach`, +// que toma como argumento un tipo que devuelva Unit (un método void) +val unaListaDeNumeros = List(1, 2, 3, 4, 10, 20, 100) +unaListaDeNumeros foreach (x => println(x)) +unaListaDeNumeros foreach println + +// Para comprensiones + +for { n <- s } yield sq(n) + +val nCuadrado2 = for { n <- s } yield sq(n) + +for { n <- nSquared2 if n < 10 } yield n + +for { n <- s; nSquared = n * n if nSquared < 10} yield nSquared + +/* Nota: Esos no son bucles. La semántica de un bucle es repetir, mientras que un for de comprension define una relación entre dos conjuntos de datos.*/ + + +///////////////////////////////////////////////// +// 8. Implicitos +///////////////////////////////////////////////// + +/* ATENCIÓN ATENCIÓN: Los implicitos son un conjunto de poderosas características de Scala + * y es fácil abusar de ellos. Si eres principiante en Scala deberías resistir la tentación + * de usarlos hasta que entiendas no solo como funcionan, sino también las mejores prácticas + * con ellos. Nosotros solo incluiremos esta sección en el tutorial porque son tan comunes + * en las librerias de Scala que es imposible hacer algo significativo sin usar una librería + * que tenga implicitos. Esto es para que entiendas como funcionan los implicitos, no para + * que definas los tuyos propios. + */ + +// Cualquier valor (val, funciones, objetos, etc) puede ser declarado como implicito usando +// la palabra "implicit". Observa que usamos la clase Perro de la sección 5. +implicit val miEnteroImplicito = 100 +implicit def miFunciónImplicita(raza: String) = new Perro("Golden " + raza) + +// Por si misma, la palabra implicit no cambia el comportamiento de un valor, +// así que estos valores pueden ser usados como siempre. +miEnteroImplicito + 2 // => 102 +miFunciónImplicita("Pitbull").raza // => "Golden Pitbull" + +// La diferencia es que estos valores ahora pueden ser usados cuando otra pieza de código +// necesite un valor implicito. Una situación así puede darse con argumentos implicitos de función: +def enviaSaludos(aQuien: String)(implicit cuantos: Int) = + s"Hola $aQuien, $cuantos saludos a ti y a los tuyos!" + +// Si proporcionamos un valor para "cuantos", la función se comporta como siempre +enviaSaludos("John")(1000) // => "Hola John, 1000 saludos a ti y a los tuyos!" + +// Pero si omitimos el parámetro implicito, un valor implicito del mismo tipo es usado, +// en este caso, "miEnteroImplicito": +enviaSaludos("Jane") // => "Hello Jane, 100 blessings to you and yours!" + +// Los parámetros de función implicit nos permiten simular clases tipo en otros lenguajes funcionales. +// Es usado tan a menudo que tiene su propio atajo. Las dos siguientes lineas significan lo mismo: +// def foo[T](implicit c: C[T]) = ... +// def foo[T : C] = ... + + +// Otra situación en la que el compilador busca un implicit es si tienes +// obj.método(...) +// pero "obj" no tiene "método" como un método. En este caso, si hay una conversión +// implicita de tipo A => B, donde A es el tipo de obj y B tiene un método llamado +// "método", esa conversión es aplicada. Así que teniendo miFunciónImplicita, podemos decir: +"Retriever".raza // => "Golden Retriever" +"Sheperd".ladra // => "Woof, woof!" + +// Aquí la cadena es convertida primero a Perro usando nuestra función miFunciónImplicita, +// y entonces el método apropiado es llamado. Esta es una herramienta extremadamente poderosa +// pero de nuevo, no puede usarse con ligereza. De hecho, cuando definiste la función implicita, +// tu compilador debería haber mostrado una advertencia, diciendo que no deberías hacer esto +// a no ser que realmente sepas lo que estás haciendo. + +///////////////////////////////////////////////// +// 9. Misc +///////////////////////////////////////////////// + +// Importando cosas +import scala.collection.immutable.List + +// Importando todos los "sub paquetes" +import scala.collection.immutable._ + +// Importando multiples clases en una línea +import scala.collection.immutable.{List, Map} + +// Renombrar un import usando '=>' +import scala.collection.immutable.{List => ImmutableList} + +// Importar todas las clases, excepto algunas. La siguiente linea excluye Map y Set: +import scala.collection.immutable.{Map => _, Set => _, _} + +// Las clases de Java pueden ser importadas también con sintaxis de Scala: +import java.swing.{JFrame, JWindow} + +// El punto de entrada de tus programas está definido en un fichero scala usando un object, +// con un solo método, main: +object Application { + def main(args: Array[String]): Unit = { + // Aquí va tu código. + } +} + +// Los ficheros pueden contener multiples clases y objetos. Compila con scalac + + +// Salida y entrada + +// Leer un fichero línea por línea +import scala.io.Source +for(line <- Source.fromFile("miarchivo.txt").getLines()) + println(line) + +// Para escribir un archivo usa el PrintWriter de Java +val writer = new PrintWriter("miarchivo.txt") +writer.write("Escribiendo linea por linea" + util.Properties.lineSeparator) +writer.write("Otra linea" + util.Properties.lineSeparator) +writer.close() + +``` + +## Más recursos + +* [Scala para los impacientes](http://horstmann.com/scala/) +* [Escuela de Scala en Twitter](http://twitter.github.io/scala_school/) +* [La documentación de Scala](http://docs.scala-lang.org/) +* [Prueba Scala en tu navegador](http://scalatutorials.com/tour/) +* Unete al [grupo de usuarios de Scala](https://groups.google.com/forum/#!forum/scala-user) diff --git a/fr-fr/erlang-fr.html.markdown b/fr-fr/erlang-fr.html.markdown index 55453c56..1073d6ad 100644 --- a/fr-fr/erlang-fr.html.markdown +++ b/fr-fr/erlang-fr.html.markdown @@ -28,7 +28,7 @@ lang: fr-fr %% 1. Variables et filtrage par motif %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -(L'équivalent anglais de *filtrage par motif* est *pattern patching*.) +(L'équivalent anglais de *filtrage par motif* est *pattern matching*.) Nb = 42. % Chaque nom de variable doit commencer par une lettre majuscule. @@ -64,7 +64,7 @@ Point = {point, 10, 45}. {point, X, Y} = Point. % X = 10, Y = 45 % On peut utiliser `_` comme caractère joker pour les variables qui ne nous -% intéressent pas. Le symbol `_` est appelé variable muette. Contrairement +% intéressent pas. Le symbole `_` est appelé variable muette. Contrairement % aux variables normales, de multiples apparitions de `_` dans un même motif % ne lient pas nécessairement à la même valeur. Personne = {personne, {nom, {prenom, joe}, {famille, armstrong}}, diff --git a/fsharp.html.markdown b/fsharp.html.markdown index 59461eed..24044d76 100644 --- a/fsharp.html.markdown +++ b/fsharp.html.markdown @@ -194,7 +194,7 @@ module ListExamples = | [] -> printfn "the list is empty" | [first] -> printfn "the list has one element %A " first | [first; second] -> printfn "list is %A and %A" first second - | _ -> printfn "the list has more than two elements" + | first :: _ -> printfn "the list has more than two elements, first element %A" first listMatcher [1; 2; 3; 4] listMatcher [1; 2] diff --git a/haxe.html.markdown b/haxe.html.markdown index f7633dbf..a31728e1 100644 --- a/haxe.html.markdown +++ b/haxe.html.markdown @@ -334,7 +334,7 @@ class LearnHaxe3 { Switch statements in Haxe are very powerful. In addition to working on basic values like strings and ints, they can also work on the generalized algebraic data types in enums (more on enums later). - Here's some basic value examples for now: + Here are some basic value examples for now: */ var my_dog_name = "fido"; var favorite_thing = ""; @@ -594,7 +594,7 @@ class ComplexEnumTest { public static function example() { var e1:ComplexEnum = IntEnum(4); // specifying the enum parameter // Now we can switch on the enum, as well as extract any parameters - // it might of had. + // it might have had. switch(e1) { case IntEnum(x) : trace('$x was the parameter passed to e1'); default: trace("Shouldn't be printed"); diff --git a/html.html.markdown b/html.html.markdown index f01f139c..b8212776 100644 --- a/html.html.markdown +++ b/html.html.markdown @@ -5,6 +5,7 @@ contributors: - ["Christophe THOMAS", "https://github.com/WinChris"] translators: - ["Robert Steed", "https://github.com/robochat"] + - ["Dimitri Kokkonis", "https://github.com/kokkonisd"] --- HTML stands for HyperText Markup Language. diff --git a/it-it/rust-it.html.markdown b/it-it/rust-it.html.markdown index 6b379f93..e4b7c33f 100644 --- a/it-it/rust-it.html.markdown +++ b/it-it/rust-it.html.markdown @@ -130,14 +130,14 @@ fn main() { ///////////// // Strutture - struct Point { + struct Punto { x: i32, y: i32, } let origine: Punto = Punto { x: 0, y: 0 }; - // Ana struct con campi senza nome, chiamata ‘tuple struct’ + // Una struct con campi senza nome, chiamata ‘tuple struct’ struct Punto2(i32, i32); let origine2 = Punto2(0, 0); diff --git a/ja-jp/asciidoc.html.markdown b/ja-jp/asciidoc.html.markdown new file mode 100644 index 00000000..7347589a --- /dev/null +++ b/ja-jp/asciidoc.html.markdown @@ -0,0 +1,135 @@ +--- +language: asciidoc +contributors: + - ["Ryan Mavilia", "http://unoriginality.rocks/"] + - ["Abel Salgado Romero", "https://twitter.com/abelsromero"] +translators: + - ["Ryota Kayanuma", "https://github.com/PicoSushi"] +filename: asciidoc-ja.md +lang: ja-jp +--- + +AsciiDocはMarkdownに似たマークアップ言語で、書籍の執筆からブログを書くことまでなんでも使うことができます。2002年、Stuart RackhamによりAsciiDocは作成され、シンプルでありつつも沢山のカスタマイズを可能にしています。 + +文書のヘッダー + +ヘッダーはオプションで、空行を含むことはできません。本文から1行以上の改行を開ける必要があります。 + +タイトルのみの例 + +``` += 文章タイトル + +文書の最初の行 +``` + +タイトルと著者 + +``` += 文書タイトル +文書 太郎 <first.last@learnxinyminutes.com> + +文書の開始 +``` + +複数の著者 + +``` += 文書タイトル +John Doe <john@go.com>; Jane Doe<jane@yo.com>; Black Beard <beardy@pirate.com> + +複数の著者による文書の始まり。 +``` + +版(著者の行を必要とします) + +``` += 第一版のタイトル +芋男 <chip@crunchy.com> +v1.0, 2016-01-13 + +このポテトについての文書は面白いです。 +``` + +段落 + +``` +段落は特別なことは不要です。 + +空行を段落の間に入れることで、段落を分けることができます。 + +折り返しをしたい場合、+ +を書くことで折り返せます! +``` + +文書の整形 + +``` +_アンダースコアで斜体になります。_ +*アスタリスクで太字になります。* +*_組み合わせると楽しい_* +`バッククォートで固定幅になります。` +`*太字の固定幅*` +``` + +節タイトル + +``` += Level 0 (文書のヘッダーにのみ使用してください) + +== Level 1 <h2> + +=== Level 2 <h3> + +==== Level 3 <h4> + +===== Level 4 <h5> + +``` + +リスト + +箇条書きリストを作るには、アスタリスクを使用してください。 + +``` +* foo +* bar +* baz +``` + +番号付きリストを作るには、ピリオドを使用してください。 + +``` +. item 1 +. item 2 +. item 3 +``` + +リストはアスタリスクやピリオドを追加することで5段階まで入れ子にできます。 + +``` +* foo 1 +** foo 2 +*** foo 3 +**** foo 4 +***** foo 5 + +. foo 1 +.. foo 2 +... foo 3 +.... foo 4 +..... foo 5 +``` + +## 補足資料 + +AsciiDocの文書を処理するツールは2種類あります。 + +1. [AsciiDoc](http://asciidoc.org/): オリジナルのPython実装で、Linuxで利用可能です。現在は開発されておらず、メンテナンスのみの状態です。 +2. [Asciidoctor](http://asciidoctor.org/): Rubyによる別実装で、JavaやJavascriptでも利用可能です。AsciiDocに新しい機能や出力形式を追加するため、現在活発に開発されています。 + +以下のリンクは `AsciiDoctor` 実装関連のものです。 + +* [Markdown - AsciiDoc syntax comparison](http://asciidoctor.org/docs/user-manual/#comparison-by-example): Common MarkdownとAsciidocの要素を並べて比較しています。 +* [Getting started](http://asciidoctor.org/docs/#get-started-with-asciidoctor): インストールから簡潔な文書を作るための簡単なガイドです。 +* [Asciidoctor User Manual](http://asciidoctor.org/docs/user-manual/): 文法のリファレンス、例、描画ツール、その他を含む完全なドキュメントです。 diff --git a/ja-jp/python3-jp.html.markdown b/ja-jp/python3-jp.html.markdown index 3b1a0d73..b9731411 100644 --- a/ja-jp/python3-jp.html.markdown +++ b/ja-jp/python3-jp.html.markdown @@ -6,13 +6,16 @@ contributors: - ["Andre Polykanine", "https://github.com/Oire"] - ["Zachary Ferguson", "http://github.com/zfergus2"] - ["evuez", "http://github.com/evuez"] + - ["Rommel Martinez", "https://ebzzry.io"] + - ["Roberto Fernandez Diaz", "https://github.com/robertofd1995"] translators: - ["kakakaya", "https://github.com/kakakaya"] + - ["Ryota Kayanuma", "https://github.com/PicoSushi"] filename: learnpython3-jp.py lang: ja-jp --- -90年代の初め、Guido Van RossumによってPythonは作成されました。現在となっては、最も有名な言語の1つです。 +90年代の初め、Guido van RossumによってPythonは作成されました。現在となっては、最も有名な言語の1つです。 私は構文の明快さによって、Pythonと恋に落ちました。 以下は基本的に実行可能な疑似コードです。 @@ -21,12 +24,11 @@ lang: ja-jp Note: この記事はPython 3に内容を絞っています。もし古いPython 2.7を学習したいなら、 [こちら](http://learnxinyminutes.com/docs/python/) をご確認下さい。 ```python - # 1行のコメントは番号記号(#)から始まります。 """ 複数行の文字は、"を3つ繋げることで 書くことができます。 - また、これはコメントとしてもよく使われます。 + また、これはドキュメントとしてもよく使われます。 """ #################################################### @@ -44,8 +46,8 @@ Note: この記事はPython 3に内容を絞っています。もし古いPython # 整数除算の結果は、正負に関わらず小数の切り捨てが行われます。 5 // 3 # => 1 -5.0 // 3.0 # => 1.0 # 浮動小数点でも同様に動作します。 -5 // 3 # => -2 +5.0 // 3.0 # => 1.0 # 浮動小数点でも同様に動作します。 -5.0 // 3.0 # => -2.0 # 除算の結果は常に浮動小数点になります。 @@ -55,7 +57,7 @@ Note: この記事はPython 3に内容を絞っています。もし古いPython 7 % 3 # => 1 # 冪乗 (x**y, x の y 乗) -2**4 # => 16 +2**3 # => 8 # 括弧により、計算の順番を優先させられます。 (1 + 3) * 2 # => 8 @@ -69,16 +71,28 @@ not True # => False not False # => True # ブール演算 -# 注意: "and" と "or" は小文字です +# 注意: "and" と "or" は小文字です。 True and False # => False False or True # => True -# 整数でブール演算をするときのメモ -0 and 2 # => 0 --5 or 0 # => -5 +# TrueとFalseは実際には1と0になるキーワードです。 +True + True # => 2 +True * 8 # => 8 +False - 5 # => -5 + +# 比較演算子はTrueとFalseを数値として扱います。 0 == False # => True -2 == True # => False 1 == True # => True +2 == True # => False +-5 != True # => True + +# bool論理演算子を整数に対して使うことで整数を真偽値に変換して評価できますが、キャストされていない値が +# bool(int)とビット演算子(& や |)を混同しないようにうにしましょう。 +bool(0) # => False +bool(4) # => True +bool(-6) # => True +0 and 2 # => 0 +-5 or 0 # => -5 # 値が等しいか確認するには == 1 == 1 # => True @@ -94,7 +108,11 @@ False or True # => True 2 <= 2 # => True 2 >= 2 # => True -# 比較は連結させられます! +# 値がある範囲の中にあるか調べる方法 +1 < 2 and 2 < 3 # => True +2 < 3 and 3 < 2 # => False + +# 連結させるともっと見やすくなります。 1 < 2 < 3 # => True 2 < 3 < 2 # => False @@ -115,7 +133,7 @@ b == a # => True, a と b が参照するオブジェクトの値 # 文字列も加算をすることができます!でも、あまり行わないように。 "Hello " + "world!" # => "Hello world!" -# '+' を使わなくても連結はできます。 +# '+' を使わなくても文字列リテラル(変数ではないもの)の連結ができます。 "Hello " "world!" # => "Hello world!" # 文字列は文字のリストであるかのように扱うことができます。 @@ -138,6 +156,12 @@ len("This is a string") # => 16 # 旧式のフォーマット方法を使うこともできます。 "%s can be %s the %s way" % ("Strings", "interpolated", "old") # => "Strings can be interpolated the old way" +# Python3.6以上では、f-stringsやフォーマット文字列を使ってフォーマットすることもできます。 +name = "Reiko" +f"She said her name is {name}." # => "She said her name is Reiko" + +# 基本的に、任意のPythonの文を中括弧に書くことができ、それは評価されて出力されます。 +f"{name} is {len(name)} characters long." # None はオブジェクトです(大文字からです!) None # => None @@ -170,7 +194,7 @@ print("Hello, World", end="!") # => Hello, World! input_string_var = input("Enter some data: ") # 入力を文字列として返します # Note: Python の初期のバージョンでは、 input() は raw_input() という名前で存在します。 -# 変数に代入する前に宣言する必要はありません。 +# Pythonでは変数の宣言は存在せず、代入のみです。 # 慣例的に、小文字でアンダースコア区切り ( lower_case_with_underscores ) の変数が使われます。 some_var = 5 some_var # => 5 @@ -207,10 +231,11 @@ li[-1] # => 3 li[4] # IndexError が発生します # スライス構文により範囲を参照できます。 +# 開始部分のインデックスに対応する部分は含まれますが、終了部分のインデックスに対応する部分は含まれません。 li[1:3] # => [2, 4] -# 先端を取り除く +# 先端を取り除いたリスト li[2:] # => [4, 3] -# 末尾を取り除く +# 末尾を取り除いたリスト li[:3] # => [1, 2, 4] # 1つ飛ばしで選択する li[::2] # =>[1, 4] @@ -272,7 +297,7 @@ a, b, c = (1, 2, 3) # a, b, c にはそれぞれ 1, 2, 3 が代入 # 拡張記法もあります。 a, *b, c = (1, 2, 3, 4) # a は 1 、 b は [2, 3] 、c は4 になります。 # 括弧を作成しなくてもデフォルトでタプルが作成されます。 -d, e, f = 4, 5, 6 +d, e, f = 4, 5, 6 # 4、5、6がそれぞれd、 e、 fに代入されます。 # 2つの変数を交換するのがどれほど簡単か見てみましょう。 e, d = d, e # d は 5 、 e は e になります。 @@ -293,14 +318,17 @@ filled_dict["one"] # => 1 # "keys()"により、全てのキーを反復可能な形式で取り出せます。 # これをリストにするために、"list()"で囲んでいます。これについては後程解説します。 -# Note: 辞書のキーの順番は考慮されていません。実行した結果がこれと異なる場合があります。 -list(filled_dict.keys()) # => ["three", "two", "one"] +# Note: Python3.7未満では、辞書のキーの順番は考慮されていません。実行した結果がこれと異なる場合があります。 +# しかし、Python3.7以降ではキーの挿入順を保つようになりました。 +list(filled_dict.keys()) # => ["three", "two", "one"] in Python <3.7 +list(filled_dict.keys()) # => ["one", "two", "three"] in Python 3.7+ + # "values()"により、全ての値を反復可能な形式で取り出せます。 # 前と同じように、これをリストにするために、"list()"で囲んでいます。 # Note: 辞書の値の順番は考慮されていません。実行した結果がこれと異なる場合があります。 -list(filled_dict.values()) # => [3, 2, 1] - +list(filled_dict.values()) # => [3, 2, 1] in Python <3.7 +list(filled_dict.values()) # => [1, 2, 3] in Python 3.7+ # "in" により、辞書のキーが存在するか確認できます。 "one" in filled_dict # => True @@ -322,7 +350,7 @@ filled_dict.setdefault("five", 6) # filled_dict["five"] は 5 のままです # 辞書にマップを追加する filled_dict.update({"four": 4}) # => {"one": 1, "two": 2, "three": 3, "four": 4} -# filled_dict["four"] = 4 # 辞書に追加する別の方法 +filled_dict["four"] = 4 # 辞書に追加する別の方法 # del により辞書からキーを削除できます。 del filled_dict["one"] # "one" キーを辞書から削除します。 @@ -341,11 +369,11 @@ some_set = {1, 1, 2, 2, 3, 4} # some_set is now {1, 2, 3, 4} invalid_set = {[1], 1} # => list はハッシュ化できないので、 TypeError が送出されます。 valid_set = {(1,), 1} -# 新しい値を集合にセットできます。 -filled_set = some_set - # 集合に新しい要素を追加できます。 +filled_set = some_set filled_set.add(5) # filled_set は {1, 2, 3, 4, 5} になりました。 +# 集合は重複した要素を持ちません。 +filled_set.add(5) # 以前の{1, 2, 3, 4, 5}のままです。 # & により、集合同士の共通部分が得られます。 other_set = {3, 4, 5, 6} @@ -378,7 +406,8 @@ filled_set | other_set # => {1, 2, 3, 4, 5, 6} # まずは変数を作りましょう。 some_var = 5 -# これはif文です。インデントがPythonでは特徴的ですね! +# これはif文です。Pythonではインデントが特徴的ですね! +# 規約ではタブではなく4つのスペースでインデントすることが推奨されています。 # 以下の例では"some_var is smaller than 10"と出力されます。 if some_var > 10: print("some_var is totally bigger than 10.") @@ -541,9 +570,9 @@ all_the_args(1, 2, a=3, b=4) prints: # * を使ってタプルを展開したり、 ** を使って辞書を展開できます。 args = (1, 2, 3, 4) kwargs = {"a": 3, "b": 4} -all_the_args(*args) # foo(1, 2, 3, 4) に対応します。 -all_the_args(**kwargs) # foo(a=3, b=4) に対応します。 -all_the_args(*args, **kwargs) # foo(1, 2, 3, 4, a=3, b=4) に対応します。 +all_the_args(*args) # all_the_args(1, 2, 3, 4) と等しいです。 +all_the_args(**kwargs) # all_the_args(a=3, b=4) と等しいです。 +all_the_args(*args, **kwargs) # all_the_args(1, 2, 3, 4, a=3, b=4) と等しいです。 # タプルで複数の値を返す @@ -646,7 +675,7 @@ dir(math) # 6. クラス #################################################### -# クラスを作成するために、"class"という演算子を使います。 +# クラスを作成するために、class文を使います。 class Human: # クラスの属性です。このクラスの全てのインスタンスで共有されます。 @@ -656,14 +685,14 @@ class Human: # 2つのアンダースコアがオブジェクトや属性の前後についているとき、これらはPythonによって利用され、 # ユーザーの名前空間には存在しないということに注意してください。 # __init__ や __str__ 、 __repr__ のようなメソッド(やオブジェクト、属性)は、 - # magic methods (または dunder methods)と呼ばれます。 - # このような名前を自分で発明しないほうがよいでしょう。 + # special methods (または dunder methods)と呼ばれます。 + # 同じような名前を自分で発明しないほうがよいでしょう。 def __init__(self, name): # 引数をインスタンスのname属性に設定します。 self.name = name # プロパティの初期化 - self.age = 0 + self._age = 0 # インスタンスメソッド。全てのメソッドは"self"を最初の引数に取ります。 def say(self, msg): @@ -686,6 +715,7 @@ class Human: # プロパティはgetterのようなものです。 # age() メソッドを同名の読取専用属性に変換します。 + # Pythonではわざわざgetterやsetterを書く必要はありません。 @property def age(self): return self._age @@ -720,24 +750,117 @@ if __name__ == '__main__': j.say(j.get_species()) # => "Joel: H. neanderthalensis" # スタティックメソッドを呼んでみましょう。 - print(Human.grunt()) # => "*grunt*" - print(i.grunt()) # => "*grunt*" + print(Human.grunt()) # => "*grunt*" + + # スタティックメソッドはインスタンスから呼ぶことはできません。 + # なぜならば、 i.grunt() は自動的に"self" ( i オブジェクト ) を引数として渡してしまうからです。 + print(i.grunt()) # => TypeError: grunt() takes 0 positional arguments but 1 was given # インスタンスのプロパティを更新してみましょう。 i.age = 42 # プロパティを取得してみましょう。 - i.say(i.age) # => 42 - j.say(j.age) # => 0 + i.say(i.age) # => "Ian: 42" + j.say(j.age) # => "Joel: 0" # プロパティを削除してみましょう。 del i.age # i.age # => AttributeError が発生します。 #################################################### -# 6.1 多重継承 +# 6.1 継承 +#################################################### +# 継承を行うことで、親クラスからメソッドと変数を継承する新しい子クラスを定義できます。 + +# 上記で定義されたHumanクラスを親クラス(基底クラス)として使い、Superheroという子クラスを定義します。 +# これは"species"、"name"や"age"といった変数や、"sing"や"grunt"のようなメソッドをHumanから継承しますが、 +# Superhero独自のプロパティを持つこともできます。 + +# ファイルを分割してモジュール化の利点を活用するために、上記のHumanクラスを独自のファイル、ここでは human.py に記述ましょう。 + +# 別のファイルから関数をインポートするには次の形式を利用してください: +# from "拡張子なしのファイル名" import "関数やクラス" + +from human import Human + + +# 親クラスを子クラスのパラメータとして指定します +class Superhero(Human): + + # もし子クラスが親クラスの全ての定義を変更なしで継承する場合、"pass"キーワードのみを書くだけで良いです。 + # しかし、今回は親クラスとは異なる子クラスを作成するので、今回は以下の通りコメントアウトしています。 + # pass + + # 子クラスは親クラスの属性を上書きできます。 + species = 'Superhuman' + + # 子クラスは親クラスのコンストラクタを引数含めて自動的に継承しますが、 + # 追加の引数や定義を行ってコンストラクタのようなメソッドを上書きすることもできます。 + # このコンストラクタは"name"引数を"Human"クラスから継承し、"superpower"と"movie"という引数を追加します。 + def __init__(self, name, movie=False, + superpowers=["super strength", "bulletproofing"]): + + # 追加のクラス属性を作成する + self.fictional = True + self.movie = movie + # デフォルト値は共有されるので、可変のデフォルト値には注意してください。 + self.superpowers = superpowers + + # "super"関数を使うと子クラスに上書きされた親クラスのメソッド(今回は "__init__")にアクセスできます。 + # これで、親クラスのコンストラクタを呼んでいます。 + super().__init__(name) + + # singメソッドを上書きし、 + def sing(self): + return 'Dun, dun, DUN!' + + # 追加のインスタンスメソッドを作成します。 + def boast(self): + for power in self.superpowers: + print("I wield the power of {pow}!".format(pow=power)) + + +if __name__ == '__main__': + sup = Superhero(name="Tick") + + # インスタンスの型を調べる + if isinstance(sup, Human): + print('I am human') + if type(sup) is Superhero: + print('I am a superhero') + + # getattr()とsuper()で使われるメソッドの解決順序を調べてみます。 + # この属性は動的であり、変更可能です。 + print(Superhero.__mro__) # => (<class '__main__.Superhero'>, + # => <class 'human.Human'>, <class 'object'>) + + # 親のメソッドを呼びだすものの、独自のクラス属性を参照します。 + print(sup.get_species()) # => Superhuman + + # 上書きされたメソッドを呼ぶ + print(sup.sing()) # => Dun, dun, DUN! + + # Humanのメソッドを呼ぶ + sup.say('Spoon') # => Tick: Spoon + + # Superhero限定のメソッドを呼ぶ + sup.boast() # => I wield the power of super strength! + # => I wield the power of bulletproofing! + + # 継承されたクラス属性 + sup.age = 31 + print(sup.age) # => 31 + + # Superhero限定の属性 + print('Am I Oscar eligible? ' + str(sup.movie)) + + + +#################################################### +# 6.2 多重継承 #################################################### # 別のクラスを定義します。 +# bat.py class Bat: species = 'Baty' @@ -759,31 +882,22 @@ if __name__ == '__main__': print(b.say('hello')) print(b.fly) -# ファイル単位のモジュール化を利用するために、上記のクラスを別々のファイルに配置することができます。 -# ここでは、human.pyとbat.pyを作成してみましょう。 - -# 他のファイルから関数をインポートするために、次のような形式を利用してください。 -# from "拡張子無しのファイル名" import "関数またはクラス" - # superhero.py -from human import Human +from superhero import Superhero from bat import Bat - -# BatmanはHumanとBatの両方を継承します。 -class Batman(Human, Bat): - - # Batmanは species のクラス属性に独自の値を持ちます。 - species = 'Superhero' +# BatmanをSuperheroとBatの両方を継承した子クラスとして定義します。 +class Batman(Superhero, Bat): def __init__(self, *args, **kwargs): # 通常、属性を継承するにはsuper()を呼び出します。 - # super(Batman, self).__init__(*args, **kwargs) + # super(Batman, self).__init__(*args, **kwargs) # しかし、ここでは多重継承を行っているので、 super() はMRO(メソッド解決順序)の次の基本クラスにのみ動作します。 # なので、全ての祖先に対して明示的に __init__ を呼ぶことにします。 # *args と **kwargs を使うことで、それぞれの継承元が # たまねぎの皮を剥がすごとく、引数を用いることができます。 - Human.__init__(self, 'anonymous', *args, **kwargs) + Superhero.__init__(self, 'anonymous', movie=True, + superpowers=['Wealthy'], *args, **kwargs) Bat.__init__(self, *args, can_fly=False, **kwargs) # 名前の属性の値を上書きします。 self.name = 'Sad Affleck' @@ -795,22 +909,18 @@ class Batman(Human, Bat): if __name__ == '__main__': sup = Batman() - # インスタンスの型を調べてみましょう。 - if isinstance(sup, Human): - print('I am human') - if isinstance(sup, Bat): - print('I am bat') - if type(sup) is Batman: - print('I am Batman') - # getattr() や super() の両方で使われるMROを取得します。 # この属性は動的であり、更新が可能です。 - print(Batman.__mro__) # => (<class '__main__.Batman'>, <class 'human.Human'>, <class 'bat.Bat'>, <class 'object'>) + print(Batman.__mro__) # => (<class '__main__.Batman'>, + # => <class 'superhero.Superhero'>, + # => <class 'human.Human'>, + # => <class 'bat.Bat'>, <class 'object'>) + # 親メソッドを呼び出しますが、独自のクラス属性を参照します。 - print(sup.get_species()) # => Superhero + print(sup.get_species()) # => Superhuman - # オーバーロードされたメソッドを呼び出します。 + # 上書きされたメソッドを呼び出します。 print(sup.sing()) # => nan nan nan nan nan batman! # 継承順により、Humanから継承されたメソッドを呼び出します。 @@ -821,10 +931,10 @@ if __name__ == '__main__': # 継承されたクラス属性 sup.age = 100 - print(sup.age) + print(sup.age) # => 100 # デフォルト値が上書きされて、2番目の先祖から継承された属性 - print('Can I fly? ' + str(sup.fly)) + print('Can I fly? ' + str(sup.fly)) # => Can I fly? False #################################################### diff --git a/kotlin.html.markdown b/kotlin.html.markdown index 9bc8b420..9336d217 100644 --- a/kotlin.html.markdown +++ b/kotlin.html.markdown @@ -109,7 +109,7 @@ fun helloWorld(val name : String) { /* When a function consists of a single expression then the curly brackets can - be omitted. The body is specified after a = symbol. + be omitted. The body is specified after the = symbol. */ fun odd(x: Int): Boolean = x % 2 == 1 println(odd(6)) // => false @@ -306,7 +306,7 @@ fun helloWorld(val name : String) { println(result) /* - We can check if an object is a particular type by using the "is" operator. + We can check if an object is of a particular type by using the "is" operator. If an object passes a type check then it can be used as that type without explicitly casting it. */ @@ -346,11 +346,6 @@ fun helloWorld(val name : String) { return this.filter {it != c} } println("Hello, world!".remove('l')) // => Heo, word! - - println(EnumExample.A) // => A - println(ObjectExample.hello()) // => hello - - testOperator() } // Enum classes are similar to Java enum types. @@ -358,6 +353,8 @@ enum class EnumExample { A, B, C } +fun printEnum() = println(EnumExample.A) // => A + /* The "object" keyword can be used to create singleton objects. We cannot instantiate it but we can refer to its unique instance by its name. @@ -367,11 +364,18 @@ object ObjectExample { fun hello(): String { return "hello" } + + override fun toString(): String { + return "Hello, it's me, ${ObjectExample::class.simpleName}" + } } -fun useObject() { - ObjectExample.hello() - val someRef: Any = ObjectExample // we use objects name just as is + +fun useSingletonObject() { + println(ObjectExample.hello()) // => hello + // In Kotlin, "Any" is the root of the class hierarchy, just like "Object" is in Java + val someRef: Any = ObjectExample + println(someRef) // => Hello, it's me, ObjectExample } @@ -381,69 +385,54 @@ throws an exception if the value is null. var b: String? = "abc" val l = b!!.length -/* You can add many custom operations using symbol like +, to particular instance -by overloading the built-in kotlin operator, using "operator" keyword - -below is the sample class to add some operator, and the most basic example -*/ -data class SomeClass(var savedValue: Int = 0) +data class Counter(var value: Int) { + // overload Counter += Int + operator fun plusAssign(increment: Int) { + this.value += increment + } -// instance += valueToAdd -operator fun SomeClass.plusAssign(valueToAdd: Int) { - this.savedValue += valueToAdd -} + // overload Counter++ and ++Counter + operator fun inc() = Counter(value + 1) -// -instance -operator fun SomeClass.unaryMinus() = SomeClass(-this.savedValue) + // overload Counter + Counter + operator fun plus(other: Counter) = Counter(this.value + other.value) -// ++instance or instance++ -operator fun SomeClass.inc() = SomeClass(this.savedValue + 1) + // overload Counter * Counter + operator fun times(other: Counter) = Counter(this.value * other.value) -// instance * other -operator fun SomeClass.times(other: SomeClass) = - SomeClass(this.savedValue * other.savedValue) + // overload Counter * Int + operator fun times(value: Int) = Counter(this.value * value) -// an overload for multiply -operator fun SomeClass.times(value: Int) = SomeClass(this.savedValue * value) + // overload Counter in Counter + operator fun contains(other: Counter) = other.value == this.value -// other in instance -operator fun SomeClass.contains(other: SomeClass) = - other.savedValue == this.savedValue + // overload Counter[Int] = Int + operator fun set(index: Int, value: Int) { + this.value = index + value + } -// instance[dummyIndex] = valueToSet -operator fun SomeClass.set(dummyIndex: Int, valueToSet: Int) { - this.savedValue = valueToSet + dummyIndex -} + // overload Counter instance invocation + operator fun invoke() = println("The value of the counter is $value") -// instance() -operator fun SomeClass.invoke() { - println("instance invoked by invoker") } - -/* return type must be Integer, -so that, it can be translated to "returned value" compareTo 0 - -for equality (==,!=) using operator will violates overloading equals function, -since it is already defined in Any class -*/ -operator fun SomeClass.compareTo(other: SomeClass) = - this.savedValue - other.savedValue - -fun testOperator() { - var x = SomeClass(4) - - println(x) // => "SomeClass(savedValue=4)" - x += 10 - println(x) // => "SomeClass(savedValue=14)" - println(-x) // => "SomeClass(savedValue=-14)" - println(++x) // => "SomeClass(savedValue=15)" - println(x * SomeClass(3)) // => "SomeClass(savedValue=45)" - println(x * 2) // => "SomeClass(savedValue=30)" - println(SomeClass(15) in x) // => true - x[2] = 10 - println(x) // => "SomeClass(savedValue=12)" - x() // => "instance invoked by invoker" - println(x >= 15) // => false +/* You can also overload operators through an extension methods */ +// overload -Counter +operator fun Counter.unaryMinus() = Counter(-this.value) + +fun operatorOverloadingDemo() { + var counter1 = Counter(0) + var counter2 = Counter(5) + counter1 += 7 + println(counter1) // => Counter(value=7) + println(counter1 + counter2) // => Counter(value=12) + println(counter1 * counter2) // => Counter(value=35) + println(counter2 * 2) // => Counter(value=10) + println(counter1 in Counter(5)) // => false + println(counter1 in Counter(7)) // => true + counter1[26] = 10 + println(counter1) // => Counter(value=36) + counter1() // => The value of the counter is 36 + println(-counter2) // => Counter(value=-5) } ``` diff --git a/linker.html.markdown b/linker.html.markdown new file mode 100644 index 00000000..ebe6233d --- /dev/null +++ b/linker.html.markdown @@ -0,0 +1,9 @@ +--- +category: tool +tool: linker +contributors: + - ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"] +--- + +This article is available in [Russian](http://localhost:4567/docs/ru-ru/linker-ru/). + diff --git a/opengl.html.markdown b/opengl.html.markdown new file mode 100644 index 00000000..83ace3e8 --- /dev/null +++ b/opengl.html.markdown @@ -0,0 +1,765 @@ +---
+category: tool
+tool: OpenGL
+filename: learnopengl.cpp
+contributors:
+ - ["Simon Deitermann", "s.f.deitermann@t-online.de"]
+---
+
+**Open Graphics Library** (**OpenGL**) is a cross-language cross-platform application programming interface
+(API) for rendering 2D computer graphics and 3D vector graphics.<sup>[1]</sup> In this tutorial we will be
+focusing on modern OpenGL from 3.3 and above, ignoring "immediate-mode", Displaylists and
+VBO's without use of Shaders.
+I will be using C++ with SFML for window, image and context creation aswell as GLEW
+for modern OpenGL extensions, though there are many other librarys available.
+
+```cpp
+// Creating an SFML window and OpenGL basic setup.
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include <SFML/Graphics.h>
+#include <iostream>
+
+int main() {
+ // First we tell SFML how to setup our OpenGL context.
+ sf::ContextSettings context{ 24, // depth buffer bits
+ 8, // stencil buffer bits
+ 4, // MSAA samples
+ 3, // major opengl version
+ 3 }; // minor opengl version
+ // Now we create the window, enable VSync
+ // and set the window active for OpenGL.
+ sf::Window window{ sf::VideoMode{ 1024, 768 },
+ "opengl window",
+ sf::Style::Default,
+ context };
+ window.setVerticalSyncEnabled(true);
+ window.setActive(true);
+ // After that we initialise GLEW and check if an error occured.
+ GLenum error;
+ glewExperimental = GL_TRUE;
+ if ((err = glewInit()) != GLEW_OK)
+ std::cout << glewGetErrorString(err) << std::endl;
+ // Here we set the color glClear will clear the buffers with.
+ glClearColor(0.0f, // red
+ 0.0f, // green
+ 0.0f, // blue
+ 1.0f); // alpha
+ // Now we can start the event loop, poll for events and draw objects.
+ sf::Event event{ };
+ while (window.isOpen()) {
+ while (window.pollEvent(event)) {
+ if (event.type == sf::Event::Closed)
+ window.close;
+ }
+ // Tell OpenGL to clear the color buffer
+ // and the depth buffer, this will clear our window.
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ // Flip front- and backbuffer.
+ window.display();
+ }
+ return 0;
+}
+```
+
+## Loading Shaders
+
+After creating a window and our event loop we should create a function,
+that sets up our shader program.
+
+```cpp
+GLuint createShaderProgram(const std::string& vertexShaderPath,
+ const std::string& fragmentShaderPath) {
+ // Load the vertex shader source.
+ std::stringstream ss{ };
+ std::string vertexShaderSource{ };
+ std::string fragmentShaderSource{ };
+ std::ifstream file{ vertexShaderPath };
+ if (file.is_open()) {
+ ss << file.rdbuf();
+ vertexShaderSource = ss.str();
+ file.close();
+ }
+ // Clear the stringstream and load the fragment shader source.
+ ss.str(std::string{ });
+ file.open(fragmentShaderPath);
+ if (file.is_open()) {
+ ss << file.rdbuf();
+ fragmentShaderSource = ss.str();
+ file.close();
+ }
+ // Create the program.
+ GLuint program = glCreateProgram();
+ // Create the shaders.
+ GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
+ GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
+ // Now we can load the shader source into the shader objects and compile them.
+ // Because glShaderSource() wants a const char* const*,
+ // we must first create a const char* and then pass the reference.
+ const char* cVertexSource = vertexShaderSource.c_str();
+ glShaderSource(vertexShader, // shader
+ 1, // number of strings
+ &cVertexSource, // strings
+ nullptr); // length of strings (nullptr for 1)
+ glCompileShader(vertexShader);
+ // Now we have to do the same for the fragment shader.
+ const char* cFragmentSource = fragmentShaderSource.c_str();
+ glShaderSource(fragmentShader, 1, &cFragmentSource, nullptr);
+ glCompileShader(fragmentShader);
+ // After attaching the source and compiling the shaders,
+ // we attach them to the program;
+ glAttachShader(program, vertexShader);
+ glAttachShader(program, fragmentShader);
+ glLinkProgram(program);
+ // After linking the shaders we should detach and delete
+ // them to prevent memory leak.
+ glDetachShader(program, vertexShader);
+ glDetachShader(program, fragmentShader);
+ glDeleteShader(vertexShader);
+ glDeleteShader(fragmentShader);
+ // With everything done we can return the completed program.
+ return program;
+}
+```
+
+If you want to check the compilation log you can add the following between <code>glCompileShader()</code> and <code>glAttachShader()</code>.
+
+```cpp
+GLint logSize = 0;
+std::vector<GLchar> logText{ };
+glGetShaderiv(vertexShader, // shader
+ GL_INFO_LOG_LENGTH, // requested parameter
+ &logSize); // return object
+if (logSize > 0) {
+ logText.resize(logSize);
+ glGetShaderInfoLog(vertexShader, // shader
+ logSize, // buffer length
+ &logSize, // returned length
+ logText.data()); // buffer
+ std::cout << logText.data() << std::endl;
+}
+```
+
+The same is possibile after <code>glLinkProgram()</code>, just replace <code>glGetShaderiv()</code> with <code>glGetProgramiv()</code>
+and <code>glGetShaderInfoLog()</code> with <code>glGetProgramInfoLog()</code>.
+
+```cpp
+// Now we can create a shader program with a vertex and a fragment shader.
+// ...
+glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+
+GLuint program = createShaderProgram("vertex.glsl", "fragment.glsl");
+
+sf::Event event{ };
+// ...
+// We also have to delete the program at the end of the application.
+// ...
+ }
+ glDeleteProgram(program);
+ return 0;
+}
+// ...
+```
+
+Ofcourse we have to create the vertex and fragment shader before we can load them,
+so lets create two basic shaders.
+
+**Vertex Shader**
+
+```glsl
+// Declare which version of GLSL we use.
+// Here we declare, that we want to use the OpenGL 3.3 version of GLSL.
+#version 330 core
+// At attribute location 0 we want an input variable of type vec3,
+// that contains the position of the vertex.
+// Setting the location is optional, if you don't set it you can ask for the
+// location with glGetAttribLocation().
+layout(location = 0) in vec3 position;
+// Every shader starts in it's main function.
+void main() {
+ // gl_Position is a predefined variable that holds
+ // the final vertex position.
+ // It consists of a x, y, z and w coordinate.
+ gl_Position = vec4(position, 1.0);
+}
+```
+
+**Fragment Shader**
+
+```glsl
+#version 330 core
+// The fragment shader does not have a predefined variable for
+// the vertex color, so we have to define a output vec4,
+// that holds the final vertex color.
+out vec4 outColor;
+
+void main() {
+ // We simply set the ouput color to red.
+ // The parameters are red, green, blue and alpha.
+ outColor = vec4(1.0, 0.0, 0.0, 1.0);
+}
+```
+
+## VAO and VBO
+Now we need to define some vertex position we can pass to our shaders. Lets define a simple 2D quad.
+
+```cpp
+// The vertex data is defined in a counter-clockwise way,
+// as this is the default front face.
+std::vector<float> vertexData {
+ -0.5f, 0.5f, 0.0f,
+ -0.5f, -0.5f, 0.0f,
+ 0.5f, -0.5f, 0.0f,
+ 0.5f, 0.5f, 0.0f
+};
+// If you want to use a clockwise definition, you can simply call
+glFrontFace(GL_CW);
+// Next we need to define a Vertex Array Object (VAO).
+// The VAO stores the current state while its active.
+GLuint vao = 0;
+glGenVertexArrays(1, &vao);
+glBindVertexArray(vao);
+// With the VAO active we can now create a Vertex Buffer Object (VBO).
+// The VBO stores our vertex data.
+GLuint vbo = 0;
+glGenBuffers(1, &vbo);
+glBindBuffer(GL_ARRAY_BUFFER, vbo);
+// For reading and copying there are also GL_*_READ and GL_*_COPY,
+// if your data changes more often use GL_DYNAMIC_* or GL_STREAM_*.
+glBufferData(GL_ARRAY_BUFFER, // target buffer
+ sizeof(vertexData[0]) * vertexData.size(), // size
+ vertexData.data(), // data
+ GL_STATIC_DRAW); // usage
+// After filling the VBO link it to the location 0 in our vertex shader,
+// which holds the vertex position.
+// ...
+// To ask for the attibute location, if you haven't set it:
+GLint posLocation = glGetAttribLocation(program, "position");
+// ..
+glEnableVertexAttribArray(0);
+glVertexAttribPointer(0, 3, // location and size
+ GL_FLOAT, // type of data
+ GL_FALSE, // normalized (always false for floats)
+ 0, // stride (interleaved arrays)
+ nullptr); // offset (interleaved arrays)
+// Everything should now be saved in our VAO and we can unbind it and the VBO.
+glBindVertexArray(0);
+glBindBuffer(GL_ARRAY_BUFFER, 0);
+// Now we can draw the vertex data in our render loop.
+// ...
+glClear(GL_COLOR_BUFFER_BIT);
+// Tell OpenGL we want to use our shader program.
+glUseProgram(program);
+// Binding the VAO loads the data we need.
+glBindVertexArray(vao);
+// We want to draw a quad starting at index 0 of the VBO using 4 indices.
+glDrawArrays(GL_QUADS, 0, 4);
+glBindVertexArray(0);
+window.display();
+// ...
+// Ofcource we have to delete the allocated memory for the VAO and VBO at
+// the end of our application.
+// ...
+glDeleteBuffers(1, &vbo);
+glDeleteVertexArrays(1, &vao);
+glDeleteProgram(program);
+return 0;
+// ...
+```
+
+You can find the current code here: [OpenGL - 1](https://pastebin.com/W8jdmVHD).
+
+## More VBO's and Color
+Let's create another VBO for some colors.
+
+```cpp
+std::vector<float> colorData {
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f
+};
+```
+
+Next we can simply change some previous parameters to create a second VBO for our colors.
+
+```cpp
+// ...
+GLuint vbo[2];
+glGenBuffers(2, vbo);
+glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
+// ...
+glDeleteBuffers(2, vbo);
+/ ...
+// With these changes made we now have to load our color data into the new VBO
+// ...
+glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
+
+glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
+glBufferData(GL_ARRAY_BUFFER, sizeof(colorData[0]) * colorData.size(),
+ colorData.data(), GL_STATIC_DRAW);
+glEnableVertexAttribArray(1);
+glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
+
+glBindVertexArray(0);
+// ...
+```
+
+Next we have to change our vertex shader to pass the color data to the fragment shader.<br>
+**Vertex Shader**
+
+```glsl
+#version 330 core
+
+layout(location = 0) in vec3 position;
+// The new location has to differ from any other input variable.
+// It is the same index we need to pass to
+// glEnableVertexAttribArray() and glVertexAttribPointer().
+layout(location = 1) in vec3 color;
+
+out vec3 fColor;
+
+void main() {
+ fColor = color;
+ gl_Position = vec4(position, 1.0);
+}
+```
+
+**Fragment Shader**
+
+```glsl
+#version 330 core
+
+in vec3 fColor;
+
+out vec4 outColor;
+
+void main() {
+ outColor = vec4(fColor, 1.0);
+}
+```
+
+We define a new input variable ```color``` which represents our color data, this data
+is passed on to ```fColor```, which is an output variable of our vertex shader and
+becomes an input variable for our fragment shader.
+It is imporatant that variables passed between shaders have the exact same name
+and type.
+
+## Handling VBO's
+
+```cpp
+// If you want to completely clear and refill a VBO use glBufferData(),
+// just like we did before.
+// ...
+// There are two mains ways to update a subset of a VBO's data.
+// To update a VBO with existing data
+std::vector<float> newSubData {
+ -0.25f, 0.5f, 0.0f
+};
+glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
+glBufferSubData(GL_ARRAY_BUFFER, // target buffer
+ 0, // offset
+ sizeof(newSubData[0]) * newSubData.size(), // size
+ newSubData.data()); // data
+// This would update the first three values in our vbo[0] buffer.
+// If you want to update starting at a specific location just set the second
+// parameter to that value and multiply by the types size.
+// ...
+// If you are streaming data, for example from a file,
+// it is faster to directly pass the data to the buffer.
+// Other access values are GL_READ_ONLY and GL_READ_WRITE.
+glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
+// You can static_cast<float*>() the void* to be more safe.
+void* Ptr = glMapBuffer(GL_ARRAY_BUFFER, // buffer to map
+ GL_WRITE_ONLY); // access to buffer
+memcpy(Ptr, newSubData.data(), sizeof(newSubData[0]) * newSubData.size());
+// To copy to a specific location add a destination offset to memcpy().
+glUnmapBuffer(GL_ARRAY_BUFFER);
+// ...
+// There is also a way to copy data from one buffer to another,
+// If we have two VBO's vbo[0] and vbo[1], we can copy like so
+// You can also read from GL_ARRAY_BUFFER.
+glBindBuffer(GL_COPY_READ_BUFFER, vbo[0]);
+// GL_COPY_READ_BUFFER and GL_COPY_WRITE_BUFFER are specifically for
+// copying buffer data.
+glBindBuffer(GL_COPY_WRITE_BUFFER, vbo[1]);
+glCopyBufferSubData(GL_COPY_READ_BUFFER, // read buffer
+ GL_COPY_WRITE_BUFFER, // write buffer
+ 0, 0, // read and write offset
+ sizeof(vbo[0]) * 3); // copy size
+// This will copy the first three elements from vbo[0] to vbo[1].
+```
+
+## Uniforms
+
+**Fragment Shader**
+
+```glsl
+// Uniforms are variables like in and out, however,
+// we can change them easily by passing new values with glUniform().
+// Lets define a time variable in our fragment shader.
+#version 330 core
+// Unlike a in/out variable we can use a uniform in every shader,
+// without the need to pass it to the next one, they are global.
+// Don't use locations already used for attributes!
+// Uniform layout locations require OpenGL 4.3!
+layout(location = 10) uniform float time;
+
+in vec3 fColor;
+
+out vec4 outColor;
+
+void main() {
+ // Create a sine wave from 0 to 1 based on the time passed to the shader.
+ float factor = (sin(time * 2) + 1) / 2;
+ outColor = vec4(fColor.r * factor, fColor.g * factor, fColor.b * factor, 1.0);
+}
+```
+
+Back to our source code.
+
+```cpp
+// If we haven't set the layout location, we can ask for it.
+GLint timeLocation = glGetUniformLocation(program, "time");
+// ...
+// Also we should define a Timer counting the current time.
+sf::Clock clock{ };
+// In out render loop we can now update the uniform every frame.
+ // ...
+ window.display();
+ glUniform1f(10, // location
+ clock.getElapsedTime().asSeconds()); // data
+}
+// ...
+```
+
+With the time getting updated every frame the quad should now be changing from
+fully colored to pitch black.
+There are different types of glUniform() you can find simple documentation here:
+[glUniform - OpenGL Refpage](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glUniform.xhtml)
+
+## Indexing and IBO's
+
+Element Array Buffers or more commonly Index Buffer Objects (IBO) allow us to use the
+same vertex data again which makes drawing a lot easier and faster. here's an example:
+
+```cpp
+// Lets create a quad from two rectangles.
+// We can simply use the old vertex data from before.
+// First, we have to create the IBO.
+// The index is referring to the first declaration in the VBO.
+std::vector<unsigned int> iboData {
+ 0, 1, 2,
+ 0, 2, 3
+};
+// That's it, as you can see we could reuse 0 - the top left
+// and 2 - the bottom right.
+// Now that we have our data, we have to fill it into a buffer.
+// Note that this has to happen between the two glBindVertexArray() calls,
+// so it gets saved into the VAO.
+GLuint ibo = 0;
+glGenBufferrs(1, &ibo);
+glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
+glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(iboData[0]) * iboData.size(),
+ iboData.data(), GL_STATIC_DRAW);
+// Next in our render loop, we replace glDrawArrays() with:
+glDrawElements(GL_TRIANGLES, iboData.size(), GL_UNSINGED_INT, nullptr);
+// Remember to delete the allocated memory for the IBO.
+```
+
+You can find the current code here: [OpenGL - 2](https://pastebin.com/R3Z9ACDE).
+
+## Textures
+
+To load out texture we first need a library that loads the data, for simplicity I will be
+using SFML, however there are a lot of librarys for loading image data.
+
+```cpp
+// Lets save we have a texture called "my_tex.tga", we can load it with:
+sf::Image image;
+image.loadFromFile("my_tex.tga");
+// We have to flip the texture around the y-Axis, because OpenGL's texture
+// origin is the bottom left corner, not the top left.
+image.flipVertically();
+// After loading it we have to create a OpenGL texture.
+GLuint texture = 0;
+glGenTextures(1, &texture);
+glBindTexture(GL_TEXTURE_2D, texture);
+// Specify what happens when the coordinates are out of range.
+glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+// Specify the filtering if the object is very large.
+glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+// Load the image data to the texture.
+glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.getSize().x, image.getSize().y,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, image.getPixelsPtr());
+// Unbind the texture to prevent modifications.
+glBindTexture(GL_TEXTURE_2D, 0);
+// Delete the texture at the end of the application.
+// ...
+glDeleteTextures(1, &texture);
+```
+
+Ofcourse there are more texture formats than only 2D textures,
+You can find further information on parameters here:
+[glBindTexture - OpenGL Refpage](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBindTexture.xhtml)<br>
+[glTexImage2D - OpenGL Refpage](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml)<br>
+[glTexParameter - OpenGL Refpage](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexParameter.xhtml)<br>
+
+```cpp
+// With the texture created, we now have to specify the UV,
+// or in OpenGL terms ST coordinates.
+std::vector<float> texCoords {
+ // The texture coordinates have to match the triangles/quad
+ // definition.
+ 0.0f, 1.0f, // start at top-left
+ 0.0f, 0.0f, // go round counter-clockwise
+ 1.0f, 0.0f,
+ 1.0f, 1.0f // end at top-right
+};
+// Now we increase the VBO's size again just like we did for the colors.
+// ...
+GLuint vbo[3];
+glGenBuffers(3, vbo);
+// ...
+glDeleteBuffers(3, vbo);
+// ...
+// Load the texture coordinates into the new buffer.
+glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
+glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords[0]) * texCoords.size(),
+ texCoords.data(), GL_STATIC_DRAW);
+glEnableVertexAttribArray(2);
+glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
+// Because the VAO does not store the texture we have to bind it before drawing.
+// ...
+glBindVertexArray(vao);
+glBindTexture(GL_TEXTURE_2D, texture);
+glDrawElements(GL_TRIANGLES, iboData.size(), GL_UNSINGED_INT, nullptr);
+// ...
+```
+
+Change the shaders to pass the data to the fragment shader.<br>
+
+**Vertex Shader**
+
+```glsl
+#version 330 core
+
+layout(location = 0) in vec3 position;
+layout(location = 1) in vec3 color;
+layout(location = 2) in vec2 texCoords;
+
+out vec3 fColor;
+out vec2 fTexCoords;
+
+void main() {
+ fColor = color;
+ fTexCoords = texCoords;
+ gl_Position = vec4(position, 1.0);
+}
+```
+
+**Fragment Shader**
+
+```glsl
+#version 330 core
+// sampler2D represents our 2D texture.
+uniform sampler2D tex;
+uniform float time;
+
+in vec3 fColor;
+in vec2 fTexCoords;
+
+out vec4 outColor;
+
+void main() {
+ // texture() loads the current texure data at the specified texture coords,
+ // then we can simply multiply them by our color.
+ outColor = texture(tex, fTexCoords) * vec4(fColor, 1.0);
+}
+```
+
+You can find the current code here: [OpenGL - 3](https://pastebin.com/u3bcwM6q)
+
+## Matrix Transformation
+
+**Vertex Shader**
+
+```glsl
+#version 330 core
+
+layout(location = 0) in vec3 position;
+layout(location = 1) in vec3 color;
+layout(location = 2) in vec2 texCoords;
+// Create 2 4x4 matricies, 1 for the projection matrix
+// and 1 for the model matrix.
+// Because we draw in a static scene, we don't need a view matrix.
+uniform mat4 projection;
+uniform mat4 model;
+
+out vec3 fColor;
+out vec2 fTexCoords;
+
+void main() {
+ fColor = color;
+ fTexCoords = texCoords;
+ // Multiplay the position by the model matrix and then by the
+ // projection matrix.
+ // Beware order of multiplication for matricies!
+ gl_Position = projection * model * vec4(position, 1.0);
+}
+```
+
+In our source we now need to change the vertex data, create a model- and a projection matrix.
+
+```cpp
+// The new vertex data, counter-clockwise declaration.
+std::vector<float> vertexData {
+ 0.0f, 1.0f, 0.0f, // top left
+ 0.0f, 0.0f, 0.0f, // bottom left
+ 1.0f, 0.0f, 0.0f, // bottom right
+ 1.0f, 1.0f, 0.0f // top right
+};
+// Request the location of our matricies.
+GLint projectionLocation = glGetUniformLocation(program, "projection");
+GLint modelLocation = glGetUniformLocation(program, "model");
+// Declaring the matricies.
+// Orthogonal matrix for a 1024x768 window.
+std::vector<float> projection {
+ 0.001953f, 0.0f, 0.0f, 0.0f,
+ 0.0f, -0.002604f, 0.0f, 0.0f,
+ 0.0f, 0.0f, -1.0f, 0.0f,
+ -1.0f, 1.0f, 0.0f, 1.0f
+};
+// Model matrix translating to x 50, y 50
+// and scaling to x 200, y 200.
+std::vector<float> model {
+ 200.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 200.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 50.0f, 50.0f, 0.0f, 1.0f
+};
+// Now we can send our calculated matricies to the program.
+glUseProgram(program);
+glUniformMatrix4fv(projectionLocation, // location
+ 1, // count
+ GL_FALSE, // transpose the matrix
+ projection.data()); // data
+glUniformMatrix4fv(modelLocation, 1, GL_FALSE, model.data());
+glUseProgram(0);
+// The glUniform*() calls have to be done, while the program is bound.
+```
+
+The application should now display the texture at the defined position and size.<br>
+You can find the current code here: [OpenGL - 4](https://pastebin.com/9ahpFLkY)
+
+```cpp
+// There are many math librarys for OpenGL, which create
+// matricies and vectors, the most used in C++ is glm (OpenGL Mathematics).
+// Its a header only library.
+// The same code using glm would look like:
+glm::mat4 projection{ glm::ortho(0.0f, 1024.0f, 768.0f, 0.0f) };
+glUniformMatrix4fv(projectionLocation, 1, GL_FALSE,
+ glm::value_ptr(projection));
+// Initialise the model matrix to the identity matrix, otherwise every
+// multiplication would be 0.
+glm::mat4 model{ 1.0f };
+model = glm::translate(model, glm::vec3{ 50.0f, 50.0f, 0.0f });
+model = glm::scale(model, glm::vec3{ 200.0f, 200.0f, 0.0f });
+glUniformMatrix4fv(modelLocation, 1, GL_FALSE,
+ glm::value_ptr(model));
+```
+
+## Geometry Shader
+
+Gemoetry shaders were introduced in OpenGL 3.2, they can produce vertices
+that are send to the rasterizer. They can also change the primitive type e.g.
+they can take a point as an input and output other primitives.
+Geometry shaders are inbetween the vertex and the fragment shader.
+
+**Vertex Shader**
+
+```glsl
+#version 330 core
+
+layout(location = 0) in vec3 position;
+layout(location = 1) in vec3 color;
+// Create an output interface block passed to the next shadaer stage.
+// Interface blocks can be used to structure data passed between shaders.
+out VS_OUT {
+ vec3 color;
+} vs_out;
+
+void main() {
+ vs_out.color = color
+ gl_Position = vec4(position, 1.0);
+}
+```
+
+**Geometry Shader**
+
+```glsl
+#version 330 core
+// The geometry shader takes in points.
+layout(points) in;
+// It outputs a triangle every 3 vertices emitted.
+layout(triangle_strip, max_vertices = 3) out;
+// VS_OUT becomes an input variable in the geometry shader.
+// Every input to the geometry shader in treated as an array.
+in VS_OUT {
+ vec3 color;
+} gs_in[];
+// Output color for the fragment shader.
+// You can also simply define color as 'out vec3 color',
+// If you don't want to use interface blocks.
+out GS_OUT {
+ vec3 color;
+} gs_out;
+
+void main() {
+ // Each emit calls the fragment shader, so we set a color for each vertex.
+ gs_out.color = mix(gs_in[0].color, vec3(1.0, 0.0, 0.0), 0.5);
+ // Move 0.5 units to the left and emit the new vertex.
+ // gl_in[] is the current vertex from the vertex shader, here we only
+ // use 0, because we are receiving points.
+ gl_Position = gl_in[0].gl_Position + vec4(-0.5, 0.0, 0.0, 0.0);
+ EmitVertex();
+ gs_out.color = mix(gs_in[0].color, vec3(0.0, 1.0, 0.0), 0.5);
+ // Move 0.5 units to the right and emit the new vertex.
+ gl_Position = gl_in[0].gl_Position + vec4(0.5, 0.0, 0.0, 0.0);
+ EmitVertex();
+ gs_out.color = mix(gs_in[0].color, vec3(0.0, 0.0, 1.0), 0.5);
+ // Move 0.5 units up and emit the new vertex.
+ gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.75, 0.0, 0.0);
+ EmitVertex();
+ EndPrimitive();
+}
+```
+
+**Fragment Shader**
+
+```glsl
+in GS_OUT {
+ vec3 color;
+} fs_in;
+
+out vec4 outColor;
+
+void main() {
+ outColor = vec4(fs_in.color, 1.0);
+}
+```
+
+If you now store a single point with a single color in a VBO and draw them,
+you should see a triangle, with your color mixed half way between
+red, green and blue on each vertex.
+
+
+## Quotes
+<sup>[1]</sup>[OpenGL - Wikipedia](https://en.wikipedia.org/wiki/OpenGL)
+
+## Books
+
+- OpenGL Superbible - Fifth Edition (covering OpenGL 3.3)
+- OpenGL Programming Guide - Eighth Edition (covering OpenGL 4.3)
diff --git a/perl.html.markdown b/perl.html.markdown index 17a538e3..08001ab0 100644 --- a/perl.html.markdown +++ b/perl.html.markdown @@ -152,7 +152,7 @@ while (condition) { ... } - +my $max = 5; # for loops and iteration for my $i (0 .. $max) { print "index is $i"; diff --git a/perl6.html.markdown b/perl6.html.markdown index cb64b646..6b0df0d4 100644 --- a/perl6.html.markdown +++ b/perl6.html.markdown @@ -247,11 +247,12 @@ concat3(|@array); #=> a, b, c ## arguments. If you really need to, you can ask for a mutable container by ## using the `is rw` trait: sub mutate( $n is rw ) { - $n++; + $n++; # postfix ++ operator increments its argument but returns its old value } my $m = 42; -mutate $m; #=> 43 +mutate $m; # the value is incremented but the old value is returned + #=> 42 say $m; #=> 43 ## This works because we are passing the container $m to the `mutate` sub. diff --git a/prolog.html.markdown b/prolog.html.markdown index f7b55ac6..d4c28cba 100644 --- a/prolog.html.markdown +++ b/prolog.html.markdown @@ -75,7 +75,7 @@ magicNumber(42). ?- 2 = 3. % False - equality test ?- X = 3. % X = 3 - assignment ?- X = 2, X = Y. % X = Y = 2 - two assignments - % Note Y is assigned to, even though it is + % Note Y is assigned too, even though it is % on the right hand side, because it is free ?- X = 3, X = 2. % False % First acts as assignment and binds X=3 diff --git a/protocol-buffer-3.html.markdown b/protocol-buffer-3.html.markdown new file mode 100644 index 00000000..46065536 --- /dev/null +++ b/protocol-buffer-3.html.markdown @@ -0,0 +1,247 @@ +--- +language: protocol-buffers +filename: protocol-buffers.proto +contributors: + - ["Shankar Shastri", "https://github.com/shankarshastri"] +--- +# Protocol Buffers + +## Why Protocol Buffers + +Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. +You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages. +Protocol Buffers are Schema Of Messages. They are language agnostic. +They can be converted to binary and converted back to message formats using the code generated by the protoc compiler for various languages. + +``` +/* +* Language Syntax +*/ + +/* +* Specifying Syntax Of Protocol Buffer Version +* Specifying Which Protocol Buffer Version To Use +* It can be usually proto3 or proto2 +*/ +syntax = "proto3"; + +/* +* Declaring Message In Protocol Buffer: +* As you can see, each field in the message definition has a unique number. +* These field numbers are used to identify your fields in the message binary format, +* and should not be changed once your message type is in use. +* Note that field numbers in the range 1 through 15 take one byte to encode, including the field number and the field's type (you can find out more about this in Protocol Buffer Encoding). +* Field numbers in the range 16 through 2047 take two bytes. So you should reserve the numbers 1 through 15 for very frequently occurring message elements. +* Remember to leave some room for frequently occurring elements that might be added in the future. +* The smallest field number you can specify is 1, and the largest is 2^29 - 1, or 536,870,911. +* You also cannot use the numbers 19000 through 19999 (FieldDescriptor::kFirstReservedNumber through FieldDescriptor::kLastReservedNumber), +* as they are reserved for the Protocol Buffers implementation - the protocol buffer compiler will complain if you use one of these reserved numbers in your .proto. +* Similarly, you cannot use any previously reserved field numbers. +* +*/ + +/* +Syntax For Declaring Message: + message ${MessageName} { + ${Scalar Value Type} ${FieldName1} = ${Tag Number1}; + . + . + . + ${Scalar Value Type} ${FieldNameN} = ${Tag NumberN}; + } + +Default Values Will be applied any case if the message doesn't contain a existing field defined +in the message definition +*/ + +message MessageTypes { + /* + * Scalar Value Types + */ + string stringType = 1; // A string must always contain UTF-8 encoded or 7-bit ASCII text. Default value = "" + + // Number Types, Default Value = 0 + int32 int32Type = 2; // Uses Variable Length Encoding. Inefficient For Negative Numbers, Instead Use sint32. + int64 int64Type = 3; // Uses Variable Length Encoding. Inefficient For Negative Numbers, Instead Use sint64. + uint32 uInt32Type = 4; // Uses Variable Length Encoding + uint64 uInt64Type = 5; // Uses Variable Length Encoding + sint32 sInt32Type = 6; // Uses Variable Length Encoding. They are efficient in encoding for negative numbers. + // Use this instead of int32 for negative numbers + sint64 sInt64Type = 7; // Uses Variable Length Encoding. They are efficient in encoding for negative numbers. + // Use this instead of int64 for negative numbers. + + fixed32 fixed32Type = 8; // Always four bytes. More efficient than uint32 if values are often greater than 2^28. + fixed64 fixed64Type = 9; // Always eight bytes. More efficient than uint64 if values are often greater than 2^56 + + sfixed32 sfixed32Type = 10; // Always four bytes. + sfixed64 sfixed64Type = 11; // Always Eight bytes. + + bool boolType = 12; // Boolean Type. Default Value = false + + bytes bytesType = 13; // May contain any arbitrary sequence of bytes. Default Value = Empty Bytes + + double doubleType = 14; + float floatType = 15; + + enum Week { + UNDEFINED = 0; // Tag 0 is always used as default in case of enum + SUNDAY = 1; + MONDAY = 2; + TUESDAY = 3; + WEDNESDAY = 4; + THURSDAY = 5; + FRIDAY = 6; + SATURDAY = 7; + } + Week wkDayType = 16; + + /* + * Defining Collection Of Scalar Value Type + * Syntax: repeated ${ScalarType} ${name} = TagValue + */ + repeated string listOfString = 17; // List[String] +} + +/* +* Defining Defined Message Types In Other Message Definition +*/ +message Person { + string fname = 1; + string sname = 2; +} + +message City { + Person p = 1; +} + +/* +* Nested Message Definitions +*/ + +message NestedMessages { + message FirstLevelNestedMessage { + string firstString = 1; + message SecondLevelNestedMessage { + string secondString = 2; + } + } + FirstLevelNestedMessage msg = 1; + FirstLevelNestedMessage.SecondLevelNestedMessage msg2 = 2; +} + +/* +* Importing Message From A File +*/ + +// one.proto +// message One { +// string oneMsg = 1; +// } + +// two.proto +// import "myproject/one.proto" +// message Two { +// string twoMsg = 2; +// } + + +/* +* Advanced Topics +*/ + +/* +* Handling Message Type Changes: +* Never Change/Use The TagNumber Of A Message Field Which Was Removed +* We should use reserved in case of message definition update. +* (https://developers.google.com/protocol-buffers/docs/proto3#updating) +*/ + +/* +* Reserved Fields +* It's used in case if we need to add/remove new fields into message. +* Using Reserved Backward and Forward Compatibility Of Messages can be achieved +*/ + + +message ReservedMessage { + reserved 0, 1, 2, 3 to 10; // Set Of Tag Numbers Which Can't be reused. + reserved "firstMsg", "secondMsg", "thirdMsg"; // Set Of Labels Which Can't Be reused. +} + +/* +* Any +* The Any message type lets you use messages as embedded types without having their .proto definition. +* An Any contains an arbitrary serialized message as bytes, +* along with a URL that acts as a globally unique identifier for and resolves to that message's type. +* For Any to work we need to import it as shown below. +*/ +/* + import "google/protobuf/any.proto"; + message AnySampleMessage { + repeated google.protobuf.Any.details = 1; + } + +*/ + + +/* +* OneOf +* There are cases, wherein only one field at-most might be present as part of the message. +* Note: OneOf messages can't be repeated. +*/ + +message OneOfMessage { + oneof msg { + string fname = 1; + string sname = 2; + }; +} + +/* +* Maps +* Map fields cannot be repeated. +* Ordering Of A Map Is Not Guaranteed. +*/ + +message MessageWithMaps { + map<string, string> mapOfMessages = 1; +} + + +/* +* Packages +* Used for preventing name clashes between protocol message types +* Syntax: + package ${packageName}; + + To Access the package; + ${packageName}.${messageName} = ${tagNumber}; +*/ + +/* +* Services +* Message Types Defined For Using In RPC system. +* When protoc compiler generates for various languages it generates stub methods for the services. +*/ + +message SearchRequest { + string queryString = 1; +} + +message SearchResponse { + string queryResponse = 1; +} +service SearchService { + rpc Search (SearchRequest) returns (SearchResponse); +} +``` + +## Generating Classes In Various Languages For Protocol Buffers + +```shell +protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR --ruby_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIR path/to/file.proto +``` + +## References + +[Google Protocol Buffers](https://developers.google.com/protocol-buffers/) diff --git a/pt-br/clojure-pt.html.markdown b/pt-br/clojure-pt.html.markdown index 7e8b3f7b..b88d4eec 100644 --- a/pt-br/clojure-pt.html.markdown +++ b/pt-br/clojure-pt.html.markdown @@ -340,7 +340,7 @@ keymap ; => {:a 1, :b 2, :c 3} (def my-atom (atom {})) ; Atualize o atom com um swap!. -; swap! pega uma funçnao and chama ela com o valor atual do atom +; swap! pega uma função e chama ela com o valor atual do atom ; como primeiro argumento, e qualquer argumento restante como o segundo (swap! my-atom assoc :a 1) ; Coloca o valor do átomo my-atom como o resultado de (assoc {} :a 1) (swap! my-atom assoc :b 2) ; Coloca o valor do átomo my-atom como o resultado de (assoc {:a 1} :b 2) diff --git a/pt-br/coffeescript-pt.html.markdown b/pt-br/coffeescript-pt.html.markdown index 8b1094b1..7129a463 100644 --- a/pt-br/coffeescript-pt.html.markdown +++ b/pt-br/coffeescript-pt.html.markdown @@ -3,19 +3,20 @@ language: coffeescript contributors: - ["Tenor Biel", "http://github.com/L8D"] - ["Xavier Yao", "http://github.com/xavieryao"] + - ["Claudio Busatto", "http://github.com/cjcbusatto"] translators: - ["Miguel Araújo", "https://github.com/miguelarauj1o"] lang: pt-br filename: learncoffeescript-pt.coffee --- -CoffeeScript é uma pequena linguagem que compila um-para-um para o JavaScript -equivalente, e não há interpretação em tempo de execução. Como um dos sucessores -de JavaScript, CoffeeScript tenta o seu melhor para exibir uma saída legível, -bem-impressa e bom funcionamento dos códigos JavaScript em todo o tempo de +CoffeeScript é uma pequena linguagem que compila um-para-um para o JavaScript +equivalente, e não há interpretação em tempo de execução. Como um dos sucessores +de JavaScript, CoffeeScript tenta o seu melhor para exibir uma saída legível, +bem-impressa e bom funcionamento dos códigos JavaScript em todo o tempo de execução JavaScript. -Veja também [site do CoffeeScript](http://coffeescript.org/), que tem um tutorial +Veja também [site do CoffeeScript](http://coffeescript.org/), que tem um tutorial completo sobre CoffeeScript. ``` coffeescript @@ -23,35 +24,35 @@ completo sobre CoffeeScript. #Segue as tendências de muitas linguagens modernas #Assim, os comentários são iguais a Ruby e Python, eles usam símbolos numéricos. -### -Os comentários em bloco são como estes, e eles traduzem diretamente para '/ *'s e +### +Os comentários em bloco são como estes, e eles traduzem diretamente para '/ *'s e '* /'s para o código JavaScript que resulta... -Você deveria entender mais de semântica de JavaScript antes de continuar... +Você deveria entender mais de semântica de JavaScript antes de continuar... ### -# Tarefa: -numero = 42 #=> número var = 42; +# Tarefa: +numero = 42 #=> var numero = 42; oposto = true #=> var oposto = true; -# Condições: -numero = -42 if oposto #=> if (oposto) {número = -42;} +# Condições: +numero = -42 if oposto #=> if (oposto) {numero = -42;} -# Funções: +# Funções: quadrado = (x) -> x * x #=> var quadrado = function (x) {return x * x;} -preencher = (recipiente, líquido = "coffee") -> - "Preenchendo o #{recipiente} with #{líquido}..." +preencher = (recipiente, liquido = "coffee") -> + "Preenchendo o #{recipiente} with #{liquido}..." #=>var preencher; # -#preencher = function(recipiente, líquido) { -# if (líquido == null) { -# líquido = "coffee"; +#preencher = function(recipiente, liquido) { +# if (liquido == null) { +# liquido = "coffee"; # } -# return "Preenchendo o " + recipiente + " with " + líquido + "..."; +# return "Preenchendo o " + recipiente + " with " + liquido + "..."; #}; -# Alcances: +# Alcances: list = [1 .. 5] #=> lista var = [1, 2, 3, 4, 5]; # Objetos: @@ -79,7 +80,7 @@ alert "Eu sabia!" if elvis? #=> if(typeof elvis !== "undefined" && elvis !== null) { alert("Eu sabia!"); } # Compressão de Matrizes: -cubes = (math.cube num for num in list) +cubes = (math.cube num for num in list) #=>cubes = (function() { # var _i, _len, _results; # _results = []; @@ -99,8 +100,9 @@ eat alimento for alimento in comidas when alimento isnt 'chocolate' # if (alimento !== 'chocolate') { # eat(alimento); # } +``` ## Recursos adicionais - [Smooth CoffeeScript](http://autotelicum.github.io/Smooth-CoffeeScript/) -- [CoffeeScript Ristretto](https://leanpub.com/coffeescript-ristretto/read)
\ No newline at end of file +- [CoffeeScript Ristretto](https://leanpub.com/coffeescript-ristretto/read) diff --git a/pug.html.markdown b/pug.html.markdown new file mode 100644 index 00000000..0187f1e0 --- /dev/null +++ b/pug.html.markdown @@ -0,0 +1,204 @@ +--- +language: Pug +contributors: + - ["Michael Warner", "https://github.com/MichaelJGW"] +filename: index.pug +--- + +## Getting Started with Pug + +Pug is a little language that compiles into the HTML. It has cleaner syntax +with additional features like if statements and loops. It can also be used +as a server side templating language for server languages like NodeJS. + +### The Language +```pug + +//- Single Line Comment + +//- Multi Line + Comment + +//- ---TAGS--- +//- Basic +div +//- <div></div> +h1 +//- <h1></h1> +my-customTag +//- <my-customTag></my-customTag> + +//- Sibling +div +div +//- <div></div> + <div></div> + +//- Child +div + div +//- <div> + <div></div> + </div> + +//- Text +h1 Hello there +//- <h1>Hello there</h1> + +//- Multi Line Text +div. + Hello + There +//- <div> + Hello + There + </div> + +//- ---ATTRIBUTES--- +div(class="my-class" id="my-id" my-custom-attrs="data" enabled) +//- <div class="my-class" id="my-id" my-custom-attrs="data" enabled></div> + +//- Short Hand +span.my-class +//- <span class="my-class"></span> +.my-class +//- <div class="my-class"></div> +div#my-id +//- <div id="my-id"></div> +div#my-id.my-class +//- <div class="my-class" id="my-id"></div> + + +//- ---JS--- +- const lang = "pug"; + +//- Multi Line JS +- + const lang = "pug"; + const awesome = true; + +//- JS Classes +- const myClass = ['class1', 'class2', 'class3'] +div(class=myClass) +//- <div class="class1 class2 class3"></div> + +//- JS Styles +- const myStyles = {'color':'white', 'background-color':'blue'} +div(styles=myStyles) +//- <div styles="{"color":"white","background-color":"blue"}"></div> + +//- JS Attributes +- const myAttributes = {"src": "photo.png", "alt": "My Photo"} +img&attributes(myAttributes) +//- <img src="photo.png" alt="My Photo"> +- let disabled = false +input(type="text" disabled=disabled) +//- <input type="text"> +- disabled = true +input(type="text" disabled=disabled) +//- <input type="text" disabled> + +//- JS Templating +- const name = "Bob"; +h1 Hi #{name} +h1= name +//- <h1>Hi Bob</h1> +//- <h1>Bob</h1> + +//- ---LOOPS--- + +//- 'each' and 'for' do the same thing we will use 'each' only. + +each value, i in [1,2,3] + p=value +//- + <p>1</p> + <p>2</p> + <p>3</p> + +each value, index in [1,2,3] + p=value + '-' + index +//- + <p>1-0</p> + <p>2-1</p> + <p>3-2</p> + +each value in [] + p=value +//- + +each value in [] + p=value +else + p No Values are here + +//- <p>No Values are here</p> + +//- ---CONDITIONALS--- + +- const number = 5 +if number < 5 + p number is less then 5 +else if number > 5 + p number is greater then 5 +else + p number is 5 +//- <p>number is 5</p> + +- const orderStatus = "Pending"; +case orderStatus + when "Pending" + p.warn Your order is pending + when "Completed" + p.success Order is Completed. + when -1 + p.error Error Occurred + default + p No Order Record Found +//- <p class="warn">Your order is pending</p> + +//- --INCLUDE-- +//- File path -> "includes/nav.png" +h1 Company Name +nav + a(href="index.html") Home + a(href="about.html") About Us + +//- File path -> "index.png" +html + body + include includes/nav.pug +//- + <html> + <body> + <h1>Company Name</h1> + <nav><a href="index.html">Home</a><a href="about.html">About Us</a></nav> + </body> + </html> + +//- Importing JS and CSS +script + include scripts/index.js +style + include styles/theme.css + +//- ---MIXIN--- +mixin basic() + div Hello ++basic("Bob") +//- <div>Hello</div> + +mixin comment(name, comment) + div + span.comment-name= name + div.comment-text= comment ++comment("Bob", "This is Awesome") +//- <div>Hello</div> + +``` + + +### Additional Resources +- [The Site](https://pugjs.org/) +- [The Docs](https://pugjs.org/api/getting-started.html) +- [Github Repo](https://github.com/pugjs/pug) diff --git a/python3.html.markdown b/python3.html.markdown index c4f15867..ecdbd932 100644 --- a/python3.html.markdown +++ b/python3.html.markdown @@ -155,7 +155,7 @@ len("This is a string") # => 16 name = "Reiko" f"She said her name is {name}." # => "She said her name is Reiko" # You can basically put any Python statement inside the braces and it will be output in the string. -f"{name} is {len(name)} characters long." +f"{name} is {len(name)} characters long." # => "Reiko is 5 characters long." # None is an object diff --git a/reason.html.markdown b/reason.html.markdown new file mode 100644 index 00000000..45633cf5 --- /dev/null +++ b/reason.html.markdown @@ -0,0 +1,543 @@ +--- +language: reason +filename: reason.re +contributors: + - ["Seth Corker", "https://sethcorker.com"] +--- + +Reason is a syntax over OCaml that is easier to get started for programmers who are familiar with C-style syntax like JavaScript. BuckleScript is part of the toolchain which compiles Reason to JavaScript so you can write statically typed code for anywhere that JavaScript runs. + +```javascript +/* Comments start with slash-star, and end with slash-star */ + +/*---------------------------------------------- + * Variable and function declaration + *---------------------------------------------- + * Variables and functions use the let keyword and end with a semi-colon + * `let` bindings are immutable + */ + +let x = 5; +/* - Notice we didn't add a type, Reason will infer it's an int */ + +/* A function like this, take two arguments and add them together */ +let add = (a, b) => a + b; +/* - This doesn't need a type annotation either! */ + +/*---------------------------------------------- + * Type annotation + *---------------------------------------------- + * Types don't need tp be explicitly annotated in most cases but when you need + * to, you can add the type after the name + */ + +/* A type can be explicitly written like so */ +let x: int = 5; + +/* The add function from before could be explicitly annotated too */ +let add2 = (a: int, b: int): int => a + b; + +/* A type can be aliased using the type keyword */ +type companyId = int; +let myId: companyId = 101; + +/* Mutation is not encouraged in Reason but it's there if you need it + If you need to mutate a let binding, the value must be wrapped in a `ref()`*/ +let myMutableNumber = ref(120); + +/* To access the value (and not the ref container), use `^` */ +let copyOfMyMutableNumber = myMutableNumber^; + +/* To assign a new value, use the `:=` operator */ +myMutableNumber := 240; + +/*---------------------------------------------- + * Basic types and operators + *---------------------------------------------- + */ + +/* > String */ + +/* Use double quotes for strings */ +let greeting = "Hello world!"; + +/* A string can span multiple lines */ +let aLongerGreeting = "Look at me, +I'm a multi-line string +"; + +/* A quoted string can be used for string interpolation and special chars + Use the `js` annotation for unicode */ +let world = {js|🌍|js}; + +/* The `j` annotation is used for string interpolation */ +let helloWorld = {j|hello, $world|j}; + +/* Concatenate strings with ++ */ +let name = "John " ++ "Wayne"; +let emailSubject = "Hi " ++ name ++ ", you're a valued customer"; + +/* > Char */ + +/* Use a single character for the char type */ +let lastLetter = 'z'; +/* - Char doesn't support Unicode or UTF-8 */ + +/* > Boolean */ + +/* A boolean be either true or false */ +let isLearning = true; + +true && false; /* - : bool = false; Logical and */ +true || true; /* - : bool = true; Logical or */ +!true; /* - : bool = false; Logical not */ + +/* Greater than `>`, or greater than or equal to `>=` */ +'a' > 'b'; /* - bool : false */ + +/* Less than `<`, or less than or equal to `<=` */ +1 < 5; /* - : bool = true */ + +/* Structural equal */ +"hello" == "hello"; /* - : bool = true */ + +/* Referential equal */ +"hello" === "hello"; /* - : bool = false */ +/* - This is false because they are two different "hello" string literals */ + +/* Structural unequal */ +lastLetter != 'a'; /* -: bool = true */ + +/* Referential unequal */ +lastLetter !== lastLetter; /* - : bool = false */ + +/* > Integer */ +/* Perform math operations on integers */ + +1 + 1; /* - : int = 2 */ +25 - 11; /* - : int = 11 */ +5 * 2 * 3; /* - : int = 30 */ +8 / 2; /* - : int = 4 */ + +/* > Float */ +/* Operators on floats have a dot after them */ + +1.1 +. 1.5; /* - : float = 2.6 */ +18.0 -. 24.5; /* - : float = -6.5 */ +2.5 *. 2.0; /* - : float = 5. */ +16.0 /. 4.0; /* - : float = 4. */ + +/* > Tuple + * Tuples have the following attributes + - immutable + - ordered + - fix-sized at creation time + - heterogeneous (can contain different types of values) + A tuple is 2 or more values */ + +let teamMember = ("John", 25); + +/* Type annotation matches the values */ +let position2d: (float, float) = (9.0, 12.0); + +/* Pattern matching is a great tool to retrieve just the values you care about + If we only want the y value, let's use `_` to ignore the value */ +let (_, y) = position2d; +y +. 1.0; /* - : float = 13. */ + +/* > Record */ + +/* A record has to have an explicit type */ +type trainJourney = { + destination: string, + capacity: int, + averageSpeed: float, +}; + +/* Once the type is declared, Reason can infer it whenever it comes up */ +let firstTrip = {destination: "London", capacity: 45, averageSpeed: 120.0}; + +/* Access a property using dot notation */ +let maxPassengers = firstTrip.capacity; + +/* If you define the record type in a different file, you have to reference the + filename, if trainJourney was in a file called Trips.re */ +let secondTrip: Trips.firstTrip = { + destination: "Paris", + capacity: 50, + averageSpeed: 150.0, +}; + +/* Records are immutable by default */ +/* But the contents of a record can be copied using the spread operator */ +let newTrip = {...secondTrip, averageSpeed: 120.0}; + +/* A record property can be mutated explicitly with the `mutable` keyword */ +type breakfastCereal = { + name: string, + mutable amount: int, +}; + +let tastyMuesli = {name: "Tasty Muesli TM", amount: 500}; + +tastyMuesli.amount = 200; +/* - tastyMuesli now has an amount of 200 */ + +/* Punning is used to avoid redundant typing */ +let name = "Just As Good Muesli"; +let justAsGoodMuesli = {name, amount: 500}; +/* - justAsGoodMuesli.name is now "Just As Good Muesli", it's equivalent + to { name: name, amount: 500 } */ + +/* > Variant + Mutually exclusive states can be expressed with variants */ + +type authType = + | GitHub + | Facebook + | Google + | Password; +/* - The constructors must be capitalized like so */ +/* - Like records, variants should be named if declared in a different file */ + +let userPreferredAuth = GitHub; + +/* Variants work great with a switch statement */ +let loginMessage = + switch (userPreferredAuth) { + | GitHub => "Login with GitHub credentials." + | Facebook => "Login with your Facebook account." + | Google => "Login with your Google account" + | Password => "Login with email and password." + }; + +/* > Option + An option can be None or Some('a) where 'a is the type */ + +let userId = Some(23); + +/* A switch handles the two cases */ +let alertMessage = + switch (userId) { + | Some(id) => "Welcome, your ID is" ++ string_of_int(id) + | None => "You don't have an account!" + }; +/* - Missing a case, `None` or `Some`, would cause an error */ + +/* > List + * Lists have the following attributes + - immutable + - ordered + - fast at prepending items + - fast at splitting + + * Lists in Reason are linked lists + */ + +/* A list is declared with square brackets */ +let userIds = [1, 4, 8]; + +/* The type can be explicitly set with list('a) where 'a is the type */ +type idList = list(int); +type attendanceList = list(string); + +/* Lists are immutable */ +/* But the contents of a list can be copied using the spread operator */ +let newUserIds = [101, 102, ...userIds]; + +/* > Array + * Arrays have the following attributes + - mutable + - fast at random access & updates */ + +/* An array is declared with `[|` and ends with `|]` */ +let languages = [|"Reason", "JavaScript", "OCaml"|]; + +/*---------------------------------------------- + * Function + *---------------------------------------------- + */ + +/* Reason functions use the arrow syntax, the expression is returned */ +let signUpToNewsletter = email => "Thanks for signing up " ++ email; + +/* Call a function like this */ +signUpToNewsletter("hello@reason.org"); + +/* For longer functions, use a block */ +let getEmailPrefs = email => { + let message = "Update settings for " ++ email; + let prefs = ["Weekly News", "Daily Notifications"]; + + (message, prefs); +}; +/* - the final tuple is implicitly returned */ + +/* > Labeled Arguments */ + +/* Arguments can be labeled with the ~ symbol */ +let moveTo = (~x, ~y) => {/* Move to x,y */}; + +moveTo(~x=7.0, ~y=3.5); + +/* Labeled arguments can also have a name used within the function */ +let getMessage = (~message as msg) => "==" ++ msg ++ "=="; + +getMessage(~message="You have a message!"); +/* - The caller specifies ~message but internally the function can make use */ + +/* The following function also has explicit types declared */ +let showDialog = (~message: string): unit => { + () /* Show the dialog */; +}; +/* - The return type is `unit`, this is a special type that is equivalent to + specifying that this function doesn't return a value + the `unit` type can also be represented as `()` */ + +/* > Currying + Functions can be curried and are partially called, allowing for easy reuse */ + +let div = (denom, numr) => numr / denom; +let divBySix = div(6); +let divByTwo = div(2); + +div(3, 24); /* - : int = 8 */ +divBySix(128); /* - : int = 21 */ +divByTwo(10); /* - : int = 5 */ + +/* > Optional Labeled Arguments */ + +/* Use `=?` syntax for optional labeled arguments */ +let greetPerson = (~name, ~greeting=?, ()) => { + switch (greeting) { + | Some(greet) => greet ++ " " ++ name + | None => "Hi " ++ name + }; +}; +/* - The third argument, `unit` or `()` is required because if we omitted it, + the function would be curried so greetPerson(~name="Kate") would create + a partial function, to fix this we add `unit` when we declare and call it */ + +/* Call greetPerson without the optional labeled argument */ +greetPerson(~name="Kate", ()); + +/* Call greetPerson with all arguments */ +greetPerson(~name="Marco", ~greeting="How are you today,"); + +/* > Pipe */ +/* Functions can be called with the pipeline operator */ + +/* Use `->` to pass in the first argument (pipe-first) */ +3->div(24); /* - : int = 8 */ +/* - This is equivalent to div(3, 24); */ + +36->divBySix; /* - : int = 6 */ +/* - This is equivalent to divBySix(36); */ + +/* Use `|>` to pass in the last argument (pipe-last) */ +24 |> div(3); /* - : int = 8 */ +/* - This is equivalent to div(3, 24); */ + +36 |> divBySix; /* - : int = 6 */ +/* - This is equivalent to divBySix(36); */ + +/* Pipes make it easier to chain code together */ +let addOne = a => a + 1; +let divByTwo = a => a / 2; +let multByThree = a => a * 3; + +let pipedValue = 3->addOne->divByTwo->multByThree; /* - : int = 6 */ + +/*---------------------------------------------- + * Control Flow & Pattern Matching + *---------------------------------------------- + */ + +/* > If-else */ +/* In Reason, `If` is an expression when evaluate will return the result */ + +/* greeting will be "Good morning!" */ +let greeting = if (true) {"Good morning!"} else {"Hello!"}; + +/* Without an else branch the expression will return `unit` or `()` */ +if (false) { + showDialog(~message="Are you sure you want to leave?"); +}; +/* - Because the result will be of type `unit`, both return types should be of + the same type if you want to assign the result. */ + +/* > Destructuring */ +/* Extract properties from data structures easily */ + +let aTuple = ("Teacher", 101); + +/* We can extract the values of a tuple */ +let (name, classNum) = aTuple; + +/* The properties of a record can be extracted too */ +type person = { + firstName: string, + age: int, +}; +let bjorn = {firstName: "Bjorn", age: 28}; + +/* The variable names have to match with the record property names */ +let {firstName, age} = bjorn; + +/* But we can rename them like so */ +let {firstName: bName, age: bAge} = bjorn; + +let {firstName: cName, age: _} = bjorn; + +/* > Switch + Pattern matching with switches is an important tool in Reason + It can be used in combination with destructuring for an expressive and + concise tool */ + +/* Lets take a simple list */ +let firstNames = ["James", "Jean", "Geoff"]; + +/* We can pattern match on the names for each case we want to handle */ +switch (firstNames) { +| [] => "No names" +| [first] => "Only " ++ first +| [first, second] => "A couple of names " ++ first ++ "," ++ second +| [first, second, third] => + "Three names, " ++ first ++ ", " ++ second ++ ", " ++ third +| _ => "Lots of names" +}; +/* - The `_` is a catch all at the end, it signifies that we don't care what + the value is so it will match every other case */ + +/* > When clause */ + +let isJohn = a => a == "John"; +let maybeName = Some("John"); + +/* When can add more complex logic to a simple switch */ +let aGreeting = + switch (maybeName) { + | Some(name) when isJohn(name) => "Hi John! How's it going?" + | Some(name) => "Hi " ++ name ++ ", welcome." + | None => "No one to greet." + }; + +/* > Exception */ + +/* Define a custom exception */ +exception Under_Age; + +/* Raise an exception within a function */ +let driveToTown = (driver: person) => + if (driver.age >= 15) { + "We're in town"; + } else { + raise(Under_Age); + }; + +let evan = {firstName: "Evan", age: 14}; + +/* Pattern match on the exception Under_Age */ +switch (driveToTown(evan)) { +| status => print_endline(status) +| exception Under_Age => + print_endline(evan.firstName ++ " is too young to drive!") +}; + +/* Alternatively, a try block can be used */ +let messageToEvan = + try (driveToTown(evan)) { + | Under_Age => evan.firstName ++ " is too young to drive!" + }; +/* - With Reason exceptions can be avoided with optionals and are seldom used */ + +/*---------------------------------------------- + * Object + *---------------------------------------------- + * Objects are similar to Record types but aren't as rigid + * An object resembles a class + */ + +/* An object may be typed like a record but contains a dot */ +type surfaceComputer = { + . + color: string, + capacity: int, +}; +/* - A single dot signifies a closed object, an object that uses this type + must have the exact shape */ + +let surfaceBook: surfaceComputer = {pub color = "blue"; pub capacity = 512}; + +/* But an object doesn't require a type */ +let house = { + /* A private property */ + val temp = ref(18.0); + /* Public properties */ + pub temperature = temp; + /* A private method only accessible from within house */ + pri setThermostat = v => temp := v; + /* A public method that calls the private setThermostat method */ + pub arriveHome = () => this#setThermostat(22.0) +}; + +house#temperature; /* - : float = 18. */ +house#arriveHome(); +house#temperature; /* - : float = 22. */ + +/*---------------------------------------------- + * Module + *---------------------------------------------- + * Modules are used to organize your code and provide namespacing, + * Each file is a module by default + */ + +/* Create a module */ +module Staff = { + type role = + | Delivery + | Sales + | Other; + type member = { + name: string, + role, + }; + + let getRoleDirectionMessage = staff => + switch (staff.role) { + | Delivery => "Deliver it like you mean it!" + | Sales => "Sell it like only you can!" + | Other => "You're an important part of the team!" + }; +}; + +/* A module can be accessed with dot notation */ +let newEmployee: Staff.member = {name: "Laura", role: Staff.Delivery}; + +/* Using the module name can be tiresome so the module's contents can be opened + into the current scope with `open` */ +open Staff; + +let otherNewEmployee: member = {name: "Fred", role: Other}; + +/* A module can be extended using the `include` keyword, include copies + the contents of the module into the scope of the new module */ +module SpecializedStaff = { + include Staff; + + /* `member` is included so there's no need to reference it explicitly */ + let ceo: member = {name: "Reggie", role: Other}; + + let getMeetingTime = staff => + switch (staff) { + | Other => 11_15 /* - : int = 1115; Underscores are for formatting only */ + | _ => 9_30 + }; +}; +``` + +## Further Reading +- [Official Reason Docs](https://reasonml.github.io/docs/en/what-and-why) +- [Official BuckleScript Docs](https://bucklescript.github.io/docs/en/what-why) +- [Try Reason](https://reasonml.github.io/en/try) +- [Get Started with Reason by Nik Graf](https://egghead.io/courses/get-started-with-reason) diff --git a/rst.html.markdown b/rst.html.markdown index 01595fe4..2423622e 100644 --- a/rst.html.markdown +++ b/rst.html.markdown @@ -47,19 +47,27 @@ Title are underlined with equals signs too Subtitles with dashes --------------------- -You can put text in *italic* or in **bold**, you can "mark" text as code with double backquote ``print()``. +You can put text in *italic* or in **bold**, you can "mark" text as code with double backquote ``print()``. -Lists are as simple as in Markdown: +Lists are similar to Markdown, but a little more involved. + +Remember to line up list symbols (like - or *) with the left edge of the previous text block, and remember to use blank lines to separate new lists from parent lists: - First item - Second item - - Sub item + + - Sub item + +- Third item or * First item * Second item - * Sub item + + * Sub item + +* Third item Tables are really easy to write: diff --git a/ru-ru/linker-ru.html.markdown b/ru-ru/linker-ru.html.markdown new file mode 100644 index 00000000..7df29c23 --- /dev/null +++ b/ru-ru/linker-ru.html.markdown @@ -0,0 +1,203 @@ +--- +category: tool +tool: linker +contributors: + - ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"] +translators: + - ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"] +lang: ru-ru +--- + +# Основные понятия и определения +**Счетчик позиций** - у компоновщика есть специальная переменная +"." (точка) всегда содержит текущую позицию вывода. + +# Функции +**ADDR(section)** - возвращает абсолютный адрес указанной секции. Однако +данная секция должна быть определенна до использования функции ADDR. + +**ALIGN(exp)** - возвращает значение счетчика позиций, выравненное на границу +следующего за exp выражения. + +**SIZEOF(section)** - возвращает размер секции в байтах. + +**FILL(param)** - определяет образец заполнения для текущей секции. Все +остальные неуказанные регионы внутри секции заполняются значением указанными +в аргументе функции. + +**KEEP(param)** - используется чтобы помечать param как неустранимый. + +**ENTRY(func)** - определяет функцию, которая будет являться точкой входа +в программу. + +```bash +# Определяем точку входа в программу +ENTRY(Reset_Handler) + +# Определяем перемнную которая содержит адрес вершины стека +_estack = 0x20020000; +# Определяем перемнную которая содержит значение размера кучи +_Min_Heap_Size = 0x200; +# Определяем перемнную которая содержит значение размера стека +_Min_Stack_Size = 0x400; + +# Описание карты памяти доступной для данного процессора +# MEMORY +# { +# ИМЯ_ОБЛАСТИ_ПАМЯТИ (права доступа) : ORIGIN = АДРЕС_НАЧАЛА, LENGTH = РАЗМЕР +# } +# В нашем примере контроллер содержит три области памяти: +# RAM - начинается с адреса 0x20000000 и занимает 128 Кбайт; +# CCMRAM - начинается с адреса 0x10000000и занимает 64 Кбайт; +# FLASH - начинается с адреса 0x8000000 занимает 1024 Кбайт; +# Причем RAM память доступка для чтения, записи и исполнения. +# CCMRAM память доступна только на чтение и запись. +# FLASH память доступна на чтение и исполнение. +MEMORY +{ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K + CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K + FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K +} + +# Описываем выходные секции +SECTIONS +{ + # Первая секция содержит таблицу векторов прерываний + .isr_vector : + { + # Выравниваем текущую позицию на границу 4-х байт. + . = ALIGN(4); + + # Существует опция --gc-sections, которая позволяет собирать мусор из неиспользуемых + # входных разделов. И если есть разделы, которые сборщик муссора не должен трогать, + # то их необходимо указать в качестве аргумента функции KEEP() (аналог ключевого слова + # volatile). + # Запись (*(.isr_vector)) означает разделы .isr_vector во всех объектных файлах. Т.к. + # обращение к разделу в общем виде выглядит так: (ИМЯ_ФАЙЛА(ИМЯ_РАЗДЕЛА)) + KEEP(*(.isr_vector)) + + # Выравниваем текущую позицию на границу 4-х байт. + . = ALIGN(4); + + # Выражение ">ОБЛАСТЬ_ПАМЯТИ" указывает в какую именно область памяти будет помещенна + # данная секция. В нашем слущае секция .isr_vector будет размещена во FLASH памяти. + } >FLASH + +# ИТОГО: Секция .isr_vector, которая содержит таблицу векторов прерываний выравнивается +# по границе 4-х байт, помечается как недоступная для сборщика мусора и размещается в начале +# FLASH памяти микроконтроллера. + + # Вторая секция содержит код программы. + .text : + { + # Выравниваем текущую позицию на границу 4-х байт. + . = ALIGN(4); + + # Указываем, что в данной секции будут хранится области .text всех + # объектных файлов + *(.text) + *(.text*) + + # Защищаем от сборщика мусора секции .init и .fini + KEEP (*(.init)) + KEEP (*(.fini)) + + # Выравниваем текущую позицию на границу 4-х байт. + . = ALIGN(4); + + # Определяется переменная _etext, которая хранит в себе адрес конца секции .text и которая + # может быть доступна в исходном тексте программы через объявление + # volaile unsigned int extern _etext; + _etext = .; + } >FLASH + +# ИТОГО: Секция .text, которая содержит код программы выравнивается по границе 4-х байт, +# включает в себя: все секции с кодом программы во всех объектных файлах и защищенные +от сборщика муссора секции .init и .fini во всех объектных файлах, распологается во FLASH +памяти микроконтроллера сразу за таблицей векторов. +Секции text, .init и .fini. располагаются в памяти в той последовательности в которой они +объявлены в скрипте. + + # Третья секция содержит константные данные. + .rodata : + { + # Выравниваем текущую позицию на границу 4-х байт. + . = ALIGN(4); + + # Указываем, что в данной секции будут хранится области .rodataвсех + # объектных файлов + *(.rodata) + *(.rodata*) + + # Выравниваем текущую позицию на границу 4-х байт. + . = ALIGN(4); + } >FLASH + + # Сохраняем в переменной _sidata абсолютный адрес секции .data + _sidata = LOADADDR(.data); + + # Четвертая секция содержит инициализированные переменные. + .data : + { + # Выравниваем текущую позицию на границу 4-х байт. + . = ALIGN(4); + + # Сохраняем в переменной _sdata адрес текущей позиции (начала секции) + _sdata = .; + + # Указываем, что в данной секции будут хранится области .data всех + # объектных файлов + *(.data) + *(.data*) + + # Выравниваем текущую позицию на границу 4-х байт. + . = ALIGN(4); + + # Сохраняем в переменной _sdata адрес текущей позиции (конец секции) + _edata = .; + + # Функция AT указывает на то, что данный сектор хранится в одной области памяти + # (в нашем случае FLASH), а исполняться будет из другой обасти памяти (в нашем случае RAM). + # Есть два типа адрессов: + # * VMA (Virtual memory address) - это run-time адрес по которому уомпилятор ожидает + # видеть данные. + # * LMA (Load memory address) - это адрес по которому линкер хранит данные. + + #Startup должен код скопировать секцию .data из адрессов LMA в адресса VMA. + + } >RAM AT> FLASH + + # Пятая секция содержит инициализированные нулем переменные. + .bss : + { + # Сохраняем в переменной _sbss и __bss_start__ адрес текущей позиции (начала секции) + _sbss = .; + __bss_start__ = _sbss; + + # Указываем, что в данной секции будут хранится области .bss всех + # объектных файлов + *(.bss) + *(.bss*) + + # Выравниваем текущую позицию на границу 4-х байт. + . = ALIGN(4); + + # Сохраняем в переменной _ebss и __bss_end__ адрес текущей позиции (начала секции) + _ebss = .; + __bss_end__ = _ebss; + } >RAM + + # Шестая секция содержит кучу и стек. Размещается в самом конце RAM. + ._user_heap_stack : + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(4); + } >RAM +} +``` + diff --git a/scala.html.markdown b/scala.html.markdown index 28424684..c7a8842e 100644 --- a/scala.html.markdown +++ b/scala.html.markdown @@ -345,7 +345,7 @@ s(0) // Boolean = false s(1) // Boolean = true /* Look up the documentation of map here - - * http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Map + * https://www.scala-lang.org/api/current/scala/collection/immutable/Map.html * and make sure you can read it */ diff --git a/swift.html.markdown b/swift.html.markdown index f834f373..c2fb3471 100644 --- a/swift.html.markdown +++ b/swift.html.markdown @@ -8,22 +8,26 @@ contributors: - ["Clayton Walker", "https://github.com/cwalk"] - ["Fernando Valverde", "http://visualcosita.xyz"] - ["Alexey Nazaroff", "https://github.com/rogaven"] + - ["@Samasaur1", "https://github.com/Samasaur1"] filename: learnswift.swift --- Swift is a programming language for iOS and OS X development created by Apple. Designed to coexist with Objective-C and to be more resilient against erroneous code, Swift was introduced in 2014 at Apple's developer conference WWDC. It is built with the LLVM compiler included in Xcode 6+. -The official _[Swift Programming Language](https://itunes.apple.com/us/book/swift-programming-language/id881256329)_ book from Apple is now available via iBooks. +The official _[Swift Programming Language](https://itunes.apple.com/us/book/swift-programming-language/id881256329)_ book from Apple is now available via iBooks. It goes into much more detail than this guide, and if you have the time and patience to read it, it's recommended. Some of these examples are from that book. Another great reference is _About Swift_ on Swift's [website](https://docs.swift.org/swift-book/). ```swift // import a module -import UIKit +import Foundation -// -// MARK: Basics -// +// Single-line comments are prefixed with // +// Multi-line comments start with /* and end with */ +/* Nested multiline comments + /* ARE */ + allowed + */ // Xcode supports landmarks to annotate your code and lists them in the jump bar // MARK: Section mark @@ -31,220 +35,383 @@ import UIKit // TODO: Do something soon // FIXME: Fix this code -// In Swift 2, println and print were combined into one print method. Print automatically appends a new line. -print("Hello, world") // println is now print -print("Hello, world", terminator: "") // printing without appending a newline +//MARK: Hello, World +// From Swift 3 on, to print, just use the `print` method. +// It automatically appends a new line. +print("Hello, world") + +// +// MARK: - Variables +// + + +//Use `let` to declare a constant and `var` to declare a variable. +let theAnswer = 42 +var theQuestion = "What is the Answer?" +theQuestion = "How many roads must a man walk down?" +theQuestion = "What is six by nine?" +// Atttempting to reassign a constant throws a compile-time error +//theAnswer = 54 + +// Both variables and constants can be declared before they are given a value, +// but must be given a value before they are used +let someConstant: Int +var someVariable: String +// These lines will throw errors: +//print(someConstant) +//print(someVariable) +someConstant = 0 +someVariable = "0" +// These lines are now valid: +print(someConstant) +print(someVariable) + +// As you can see above, variable types are automatically inferred. +// To explicitly declare the type, write it after the variable name, +// separated by a colon. +let aString: String = "A string" +let aDouble: Double = 0 + +// Values are never implicitly converted to another type. +// Explicitly make instances of the desired type. +let stringWithDouble = aString + String(aDouble) +let intFromDouble = Int(aDouble) + +// For strings, use string interpolation +let descriptionString = "The value of aDouble is \(aDouble)" +// You can put any expression inside string interpolation. +let equation = "Six by nine is \(6 * 9), not 42!" +// To avoid escaping double quotes and backslashes, change the string delimiter +let explanationString = #"The string I used was "The value of aDouble is \(aDouble)" and the result was \#(descriptionString)"# +// You can put as many number signs as you want before the opening quote, +// just match them at the ending quote. They also change the escape character +// to a backslash followed by the same number of number signs. + +let multiLineString = """ + This is a multi-line string. + It's called that because it takes up multiple lines (wow!) + Any indentation beyond the closing quotation marks is kept, the rest is discarded. + You can include " or "" in multi-line strings because the delimeter is three "s. + """ + +// Arrays +let shoppingList = ["catfish", "water", "tulips",] //commas are allowed after the last element +let secondElement = shoppingList[1] // Arrays are 0-indexed + +// Arrays declared with let are immutable; the following line throws a compile-time error +//shoppingList[2] = "mango" + +// Arrays are structs (more on that later), so this creates a copy instead of referencing the same object +var mutableShoppingList = shoppingList +mutableShoppingList[2] = "mango" + +// == is equality +shoppingList == mutableShoppingList // false + +// Dictionaries declared with let are also immutable +var occupations = [ + "Malcolm": "Captain", + "Kaylee": "Mechanic" +] +occupations["Jayne"] = "Public Relations" +// Dictionaries are also structs, so this also creates a copy +let immutableOccupations = occupations + +immutableOccupations == occupations // true -// variables (var) value can change after being set -// constants (let) value can NOT be changed after being set +// Arrays and dictionaries both automatically grow as you add elements +mutableShoppingList.append("blue paint") +occupations["Tim"] = "CEO" -var myVariable = 42 +// They can both be set to empty +mutableShoppingList = [] +occupations = [:] + +let emptyArray = [String]() +let emptyArray2 = Array<String>() // same as above +// [T] is shorthand for Array<T> +let emptyArray3: [String] = [] // Declaring the type explicitly allows you to set it to an empty array +let emptyArray4: Array<String> = [] // same as above + +// [Key: Value] is shorthand for Dictionary<Key, Value> +let emptyDictionary = [String: Double]() +let emptyDictionary2 = Dictionary<String, Double>() // same as above +var emptyMutableDictionary: [String: Double] = [:] +var explicitEmptyMutableDictionary: Dictionary<String, Double> = [:] // same as above + +// MARK: Other variables let øπΩ = "value" // unicode variable names -let π = 3.1415926 -let convenience = "keyword" // contextual variable name -let weak = "keyword"; let override = "another keyword" // statements can be separated by a semi-colon -let `class` = "keyword" // backticks allow keywords to be used as variable names -let explicitDouble: Double = 70 -let intValue = 0007 // 7 -let largeIntValue = 77_000 // 77000 -let label = "some text " + String(myVariable) // String construction -let piText = "Pi = \(π), Pi 2 = \(π * 2)" // String interpolation - -// Build Specific values -// uses -D build configuration -#if false - print("Not printed") - let buildValue = 3 -#else - let buildValue = 7 -#endif -print("Build value: \(buildValue)") // Build value: 7 +let 🤯 = "wow" // emoji variable names -/* -Optionals are a Swift language feature that either contains a value, -or contains nil (no value) to indicate that a value is missing. -A question mark (?) after the type marks the value as optional. +// Keywords can be used as variable names +// These are contextual keywords that wouldn't be used now, so are allowed +let convenience = "keyword" +let weak = "another keyword" +let override = "another keyword" + +// Using backticks allows keywords to be used as variable names even if they wouldn't be allowed normally +let `class` = "keyword" -Because Swift requires every property to have a value, even nil must be -explicitly stored as an Optional value. +// MARK: - Optionals + +/* + Optionals are a Swift language feature that either contains a value, + or contains nil (no value) to indicate that a value is missing. + Nil is roughly equivalent to `null` in other languages. + A question mark (?) after the type marks the value as optional of that type. + + If a type is not optional, it is guaranteed to have a value. + + Because Swift requires every property to have a type, even nil must be + explicitly stored as an Optional value. + + Optional<T> is an enum, with the cases .none (nil) and .some(T) (the value) + */ -Optional<T> is an enum. -*/ var someOptionalString: String? = "optional" // Can be nil -// same as above, but ? is a postfix operator (syntax candy) -var someOptionalString2: Optional<String> = "optional" +// T? is shorthand for Optional<T> — ? is a postfix operator (syntax candy) +let someOptionalString2: Optional<String> = nil +let someOptionalString3 = String?.some("optional") // same as the first one +let someOptionalString4 = String?.none //nil + +/* + To access the value of an optional that has a value, use the postfix + operator !, which force-unwraps it. Force-unwrapping is like saying, "I + know that this optional definitely has a value, please give it to me." + + Trying to use ! to access a non-existent optional value triggers a + runtime error. Always make sure that an optional contains a non-nil + value before using ! to force-unwrap its value. + */ if someOptionalString != nil { // I am not nil if someOptionalString!.hasPrefix("opt") { print("has the prefix") } - - let empty = someOptionalString?.isEmpty } -someOptionalString = nil -/* -Trying to use ! to access a non-existent optional value triggers a runtime -error. Always make sure that an optional contains a non-nil value before -using ! to force-unwrap its value. -*/ - -// implicitly unwrapped optional -var unwrappedString: String! = "Value is expected." -// same as above, but ! is a postfix operator (more syntax candy) -var unwrappedString2: ImplicitlyUnwrappedOptional<String> = "Value is expected." - -// If let structure - -// If let is a special structure in Swift that allows you to check if an Optional rhs holds a value, and in case it does - unwraps and assigns it to the lhs. -if let someOptionalStringConstant = someOptionalString { +// Swift supports "optional chaining," which means that you can call functions +// or get properties of optional values and they are optionals of the appropriate type. +// You can even do this multiple times, hence the name "chaining." + +let empty = someOptionalString?.isEmpty // Bool? + +// if-let structure - +// if-let is a special structure in Swift that allows you to check +// if an Optional rhs holds a value, and if it does unwrap +// and assign it to the lhs. +if let someNonOptionalStringConstant = someOptionalString { // has `Some` value, non-nil - if !someOptionalStringConstant.hasPrefix("ok") { + // someOptionalStringConstant is of type String, not type String? + if !someNonOptionalStringConstant.hasPrefix("ok") { // does not have the prefix } } -// The nil-coalescing operator ?? unwraps an optional if it contains a non-nil value, or returns a default value. -var someOptionalString: String? -let someString = someOptionalString ?? "abc" -print(someString) // abc +//if-var is allowed too! +if var someNonOptionalString = someOptionalString { + someNonOptionalString = "Non optional AND mutable" + print(someNonOptionalString) +} -// Swift has support for storing a value of any type. -// For that purposes there is two keywords: `Any` and `AnyObject` -// `AnyObject` == `id` from Objective-C -// `Any` – also works with any scalar values (Class, Int, struct, etc.) -var anyVar: Any = 7 -anyVar = "Changed value to a string, not good practice, but possible." -let anyObjectVar: AnyObject = Int(1) as NSNumber +// You can bind multiple optional values in one if-let statement. +// If any of the bound values are nil, the if statement does not execute. +if let first = someOptionalString, let second = someOptionalString2, + let third = someOptionalString3, let fourth = someOptionalString4 { + print("\(first), \(second), \(third), and \(fourth) are all not nil") +} -/* - Comment here +//if-let supports "," (comma) clauses, which can be used to +// enforce conditions on newly-bound optional values. +// Both the assignment and the "," clause must pass. +let someNumber: Int? = 7 +if let num = someNumber, num > 3 { + print("num is not nil and is greater than 3") +} - /* - Nested comments are also supported - */ -*/ +// Implicitly unwrapped optional — An optional value that doesn't need to be unwrapped +let unwrappedString: String! = "Value is expected." -// -// MARK: Collections -// +// Here's the difference: +let forcedString = someOptionalString! // requires an exclamation mark +let implicitString = unwrappedString // doesn't require an exclamation mark /* -Array and Dictionary types are structs. So `let` and `var` also indicate -that they are mutable (var) or immutable (let) when declaring these types. -*/ - -// Array -var shoppingList = ["catfish", "water", "lemons"] -shoppingList[1] = "bottle of water" -let emptyArray = [String]() // let == immutable -let emptyArray2 = Array<String>() // same as above -var emptyMutableArray = [String]() // var == mutable -var explicitEmptyMutableStringArray: [String] = [] // same as above - + You can think of an implicitly unwrapped optional as giving permission + for the optional to be unwrapped automatically whenever it's used. + Rather than placing an exclamation mark after the optional's name each time you use it, + you place an exclamation mark after the optional's type when you declare it. + */ -// Dictionary -var occupations = [ - "Malcolm": "Captain", - "kaylee": "Mechanic" -] -occupations["Jayne"] = "Public Relations" -let emptyDictionary = [String: Float]() // let == immutable -let emptyDictionary2 = Dictionary<String, Float>() // same as above -var emptyMutableDictionary = [String: Float]() // var == mutable -var explicitEmptyMutableDictionary: [String: Float] = [:] // same as above +// Otherwise, you can treat an implicitly unwrapped optional the same way the you treat a normal optional +// (i.e., if-let, != nil, etc.) +// Pre-Swift 5, T! was shorthand for ImplicitlyUnwrappedOptional<T> +// Swift 5 and later, using ImplicitlyUnwrappedOptional throws a compile-time error. +//var unwrappedString2: ImplicitlyUnwrappedOptional<String> = "Value is expected." //error -// -// MARK: Control Flow -// - -// Condition statements support "," (comma) clauses, which can be used -// to help provide conditions on optional values. -// Both the assignment and the "," clause must pass. -let someNumber = Optional<Int>(7) -if let num = someNumber, num > 3 { - print("num is greater than 3") -} - -// for loop (array) -let myArray = [1, 1, 2, 3, 5] -for value in myArray { - if value == 1 { - print("One!") - } else { - print("Not one!") - } -} +// The nil-coalescing operator ?? unwraps an optional if it contains a non-nil value, or returns a default value. +someOptionalString = nil +let someString = someOptionalString ?? "abc" +print(someString) // abc +// a ?? b is shorthand for a != nil ? a! : b -// for loop (dictionary) -var dict = ["one": 1, "two": 2] -for (key, value) in dict { - print("\(key): \(value)") -} +// MARK: - Control Flow -// for loop (range) -for i in -1...shoppingList.count { - print(i) -} -shoppingList[1...2] = ["steak", "peacons"] -// use ..< to exclude the last number +let condition = true +if condition { print("condition is true") } // can't omit the braces -// while loop -var i = 1 -while i < 1000 { - i *= 2 +if theAnswer > 50 { + print("theAnswer > 50") +} else if condition { + print("condition is true") +} else { + print("Neither are true") } -// repeat-while loop -repeat { - print("hello") -} while 1 == 2 +// The condition in an `if` statement must be a `Bool`, so the following code is an error, not an implicit comparison to zero +//if 5 { +// print("5 is not zero") +//} // Switch +// Must be exhaustive +// Does not implicitly fall through, use the fallthrough keyword // Very powerful, think `if` statements with syntax candy // They support String, object instances, and primitives (Int, Double, etc) let vegetable = "red pepper" +let vegetableComment: String switch vegetable { case "celery": - let vegetableComment = "Add some raisins and make ants on a log." -case "cucumber", "watercress": - let vegetableComment = "That would make a good tea sandwich." + vegetableComment = "Add some raisins and make ants on a log." +case "cucumber", "watercress": // match multiple values + vegetableComment = "That would make a good tea sandwich." case let localScopeValue where localScopeValue.hasSuffix("pepper"): - let vegetableComment = "Is it a spicy \(localScopeValue)?" + vegetableComment = "Is it a spicy \(localScopeValue)?" default: // required (in order to cover all possible input) - let vegetableComment = "Everything tastes good in soup." + vegetableComment = "Everything tastes good in soup." +} +print(vegetableComment) + +// You use the `for-in` loop to iterate over a sequence, such as an array, dictionary, range, etc. +for element in shoppingList { + print(element) // shoppingList is of type `[String]`, so element is of type `String` +} +//Iterating through a dictionary does not guarantee any specific order +for (person, job) in immutableOccupations { + print("\(person)'s job is \(job)") +} +for i in 1...5 { + print(i, terminator: " ") // Prints "1 2 3 4 5" +} +for i in 0..<5 { + print(i, terminator: " ") // Prints "0 1 2 3 4" +} +//for index in range can replace a C-style for loop: +// for (int i = 0; i < 10; i++) { +// //code +// } +//becomes: +// for i in 0..<10 { +// //code +// } +//To step by more than one, use the stride(from:to:by:) or stride(from:through:by) functions +//`for i in stride(from: 0, to: 10, by: 2)` is the same as `for (int i = 0; i < 10; i += 2)` +//`for i in stride(from: 0, through: 10, by: 2)` is the same as `for (int i = 0; i <= 10; i += 2) + +// while loops are just like most languages +var i = 0 +while i < 5 { + i += Bool.random() ? 1 : 0 + print(i) } -// -// MARK: Functions -// +// This is like a do-while loop in other languages — the body of the loop executes a minimum of once +repeat { + i -= 1 + i += Int.random(in: 0...3) +} while i < 5 -// Functions are a first-class type, meaning they can be nested -// in functions and can be passed around +// The continue statement continues executing a loop at the next iteration +// The break statement ends a swift or loop immediately -// Function with Swift header docs (format as Swift-modified Markdown syntax) +// MARK: - Functions -/** -A greet operation +// Functions are a first-class type, meaning they can be nested in functions and can be passed around. -- A bullet in docs -- Another bullet in the docs +// Function with Swift header docs (format as Swift-modified Markdown syntax) -- Parameter name : A name -- Parameter day : A day -- Returns : A string containing the name and day value. -*/ +/// A greet operation. +/// +/// - Parameters: +/// - name: A name. +/// - day: A day. +/// - Returns: A string containing the name and day value. func greet(name: String, day: String) -> String { return "Hello \(name), today is \(day)." } greet(name: "Bob", day: "Tuesday") -// similar to above except for the function parameter behaviors -func greet2(name: String, externalParamName localParamName: String) -> String { - return "Hello \(name), the day is \(localParamName)" +// Ideally, function names and parameter labels combine to make function calls similar to sentences. +func sayHello(to name: String, onDay day: String) -> String { + return "Hello \(name), the day is \(day)" +} +sayHello(to: "John", onDay: "Sunday") + +//Functions that don't return anything can omit the return arrow; they don't need to say that they return Void (although they can). +func helloWorld() { + print("Hello, World!") +} + +// Argument labels can be blank +func say(_ message: String) { + print(#"I say "\#(message)""#) +} +say("Hello") + +// Default parameters can be ommitted when calling the function. +func printParameters(requiredParameter r: Int, optionalParameter o: Int = 10) { + print("The required parameter was \(r) and the optional parameter was \(o)") +} +printParameters(requiredParameter: 3) +printParameters(requiredParameter: 3, optionalParameter: 6) + +// Variadic args — only one set per function. +func setup(numbers: Int...) { + // it's an array + let _ = numbers[0] + let _ = numbers.count +} + +// pass by ref +func swapTwoInts(a: inout Int, b: inout Int) { + let tempA = a + a = b + b = tempA +} +var someIntA = 7 +var someIntB = 3 +swapTwoInts(a: &someIntA, b: &someIntB) //must be called with an & before the variable name. +print(someIntB) // 7 + +type(of: greet) // (String, String) -> String +type(of: helloWorld) // () -> Void + +// Passing and returning functions +func makeIncrementer() -> ((Int) -> Int) { + func addOne(number: Int) -> Int { + return 1 + number + } + return addOne +} +var increment = makeIncrementer() +increment(7) + +func performFunction(_ function: (String, String) -> String, on string1: String, and string2: String) { + let result = function(string1, string2) + print("The result of calling the function on \(string1) and \(string2) was \(result)") } -greet2(name: "John", externalParamName: "Sunday") // Function that returns multiple items in a tuple func getGasPrices() -> (Double, Double, Double) { @@ -271,46 +438,24 @@ print("Highest gas price: \(pricesTuple2.highestPrice)") func testGuard() { // guards provide early exits or breaks, placing the error handler code near the conditions. // it places variables it declares in the same scope as the guard statement. + // They make it easier to avoid the "pyramid of doom" guard let aNumber = Optional<Int>(7) else { - return + return // guard statements MUST exit the scope that they are in. + // They generally use `return` or `throw`. } - + print("number is \(aNumber)") } testGuard() -// Variadic Args -func setup(numbers: Int...) { - // it's an array - let _ = numbers[0] - let _ = numbers.count -} - -// Passing and returning functions -func makeIncrementer() -> ((Int) -> Int) { - func addOne(number: Int) -> Int { - return 1 + number - } - return addOne -} -var increment = makeIncrementer() -increment(7) - -// pass by ref -func swapTwoInts(a: inout Int, b: inout Int) { - let tempA = a - a = b - b = tempA -} -var someIntA = 7 -var someIntB = 3 -swapTwoInts(a: &someIntA, b: &someIntB) -print(someIntB) // 7 +// Note that the print function is declared like so: +// func print(_ input: Any..., separator: String = " ", terminator: String = "\n") +// To print without a newline: +print("No newline", terminator: "") +print("!") +// MARK: - Closures -// -// MARK: Closures -// var numbers = [1, 2, 6] // Functions are special case closures ({}) @@ -336,85 +481,157 @@ numbers = numbers.sorted { $0 > $1 } print(numbers) // [18, 6, 3] -// -// MARK: Structures -// +// MARK: - Enums -// Structures and classes have very similar capabilities -struct NamesTable { - let names: [String] +// Enums can optionally be of a specific type or on their own. +// They can contain methods like classes. - // Custom subscript - subscript(index: Int) -> String { - return names[index] +enum Suit { + case spades, hearts, diamonds, clubs + var icon: Character { + switch self { + case .spades: + return "♤" + case .hearts: + return "♡" + case .diamonds: + return "♢" + case .clubs: + return "♧" + } } } -// Structures have an auto-generated (implicit) designated initializer -let namesTable = NamesTable(names: ["Me", "Them"]) -let name = namesTable[1] -print("Name is \(name)") // Name is Them - -// -// MARK: Error Handling -// +// Enum values allow short hand syntax, no need to type the enum type +// when the variable is explicitly declared +var suitValue: Suit = .hearts -// The `Error` protocol is used when throwing errors to catch -enum MyError: Error { - case badValue(msg: String) - case reallyBadValue(msg: String) +// Conforming to the CaseIterable protocol automatically synthesizes the allCases property, +// which contains all the values. It works on enums without associated values or @available attributes. +enum Rank: CaseIterable { + case ace + case two, three, four, five, six, seven, eight, nine, ten + case jack, queen, king + var icon: String { + switch self { + case .ace: + return "A" + case .two: + return "2" + case .three: + return "3" + case .four: + return "4" + case .five: + return "5" + case .six: + return "6" + case .seven: + return "7" + case .eight: + return "8" + case .nine: + return "9" + case .ten: + return "10" + case .jack: + return "J" + case .queen: + return "Q" + case .king: + return "K" + } + } } -// functions marked with `throws` must be called using `try` -func fakeFetch(value: Int) throws -> String { - guard 7 == value else { - throw MyError.reallyBadValue(msg: "Some really bad value") +for suit in [Suit.clubs, .diamonds, .hearts, .spades] { + for rank in Rank.allCases { + print("\(rank.icon)\(suit.icon)") } +} - return "test" +// String enums can have direct raw value assignments +// or their raw values will be derived from the Enum field +enum BookName: String { + case john + case luke = "Luke" } +print("Name: \(BookName.john.rawValue)") -func testTryStuff() { - // assumes there will be no error thrown, otherwise a runtime exception is raised - let _ = try! fakeFetch(value: 7) +// Enum with associated Values +enum Furniture { + // Associate with Int + case desk(height: Int) + // Associate with String and Int + case chair(String, Int) + + func description() -> String { + //either placement of let is acceptable + switch self { + case .desk(let height): + return "Desk with \(height) cm" + case let .chair(brand, height): + return "Chair of \(brand) with \(height) cm" + } + } +} - // if an error is thrown, then it proceeds, but if the value is nil - // it also wraps every return value in an optional, even if its already optional - let _ = try? fakeFetch(value: 7) +var desk: Furniture = .desk(height: 80) +print(desk.description()) // "Desk with 80 cm" +var chair = Furniture.chair("Foo", 40) +print(chair.description()) // "Chair of Foo with 40 cm" - do { - // normal try operation that provides error handling via `catch` block - try fakeFetch(value: 1) - } catch MyError.badValue(let msg) { - print("Error message: \(msg)") - } catch { - // must be exhaustive +// MARK: - Structures & Classes + +/* + Structures and classes in Swift have many things in common. Both can: + - Define properties to store values + - Define methods to provide functionality + - Define subscripts to provide access to their values using subscript syntax + - Define initializers to set up their initial state + - Be extended to expand their functionality beyond a default implementation + - Conform to protocols to provide standard functionality of a certain kind + + Classes have additional capabilities that structures don't have: + - Inheritance enables one class to inherit the characteristics of another. + - Type casting enables you to check and interpret the type of a class instance at runtime. + - Deinitializers enable an instance of a class to free up any resources it has assigned. + - Reference counting allows more than one reference to a class instance. + + Unless you need to use a class for one of these reasons, use a struct. + + Structures are value types, while classes are reference types. + */ + +// MARK: Structures + +struct NamesTable { + let names: [String] + + // Custom subscript + subscript(index: Int) -> String { + return names[index] } } -testTryStuff() -// -// MARK: Classes -// +// Structures have an auto-generated (implicit) designated "memberwise" initializer +let namesTable = NamesTable(names: ["Me", "Them"]) +let name = namesTable[1] +print("Name is \(name)") // Name is Them -// Classes, structures and its members have three levels of access control -// They are: internal (default), public, private +// MARK: Classes -public class Shape { - public func getArea() -> Int { +class Shape { + func getArea() -> Int { return 0 } } -// All methods and properties of a class are public. -// If you just need to store data in a -// structured object, you should use a `struct` - -internal class Rect: Shape { +class Rect: Shape { var sideLength: Int = 1 - + // Custom getter and setter property - private var perimeter: Int { + var perimeter: Int { get { return 4 * sideLength } @@ -423,16 +640,16 @@ internal class Rect: Shape { sideLength = newValue / 4 } } - + // Computed properties must be declared as `var`, you know, cause' they can change var smallestSideLength: Int { return self.sideLength - 1 } - + // Lazily load a property // subShape remains nil (uninitialized) until getter called lazy var subShape = Rect(sideLength: 4) - + // If you don't need a custom getter and setter, // but still want to run code before and after getting or setting // a property, you can use `willSet` and `didSet` @@ -442,19 +659,19 @@ internal class Rect: Shape { print(someIdentifier) } } - + init(sideLength: Int) { self.sideLength = sideLength // always super.init last when init custom properties super.init() } - + func shrink() { if sideLength > 0 { sideLength -= 1 } } - + override func getArea() -> Int { return sideLength * sideLength } @@ -486,13 +703,13 @@ class Circle: Shape { override func getArea() -> Int { return 3 * radius * radius } - + // Place a question mark postfix after `init` is an optional init // which can return nil init?(radius: Int) { self.radius = radius super.init() - + if radius <= 0 { return nil } @@ -509,104 +726,143 @@ if let circle = myEmptyCircle { print("circle is not nil") } +// MARK: - Protocols -// -// MARK: Enums -// +// protocols are also known as interfaces in some other languages -// Enums can optionally be of a specific type or on their own. -// They can contain methods like classes. +// `protocol`s can require that conforming types have specific +// instance properties, instance methods, type methods, +// operators, and subscripts. -enum Suit { - case spades, hearts, diamonds, clubs - func getIcon() -> String { - switch self { - case .spades: return "♤" - case .hearts: return "♡" - case .diamonds: return "♢" - case .clubs: return "♧" - } - } +protocol ShapeGenerator { + var enabled: Bool { get set } + func buildShape() -> Shape } -// Enum values allow short hand syntax, no need to type the enum type -// when the variable is explicitly declared -var suitValue: Suit = .hearts +// MARK: - Other -// String enums can have direct raw value assignments -// or their raw values will be derived from the Enum field -enum BookName: String { - case john - case luke = "Luke" -} -print("Name: \(BookName.john.rawValue)") +// MARK: Typealiases -// Enum with associated Values -enum Furniture { - // Associate with Int - case desk(height: Int) - // Associate with String and Int - case chair(String, Int) +// Typealiases allow one type (or composition of types) to be referred to by another name +typealias Integer = Int +let myInteger: Integer = 0 - func description() -> String { - switch self { - case .desk(let height): - return "Desk with \(height) cm" - case .chair(let brand, let height): - return "Chair of \(brand) with \(height) cm" - } - } -} +// MARK: = Operator -var desk: Furniture = .desk(height: 80) -print(desk.description()) // "Desk with 80 cm" -var chair = Furniture.chair("Foo", 40) -print(chair.description()) // "Chair of Foo with 40 cm" +// Assignment does not return a value. This means it can't be used in conditional statements, +// and the following statement is also illegal +// let multipleAssignment = theQuestion = "No questions asked" +//But you can do this: +let multipleAssignment = "No questions asked", secondConstant = "No answers given" +// MARK: Ranges -// -// MARK: Protocols -// +// The ..< and ... operators create ranges. -// `protocol`s can require that conforming types have specific -// instance properties, instance methods, type methods, -// operators, and subscripts. +// ... is inclusive on both ends (a "closed range") — mathematically, [0, 10] +let _0to10 = 0...10 +// ..< is inclusive on the left, exclusive on the right (a "range") — mathematically, [0, 10) +let singleDigitNumbers = 0..<10 +// You can omit one end (a "PartialRangeFrom") — mathematically, [0, ∞) +let toInfinityAndBeyond = 0... +// Or the other end (a "PartialRangeTo") — mathematically, (-∞, 0) +let negativeInfinityToZero = ..<0 +// (a "PartialRangeThrough") — mathematically, (-∞, 0] +let negativeInfinityThroughZero = ...0 -protocol ShapeGenerator { - var enabled: Bool { get set } - func buildShape() -> Shape +// MARK: Wildcard operator + +// In Swift, _ (underscore) is the wildcard operator, which allows values to be ignored + +// It allows functions to be declared without argument labels: +func function(_ labelLessParameter: Int, label labeledParameter: Int, labelAndParameterName: Int) { + print(labelLessParameter, labeledParameter, labelAndParameterName) } +function(0, label: 0, labelAndParameterName: 0) -// Protocols declared with @objc allow optional functions, -// which allow you to check for conformance. These functions must be -// marked with @objc also. -@objc protocol TransformShape { - @objc optional func reshape() - @objc optional func canReshape() -> Bool +// You can ignore the return values of functions +func printAndReturn(_ str: String) -> String { + print(str) + return str } +let _ = printAndReturn("Some String") -class MyShape: Rect { - var delegate: TransformShape? +// You can ignore part of a tuple and keep part of it +func returnsTuple() -> (Int, Int) { + return (1, 2) +} +let (_, two) = returnsTuple() - func grow() { - sideLength += 2 +// You can ignore closure parameters +let closure: (Int, Int) -> String = { someInt, _ in + return "\(someInt)" +} +closure(1, 2) // returns 1 - // Place a question mark after an optional property, method, or - // subscript to gracefully ignore a nil value and return nil - // instead of throwing a runtime error ("optional chaining"). - if let reshape = self.delegate?.canReshape?(), reshape { - // test for delegate then for method - self.delegate?.reshape?() - } - } +// You can ignore the value in a for loop +for _ in 0..<10 { + // Code to execute 10 times } +// MARK: Access Control -// -// MARK: Other -// +/* + Swift has five levels of access control: + - Open: Accessible *and subclassible* in any module that imports it. + - Public: Accessible in any module that imports it, subclassible in the module it is declared in. + - Internal: Accessible and subclassible in the module it is declared in. + - Fileprivate: Accessible and subclassible in the file it is declared in. + - Private: Accessible and subclassible in the enclosing declaration (think inner classes/structs/enums) + + See more here: https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html + */ + +// MARK: Conditional Compilation, Compile-Time Diagnostics, & Availability Conditions + +// Conditional Compilation +#if false +print("This code will not be compiled") +#else +print("This code will be compiled") +#endif +/* + Options are: + os() macOS, iOS, watchOS, tvOS, Linux + arch() i386, x86_64, arm, arm64 + swift() >= or < followed by a version number + compiler() >= or < followed by a version number + canImport() A module name + targetEnvironment() simulator + */ +#if swift(<3) +println() +#endif + +// Compile-Time Diagnostics +// You can use #warning(message) and #error(message) to have the compiler emit warnings and/or errors +#warning("This will be a compile-time warning") +// #error("This would be a compile-time error") + +//Availability Conditions +if #available(iOSMac 10.15, *) { + // macOS 10.15 is available, you can use it here +} else { + // macOS 10.15 is not available, use alternate APIs +} + +// MARK: Any and AnyObject + +// Swift has support for storing a value of any type. +// For that purpose there are two keywords: `Any` and `AnyObject` +// `AnyObject` == `id` from Objective-C +// `Any` works with any values (class, Int, struct, etc.) +var anyVar: Any = 7 +anyVar = "Changed value to a string, not good practice, but possible." +let anyObjectVar: AnyObject = Int(1) as NSNumber -// `extension`s: Add extra functionality to an already existing type +// MARK: Extensions + +// Extensions allow you to add extra functionality to an already-declared type, even one that you don't have the source code for. // Square now "conforms" to the `CustomStringConvertible` protocol extension Square: CustomStringConvertible { @@ -619,17 +875,23 @@ print("Square: \(mySquare)") // You can also extend built-in types extension Int { - var customProperty: String { - return "This is \(self)" + var doubled: Int { + return self * 2 } - - func multiplyBy(num: Int) -> Int { + + func multipliedBy(num: Int) -> Int { return num * self } + + mutating func multiplyBy(num: Int) { + self *= num + } } -print(7.customProperty) // "This is 7" -print(14.multiplyBy(num: 3)) // 42 +print(7.doubled) // 14 +print(7.doubled.multipliedBy(num: 3)) // 42 + +// MARK: Generics // Generics: Similar to Java and C#. Use the `where` keyword to specify the // requirements of the generics. @@ -642,10 +904,21 @@ func findIndex<T: Equatable>(array: [T], valueToFind: T) -> Int? { } return nil } -let foundAtIndex = findIndex(array: [1, 2, 3, 4], valueToFind: 3) -print(foundAtIndex == 2) // true +findIndex(array: [1, 2, 3, 4], valueToFind: 3) // 2 + +// You can extend types with generics as well +extension Array where Array.Element == Int { + var sum: Int { + var total = 0 + for el in self { + total += el + } + return total + } +} + +// MARK: Operators -// Operators: // Custom operators can start with the characters: // / = - + * % < > ! & | ^ . ~ // or @@ -678,4 +951,40 @@ var bar: Float = 20 foo <-> bar print("foo is \(foo), bar is \(bar)") // "foo is 20.0, bar is 10.0" + +// MARK: - Error Handling + +// The `Error` protocol is used when throwing errors to catch +enum MyError: Error { + case badValue(msg: String) + case reallyBadValue(msg: String) +} + +// functions marked with `throws` must be called using `try` +func fakeFetch(value: Int) throws -> String { + guard 7 == value else { + throw MyError.reallyBadValue(msg: "Some really bad value") + } + + return "test" +} + +func testTryStuff() { + // assumes there will be no error thrown, otherwise a runtime exception is raised + let _ = try! fakeFetch(value: 7) + + // if an error is thrown, then it proceeds, but if the value is nil + // it also wraps every return value in an optional, even if its already optional + let _ = try? fakeFetch(value: 7) + + do { + // normal try operation that provides error handling via `catch` block + try fakeFetch(value: 1) + } catch MyError.badValue(let msg) { + print("Error message: \(msg)") + } catch { + // must be exhaustive + } +} +testTryStuff() ``` diff --git a/th-th/pascal.th.html.markdown b/th-th/pascal.th.html.markdown new file mode 100644 index 00000000..bf1da958 --- /dev/null +++ b/th-th/pascal.th.html.markdown @@ -0,0 +1,236 @@ +--- +language: Pascal +filename: learnpascal.pas +contributors: + - ["Ganesha Danu", "http://github.com/blinfoldking"] + - ["Keith Miyake", "https://github.com/kaymmm"] +translators: + - ["Worajedt Sitthidumrong", "https://bitbucket.org/wrj"] +lang: th-th +--- + +> Pascal (ปาสกาล) เป็นภาษาโปรแกรมมิ่งทั้งแบบ imperative และ procedural ที่ออกแบบโดย Niklaus Wirth (นิเคล้า เวิร์ท) เมื่อปี 1968-69 และเผยแพร่ตอน 1970 โดยเน้นให้เป็นภาษาที่เล็ก มีประสิทธิภาพ เพื่อเสริมการเขียนโปรแกรมที่มีแนวปฏิบัติที่ดีด้วยการใช้โครงสร้างของตัวภาษา และโครงสร้างข้อมูลมากำกับ ชื่อของภาษานี้ตั้งเป็นเกียรติให้กับนักคณิตศาสตร์ชาวฝรั่งเศส, นักปรัชญา และนักฟิสิกส์ ชื่อ Blaise Pascal (เบลส ปาสกาล) ข้อมูลจาก : [วิกิพีเดีย][1] + +การคอมไพล์และรันโค้ดภาษาปาสกาลนี้ สามารถใช้ปาสกาลคอมไพลเลอร์ฟรีชื่อ Free Pascal ได้ โดย [ดาวน์โหลดที่นี่][2] + +ด้านล่างจะเป็นโครงสร้างภาษาหลัก ๆ ที่ต้องเข้าใจก่อน ปาสกาลจะเป็นภาษาที่เข้มงวดกับโครงสร้างโค้ดมาก + +```pascal +//โปรแกรมปาสกาล +//คอมเม้นต์เขียนแบบนี้ ใช้สแลชสองครั้ง +{ + แต่ถ้าต้องการคอมเม้นหลาย ๆ บรรทัด + ให้ใช้ วงเล็บปีกกา (curly brackets) + เนื้อหาอยู่บรรทัดเดียวกันกับปีกกาได้ +} + +//อย่างแรก ต้องประกาศ ชื่อโปรแกรม +program learn_pascal; //<-- ห้ามลืม semicolon + +const + { + ประกาศค่าคงที่ (constant) ในบล็อคนี้ + } +type + { + ประกาศชนิดข้อมูลของเราเองที่นี่ ไม่ว่าจะเป็น ชนิดข้อมูลทั่วไป + หรือจะเป็นคลาส + } +var + { + ตัวแปร ในภาษาปาสกาล ไม่เหมือนกับภาษาอื่น ๆ + เพราะต้องประกาศในบล็อค var ก่อนใช้งานเสมอ + } + +//มาถึงส่วนโปรแกรมหลัก หรือ main fucntion นั่นเอง +begin + { + โค้ดเราทำงานอะไร อย่างไร ก็เริ่มรันจากตรงนี้ + } +end. // จบการทำงานของ _โปรแกรม_ เราจะจบด้วย จุลภาค "." +``` + +โค้ดต่อจากนี้ จะเป็นการอธิบายประกาศตัวแปรของปาสกาล + +```pascal +//การประกาศตัวแปร ทำได้แบบนี้ +//var ชื่อตัวแปร : ชนิด ; +var a:integer; +var b:integer; + +//หรือแบบที่นิยมมากกว่า คือเอามาเก็บในบล็อค var ทั้งหมด +var + a : integer; + b : integer; + +//ถ้าจะเอาแบบสั้น ๆ บรรทัดเดียว ก็ทำได้ ทำได้พร้อมกันหลาย ๆ ตัวแปรด้วย +var a,b : integer; +``` + +โค้ดตัวอย่างนี้เป็นโปรแกรม Learn\_More ที่เป็นโครงสร้างโปรแกรมง่าย ๆ ที่จบสมบูรณ์หนึ่งโปรแกรม มีบล็อค program, const, type, main (Begin..End.) + +```pascal +program Learn_More; +// มาต่อเรื่อง ชนิดของข้อมูล (data types) และ ตัวดำเนินการ (operators) + +const + PI = 3.141592654; + GNU = 'GNU''s Not Unix'; + // ค่าคงที่ ให้ตั้งชื่อเป็น ตัวพิมพ์ใหญ่ ทั้งหมด ใช้กับชนิดข้อมูลใดๆ ก็ได้ + // ค่าคงที่ ก็ตามชื่อเลย กำหนดค่าแล้ว ไม่สามารถเปลี่ยนแปลงได้ขณะรัน + +// การประกาศชนิดข้อมูลของเราเอง +// "ชนิด" ของตัวแปรสองแบบนี้ จะนำไปใช้ด้านล่าง +type + ch_array : array [0..255] of char; + // อะเรย์ เป็นชนิดข้อมูลที่มี ความยาว/ช่องเก็บข้อมูล และ ชนิดข้อมูล + // โค้ดด้านบน เป็นการประกาศอะเรย์ของตัวอักษา 255 ตัวอักษา + // ซึ่งได้ ความยาว/ช่องเก็บข้อมูลในตัวแปรตัวนี้ 256 ช่องที่เป็นข้อความ + md_array : array of array of integer; + // ด้านบนนี้ เป็นตัวอย่าง อะเรย์สองมิติของเลขจำนวนเต็ม + // อะเรย์ ยังซ้อนกับอะเรย์ได้อีกด้วย ทำให้สร้าง อะเรย์หลายมิติได้ + // เรายังสามารถสร้าง อะเรย์ที่มีความยาวช่องเท่ากับศูนย์ (0) ได้อีกด้วย + // ซึ่งทำให้เกิด อะเรย์ที่จำนวนช่องยืดหยุ่นได้ (dymaically sized array) + +// การประกาศตัวแปร : ชื่อตัวแปรเหล่านี้จะนำไปใช้ด้านล่างต่อไป +var + int, c, d : integer; + // ประกาศในบล็อค var มีตัวแปรสามตัวเป็นอินทีเจอร์ + // ชนิดจำนวนเต็ม แบบ 16 bit มีช่วงข้อมูล [-32,768.. 32,767] + // »int« ในที่นี้เป็น "ชื่อตัวแปร" ที่ต้นฉบับตั้งให้สอดคล้องกับชนิดข้อมูล + // อย่าสับสนกับบางภาษาที่มีชนิด int ประกาศหน้าชื่อตัวแปร + r : real; + // ตัวแปร r เป็นชนิดเรียล (real) หรือเลขทศนิยม + // real มีช่วงข้อมูล [3.4E-38..3.4E38] + bool : boolean; + // ข้อมูลชนิดบูเลียน (boolean) มีค่าได้สองแบบ คือ True/False + ch : char; + // ตัวแปร ch เป็นชนิดตัวอักษร (ชาร์? คาร์?) หรือคาแรกเตอร์ + // ตัวอักษรเป็นแบบ ASCII 8 bit ดังนั้นจะไม่ใช่ UTF, Unicode + str : string; + // ตัวแปรสตริงจะเก็บข้อความ หรือ char หลาย ๆ ตัว + // ชนิดข้อมูลนี้ไม่เป็นมาตรฐานภาษาแต่คอมไพเลอร์ปาสกาลก็มักจะมีให้ + // ทั่ว ๆ ไปแล้ว จะเป็นอะเรย์ของ char ความยาวตั้งต้น 255 + s : string[50]; + // แบบนี้คือ กำหนดความยาว string เอง ให้เก็บ char 50 ตัว + // แบบนี้ก็ทำให้ประหยัดหน่วยความจำมากขึ้นนั่นเอง + my_str: ch_array; + // ชนิดตัวแปร ใช้เป็นชนิดที่เรากำหนดเองก็ได้ อย่างตอนนี้ + // ch_array เป็น "ชนิดข้อมูล" ที่เราสร้างขึ้นมาในบล็อค type + my_2d : md_array; + // ตัวแปรแบบอะเรย์ที่ไม่ประกาศขนาด (dynamically sized array) + // ก่อนเอาไปใช้จริงต้องระบุขนาดก่อนใช้เสมอ + + // ชนิดข้อมูลแบบ integer เพิ่มเติม + b : byte; // มีช่วงข้อมูล [0..255] + shi : shortint; // มีช่วงข้อมูล [-128..127] + smi : smallint; // มีช่วงข้อมูล [-32,768..32,767] (standard Integer) + w : word; // มีช่วงข้อมูล [0..65,535] + li : longint; // มีช่วงข้อมูล [-2,147,483,648..2,147,483,647] + lw : longword; // มีช่วงข้อมูล [0..4,294,967,295] + c : cardinal; // ก็คือ longword + i64 : int64; // มีช่วงข้อมูล + // [-9223372036854775808..9223372036854775807] + qw : qword; // มีช่วงข้อมูล [0..18,446,744,073,709,551,615] + + // ชนิดข้อมูลแบบ real เพิ่มเติม + rr : real; // มีช่วงข้อมูลที่ขึ้นกับระบบปฏิบัติการ + // (เช่นเป็นแบบ 8-bit, 16-bit, ฯลฯ) + rs : single; // มีช่วงข้อมูล [1.5E-45..3.4E38] + rd : double; // มีช่วงข้อมูล [5.0E-324 .. 1.7E308] + re : extended; // มีช่วงข้อมูล [1.9E-4932..1.1E4932] + rc : comp; // มีช่วงข้อมูล [-2E64+1 .. 2E63-1] + +Begin + // การกำหนดค่าตัวแปรให้ขณะประกาศ + int := 1; + r := 3.14; + ch := 'a'; // ใช้ single quote เหมือนกันทั้ง char และ string + str := 'apple'; + bool := true; + // ภาษาปาสกาล มอง "ชื่อเฉพาะ" แบบไม่สนพิมพ์ใหญ่พิมพ์เล็ก + // (case-insensitive language) + // ตัวดำเนินการแบบคณิตศาสตร์ (arithmethic operation) + int := 1 + 1; // int = 2 ซึ่งจะกำหนดทับค่าเดิมด้านบนที่เคยประกาศ + int := int + 1; // int = 2 + 1 = 3 นำค่าตอนนี้ (2) มา +1 ได้ 3 + int := 4 div 2; // int = 2 หารด้วย div จะได้ผลเป็น integer เสมอ + int := 3 div 2; // int = 1 + int := 1 div 2; // int = 0 + + bool := true or false; // bool = true + bool := false and true; // bool = false + bool := true xor true; // bool = false + + r := 3 / 2; // หารด้วย / จะได้ผลเป็น real เสมอ + r := int; // เรากำหนดค่า integer ให้ตัวแปร real ได้ + // แต่ทำกลับกัน โดยกำหนด real ให้ integer ไม่ได้ + + c := str[1]; // กำหนดค่าแรกใน array str ให้ตัวแปร c ที่เป็น char + str := 'hello' + 'world'; // เรารวม string เข้าด้วยกันด้วย + + + my_str[0] := 'a'; // กำหนดค่าให้ string เฉพาะตำแหน่งแบบอะเรย์ทั่วไป + + setlength(my_2d,10,10); // ปรับขนาดอะเรย์ 2 มิติให้เป็นขนาด 10x10 + // โดยตัวแปร my_2d นี้สร้างแล้วด้านบน + for c := 0 to 9 do // อะเรย์เริ่มจาก 0 และจบที่ ความยาว-1 + for d := 0 to 9 do // ตัวนับ (counter) จำเป็นต้องประกาศก่อนใช้ + my_2d[c,d] := c * d; + // กำหนดอะเรย์หลายมิติ ด้วยการใช้วงเล็บก้ามปู (square brackets) + +End. +// จบโปรแกรมบริบูรณ์ ด้วย "." +``` + +ด้านล่าง เป็นตัวอย่างการเขียนโปรแกรมปาสกาลชื่อ Functional\_Programming + +```pascal +program Functional_Programming; + +Var + i, dummy : integer; + +function factorial_recursion(const a: integer) : integer; +{ ทำการคำนวณแฟคทอเรียลซ้ำ ๆ ของเลขจำนวนเต็ม โดยผ่านพารามิเตอร์ a + ถ้าจะประกาศตัวแปรโลคอลในฟังก์ชั่น ก็ทำได้ โดยการใช้บล็อค var ภายในฟังก์ชั่น + เช่น : + var + local_a : integer; +} +Begin + If a >= 1 Then + { ฟังก์ชั่นนี้คืนค่ากลับ โดยการกำหนดค่าที่ผ่านทางพารามิเตอร์ a + นำมาคูณกับฟังก์ชั่นที่ผ่าน a-1 สุดท้ายก็กำหนดค่าลงไปให้กับฟังก์ชั่นตรงๆ } + factorial_recursion := a * factorial_recursion(a-1) + Else + factorial_recursion := 1; +End; // จบ ฟังก์ชั่น ด้วย ";" หลัง End ไม่เหมือนกับจบ โปรแกรม ที่จะใช้ "." + +procedure get_integer(var i : integer; dummy : integer); +{ เรารับ input จากผู้ใช้มาเก็บใน parameter i ที่เป็น integer ที่ตั้งขึ้นใน + พารามิเตอร์ โดยใช้ var ประกาศ ทำให้ค่าที่รับเข้ามาจะเปลี่ยนปรับได้จาก + ภายนอกการประกาศพารามิเตอร์นี้ ส่วน dummy เป็นตัวแปรที่ปรับเปลี่ยนได้ + "เฉพาะจากภายในฟังก์ชั่น,โพรซีเยอร์นั้น ๆ } +Begin + write('Enter an integer: '); + readln(i); + dummy := 4; // dummy จะไม่ทำให้ค่าที่ได้รับมาครั้งแรกใน main block เปลี่ยน +End; + +//--------------------// +// main program block +//--------------------// +Begin + dummy := 3; + get_integer(i, dummy); + writeln(i, '! = ', factorial_recursion(i)); + // พิมพ์ค่า i! + writeln('dummy = ', dummy); // จะให้ค่าเป็น '3' เสมอ + // เพราะจะไม่เปลี่ยนเนื่องด้วย + // การประกาศพารามิเตอร์ใน + // โพรซีเยอร์ get_integer ด้านบน +End. + +``` + +[1]: https://en.wikipedia.org/wiki/Pascal_(programming_language) +[2]: https://www.freepascal.org/ diff --git a/toml.html.markdown b/toml.html.markdown index 814e57e7..385a2437 100755 --- a/toml.html.markdown +++ b/toml.html.markdown @@ -32,7 +32,7 @@ boolean = true dateTime = 1979-05-27T07:32:00-08:00 scientificNotation = 1e+12 "key can be quoted" = true # Both " and ' are fine -"key may contains" = "letters, numbers, underscores, and dashes" +"key may contain" = "letters, numbers, underscores, and dashes" # A bare key must be non-empty, but an empty quoted key is allowed "" = "blank" # VALID but discouraged @@ -225,26 +225,26 @@ color = "gray" # sub-table will belong to the nearest table element above it. [[fruit]] - name = "apple" + name = "apple" # I am a property in fruit table/map - [fruit.Geometry] + [fruit.geometry] shape = "round" - note = "I am an fruit's property" + note = "I am a property in geometry table/map" [[fruit.color]] name = "red" - note = "I am an array's item in apple" + note = "I am an array item in apple fruit's table/map" [[fruit.color]] name = "green" - note = "I am in the same array than red" + note = "I am in the same array as red" [[fruit]] name = "banana" [[fruit.color]] name = "yellow" - note = "I am an array's item too but banana's one" + note = "I am an array item in banana fruit's table/map" ``` In JSON land, this code will be: diff --git a/typescript.html.markdown b/typescript.html.markdown index ba4a9e71..cf2111d5 100644 --- a/typescript.html.markdown +++ b/typescript.html.markdown @@ -223,6 +223,43 @@ moreNumbers[5] = 5; // Error, elements are read-only moreNumbers.push(5); // Error, no push method (because it mutates array) moreNumbers.length = 3; // Error, length is read-only numbers = moreNumbers; // Error, mutating methods are missing + +// Tagged Union Types for modelling state that can be in one of many shapes +type State = + | { type: "loading" } + | { type: "success", value: number } + | { type: "error", message: string }; + +declare const state: State; +if (state.type === "success") { + console.log(state.value); +} else if (state.type === "error") { + console.error(state.message); +} + +// Iterators and Generators + +// for..of statement +// iterate over the list of values on the object being iterated +let arrayOfAnyType = [1, "string", false]; +for (const val of arrayOfAnyType) { + console.log(val); // 1, "string", false +} + +let list = [4, 5, 6]; +for (const i of list) { + console.log(i); // 4, 5, 6 +} + +// for..in statement +// iterate over the list of keys on the object being iterated +for (const i in list) { + console.log(i); // 0, 1, 2 +} + + + + ``` ## Further Reading diff --git a/vyper.html.markdown b/vyper.html.markdown index 2c654797..fec1a79f 100644 --- a/vyper.html.markdown +++ b/vyper.html.markdown @@ -386,11 +386,16 @@ uint newLength = names.push("John"); # adding returns new length of the array names.length; # get length names.length = 1; # lengths can be set (for dynamic arrays in storage only) -# multidimensional fixed array -ls: (uint256[10])[3] # note the parentheses +# Multidimensional Arrays +# At initialization, array dimensions must be hard-coded or constants +# Initialize a 10-column by 3-row, multidimensional fixed array +ls: (uint256[10])[3] # parentheses are optional @public def setToThree(): - self.ls[5][3] = 3 # multidimensional array access + # Multidimensional Array Access and Write + # access indices are reversed + # set element in row 2 (3rd row) column 5 (6th column) to 3 + self.ls[2][5] = 3 # Dictionaries (any simple type to any other type including structs) theMap: map(uint256, bytes32) diff --git a/wasm.html.markdown b/wasm.html.markdown new file mode 100644 index 00000000..98bfc000 --- /dev/null +++ b/wasm.html.markdown @@ -0,0 +1,227 @@ +--- +language: WebAssembly +filename: learn-wasm.wast +contributors: + - ["Dean Shaff", "http://dean-shaff.github.io"] +--- + +``` +;; learn-wasm.wast + +(module + ;; In WebAssembly, everything is included in a module. Moreover, everything + ;; can be expressed as an s-expression. Alternatively, there is the + ;; "stack machine" syntax, but that is not compatible with Binaryen + ;; intermediate representation (IR) syntax. + + ;; The Binaryen IR format is *mostly* compatible with WebAssembly text format. + ;; There are some small differences: + ;; local_set -> local.set + ;; local_get -> local.get + + ;; We have to enclose code in functions + + ;; Data Types + (func $data_types + ;; WebAssembly has only four types: + ;; i32 - 32 bit integer + ;; i64 - 64 bit integer (not supported in JavaScript) + ;; f32 - 32 bit floating point + ;; f64 - 64 bit floating point + + ;; We can declare local variables with the "local" keyword + ;; We have to declare all variables before we start doing anything + ;; inside the function + + (local $int_32 i32) + (local $int_64 i64) + (local $float_32 f32) + (local $float_64 f64) + + ;; These values remain uninitialized. + ;; To set them to a value, we can use <type>.const: + + (local.set $int_32 (i32.const 16)) + (local.set $int_32 (i64.const 128)) + (local.set $float_32 (f32.const 3.14)) + (local.set $float_64 (f64.const 1.28)) + ) + + ;; Basic operations + (func $basic_operations + + ;; In WebAssembly, everything is an s-expression, including + ;; doing math, or getting the value of some variable + + (local $add_result i32) + (local $mult_result f64) + + (local.set $add_result (i32.add (i32.const 2) (i32.const 4))) + ;; the value of add_result is now 6! + + ;; We have to use the right data type for each operation: + ;; (local.set $mult_result (f32.mul (f32.const 2.0) (f32.const 4.0))) ;; WRONG! mult_result is f64! + (local.set $mult_result (f64.mul (f64.const 2.0) (f64.const 4.0))) ;; WRONG! mult_result is f64! + + ;; WebAssembly has some builtin operations, like basic math and bitshifting. + ;; Notably, it does not have built in trigonometric functions. + ;; In order to get access to these functions, we have to either + ;; - implement them ourselves (not recommended) + ;; - import them from elsewhere (later on) + ) + + ;; Functions + ;; We specify arguments with the `param` keyword, and specify return values + ;; with the `result` keyword + ;; The current value on the stack is the return value of a function + + ;; We can call other functions we've defined with the `call` keyword + + (func $get_16 (result i32) + (i32.const 16) + ) + + (func $add (param $param0 i32) (param $param1 i32) (result i32) + (i32.add + (local.get $param0) + (local.get $param1) + ) + ) + + (func $double_16 (result i32) + (i32.mul + (i32.const 2) + (call $get_16)) + ) + + ;; Up until now, we haven't be able to print anything out, nor do we have + ;; access to higher level math functions (pow, exp, or trig functions). + ;; Moreover, we haven't been able to use any of the WASM functions in Javascript! + ;; The way we get those functions into WebAssembly + ;; looks different whether we're in a Node.js or browser environment. + + ;; If we're in Node.js we have to do two steps. First we have to convert the + ;; WASM text representation into actual webassembly. If we're using Binyaren, + ;; we can do that with a command like the following: + + ;; wasm-as learn-wasm.wast -o learn-wasm.wasm + + ;; We can apply Binaryen optimizations to that file with a command like the + ;; following: + + ;; wasm-opt learn-wasm.wasm -o learn-wasm.opt.wasm -O3 --rse + + ;; With our compiled WebAssembly, we can now load it into Node.js: + ;; const fs = require('fs') + ;; const instantiate = async function (inFilePath, _importObject) { + ;; var importObject = { + ;; console: { + ;; log: (x) => console.log(x), + ;; }, + ;; math: { + ;; cos: (x) => Math.cos(x), + ;; } + ;; } + ;; importObject = Object.assign(importObject, _importObject) + ;; + ;; var buffer = fs.readFileSync(inFilePath) + ;; var module = await WebAssembly.compile(buffer) + ;; var instance = await WebAssembly.instantiate(module, importObject) + ;; return instance.exports + ;; } + ;; + ;; const main = function () { + ;; var wasmExports = await instantiate('learn-wasm.wasm') + ;; wasmExports.print_args(1, 0) + ;; } + + ;; The following snippet gets the functions from the importObject we defined + ;; in the JavaScript instantiate async function, and then exports a function + ;; "print_args" that we can call from Node.js + + (import "console" "log" (func $print_i32 (param i32))) + (import "math" "cos" (func $cos (param f64) (result f64))) + + (func $print_args (param $arg0 i32) (param $arg1 i32) + (call $print_i32 (local.get $arg0)) + (call $print_i32 (local.get $arg1)) + ) + (export "print_args" (func $print_args)) + + ;; Loading in data from WebAssembly memory. + ;; Say that we want to apply the cosine function to a Javascript array. + ;; We need to be able to access the allocated array, and iterate through it. + ;; This example will modify the input array inplace. + ;; f64.load and f64.store expect the location of a number in memory *in bytes*. + ;; If we want to access the 3rd element of an array, we have to pass something + ;; like (i32.mul (i32.const 8) (i32.const 2)) to the f64.store function. + + ;; In JavaScript, we would call `apply_cos64` as follows + ;; (using the instantiate function from earlier): + ;; + ;; const main = function () { + ;; var wasm = await instantiate('learn-wasm.wasm') + ;; var n = 100 + ;; const memory = new Float64Array(wasm.memory.buffer, 0, n) + ;; for (var i=0; i<n; i++) { + ;; memory[i] = i; + ;; } + ;; wasm.apply_cos64(n) + ;; } + ;; + ;; This function will not work if we allocate a Float32Array on the JavaScript + ;; side. + + (memory (export "memory") 100) + + (func $apply_cos64 (param $array_length i32) + ;; declare the loop counter + (local $idx i32) + ;; declare the counter that will allow us to access memory + (local $idx_bytes i32) + ;; constant expressing the number of bytes in a f64 number. + (local $bytes_per_double i32) + + ;; declare a variable for storing the value loaded from memory + (local $temp_f64 f64) + + (local.set $idx (i32.const 0)) + (local.set $idx_bytes (i32.const 0)) ;; not entirely necessary + (local.set $bytes_per_double (i32.const 8)) + + (block + (loop + ;; this sets idx_bytes to bytes offset of the value we're interested in. + (local.set $idx_bytes (i32.mul (local.get $idx) (local.get $bytes_per_double))) + + ;; get the value of the array from memory: + (local.set $temp_f64 (f64.load (local.get $idx_bytes))) + + ;; now apply the cosine function: + (local.set $temp_64 (call $cos (local.get $temp_64))) + + ;; now store the result at the same location in memory: + (f64.store + (local.get $idx_bytes) + (local.get $temp_64)) + + ;; do it all in one step instead + (f64.store + (local.get $idx_bytes) + (call $cos + (f64.load + (local.get $idx_bytes)))) + + ;; increment the loop counter + (local.set $idx (i32.add (local.get $idx) (i32.const 1))) + + ;; stop the loop if the loop counter is equal the array length + (br_if 1 (i32.eq (local.get $idx) (local.get $array_length))) + (br 0) + ) + ) + ) + (export "apply_cos64" (func $apply_cos64)) +) + +``` diff --git a/wolfram.html.markdown b/wolfram.html.markdown index 4514006d..5fddbc82 100644 --- a/wolfram.html.markdown +++ b/wolfram.html.markdown @@ -123,8 +123,8 @@ myHash[["Green"]] (* 2, use it *) myHash[["Green"]] := 5 (* 5, update it *) myHash[["Puce"]] := 3.5 (* 3.5, extend it *) KeyDropFrom[myHash, "Green"] (* Wipes out key Green *) -Keys[myHash] (* {Red} *) -Values[myHash] (* {1} *) +Keys[myHash] (* {Red, Puce} *) +Values[myHash] (* {1, 3.5} *) (* And you can't do any demo of Wolfram without showing this off *) Manipulate[y^2, {y, 0, 20}] (* Return a reactive user interface that displays y^2 diff --git a/yaml.html.markdown b/yaml.html.markdown index 09c5dfc5..f1393c09 100644 --- a/yaml.html.markdown +++ b/yaml.html.markdown @@ -38,6 +38,8 @@ however: 'A string, enclosed in quotes.' 'Keys can be quoted too.': "Useful if you want to put a ':' in your key." single quotes: 'have ''one'' escape pattern' double quotes: "have many: \", \0, \t, \u263A, \x0d\x0a == \r\n, and more." +# UTF-8/16/32 characters need to be encoded +Superscript two: \u00B2 # Multiple-line strings can be written either as a 'literal block' (using |), # or a 'folded block' (using '>'). diff --git a/zfs.html.markdown b/zfs.html.markdown index fad6b62d..6795b1fa 100644 --- a/zfs.html.markdown +++ b/zfs.html.markdown @@ -221,7 +221,7 @@ Delete dataset ```bash # Datasets cannot be deleted if they have any snapshots -zfs destroy tank/root/home +$ zfs destroy tank/root/home ``` Get / set properties of a dataset @@ -294,6 +294,7 @@ tank/home/sarlalian@now 0 - 259M - tank/home/alice@now 0 - 156M - tank/home/bob@now 0 - 156M - ... +``` Destroy snapshots @@ -313,13 +314,13 @@ Renaming Snapshots $ zfs rename tank/home/sarlalian@now tank/home/sarlalian@today $ zfs rename tank/home/sarlalian@now today -# zfs rename -r tank/home@now @yesterday +$ zfs rename -r tank/home@now @yesterday ``` Accessing snapshots ```bash -# CD Into a snapshot directory +# CD into a snapshot directory $ cd /home/.zfs/snapshot/ ``` @@ -335,11 +336,11 @@ $ zfs send tank/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' -# Send full dataset with snapshos to new host +# Send full dataset with snapshots to new host $ zfs send -v -R tank/home@now | ssh root@backup_server 'zfs recv tank/home' ``` -Cloneing Snapshots +Cloning Snapshots ```bash # Clone a snapshot diff --git a/zh-cn/lambda-calculus-cn.html.markdown b/zh-cn/lambda-calculus-cn.html.markdown new file mode 100644 index 00000000..7719ee71 --- /dev/null +++ b/zh-cn/lambda-calculus-cn.html.markdown @@ -0,0 +1,223 @@ +--- +category: Algorithms & Data Structures +name: Lambda Calculus +lang: zh-cn +contributors: + - ["Max Sun", "http://github.com/maxsun"] + - ["Yan Hui Hang", "http://github.com/yanhh0"] +translators: + - ["Maoyin Sun", "https://github.com/simonmysun"] +--- + +# Lambda 演算 + +Lambda 演算(lambda calculus, λ-calculus), +最初由[阿隆佐·邱奇][]([Alonzo Church][])提出, +是世界上最小的编程语言. +尽管没有数字, 字符串, 布尔或者任何非函数的数据类型, +lambda 演算仍可以表示任何图灵机. + +[阿隆佐·邱奇]: https://zh.wikipedia.org/wiki/%E9%98%BF%E9%9A%86%E4%BD%90%C2%B7%E9%82%B1%E5%A5%87 +[Alonzo Church]: https://en.wikipedia.org/wiki/Alonzo_Church + +Lambda 演算由三种元素组成: **变量**(variables)、**函数**(functions)和**应用**(applications)。 + +| 名称 | 语法 | 示例 | 解释 | +|------|----------------------|-----------|--------------------------------------------------| +| 变量 | `<变量名>` | `x` | 一个名为"x"的变量 | +| 函数 | `λ<参数>.<函数体>` | `λx.x` | 一个以"x"(前者)为参数、以"x"(后者)为函数体的函数 | +| 应用 | `<函数><变量或函数>` | `(λx.x)a` | 以"a"为参数调用函数"λx.x" | + +最基本的函数为恒等函数: `λx.x`, 它等价于`f(x) = x`. +第一个"x"为函数的参数, 第二个为函数体. + +## 自由变量和约束变量: + +- 在函数`λx.x`中, "x"被称作约束变量因为它同时出现在函数体和函数参数中. +- 在`λx.y`中, "y"被称作自由变量因为它没有被预先声明. + +## 求值: + +求值操作是通过[β-归约][]([β-Reduction][])完成的, +它本质上是词法层面上的替换. + +[β-归约]: https://zh.wikipedia.org/wiki/%CE%9B%E6%BC%94%E7%AE%97#'%22%60UNIQ--postMath-0000006F-QINU%60%22'-%E6%AD%B8%E7%B4%84 +[β-Reduction]: https://en.wikipedia.org/wiki/Lambda_calculus#Beta_reduction + +当对表达式`(λx.x)a`求值时, 我们将函数体中所有出现的"x"替换为"a". + +- `(λx.x)a`计算结果为: `a` +- `(λx.y)a`计算结果为: `y` + +你甚至可以创建高阶函数: + +- `(λx.(λy.x))a`计算结果为: `λy.a` + +尽管 lambda 演算传统上仅支持单个参数的函数, +但我们可以通过一种叫作[柯里化][]([Currying][])的技巧创建多个参数的函数. + +[柯里化]: https://zh.wikipedia.org/wiki/%E6%9F%AF%E9%87%8C%E5%8C%96 +[Currying]: https://en.wikipedia.org/wiki/Currying + +- `(λx.λy.λz.xyz)`等价于`f(x, y, z) = ((x y) z)` + +有时`λxy.<body>`与`λx.λy.<body>`可以互换使用. + +---- + +认识到传统的 **lambda 演算没有数字, 字符或者任何非函数的数据类型**很重要. + +## 布尔逻辑: + +在 lambda 演算中没有"真"或"假". 甚至没有 1 或 0. + +作为替换: + +`T`表示为: `λx.λy.x` + +`F`表示为: `λx.λy.y` + +首先, 我们可以定义一个"if"函数`λbtf`, 它当`b`为真时返回`t`, +`b`为假时返回`f` + +`IF`等价于: `λb.λt.λf.b t f` + +通过`IF`, 我们可以定义基本的布尔逻辑运算符: + +`a AND b`等价于: `λab.IF a b F` + +`a OR b`等价于: `λab.IF a T b` + +`NOT a`等价于: `λa.IF a F T` + +*注意: `IF a b c`本质上指: `IF((a b) c)`* + +## 数字: + +尽管 lambda 演算中没有数字, +我们还可以用[邱奇编码][]([Church numerals][])将数字嵌入到 lambda 演算中. + +[邱奇编码]: https://zh.wikipedia.org/wiki/%E9%82%B1%E5%A5%87%E7%BC%96%E7%A0%81 +[Church numerals]: https://en.wikipedia.org/wiki/Church_encoding + +对于任意数字 n: <code>n = λf.f<sup>n</sup></code> 所以: + +`0 = λf.λx.x` + +`1 = λf.λx.f x` + +`2 = λf.λx.f(f x)` + +`3 = λf.λx.f(f(f x))` + +要增加一个邱奇数, 我们使用后继函数`S(n) = n + 1`: + +`S = λn.λf.λx.f((n f) x)` + +使用后继函数, 我们可以定义加法: + +`ADD = λab.(a S)b` + +**挑战**: 试定义乘法函数! + +## 变得更小: SKI, SK 和 Iota + +### SKI 组合子演算 + +令 S, K, I 为下列函数: + +`I x = x` + +`K x y = x` + +`S x y z = x z (y z)` + +我们可以将 lambda 演算中的表达式转换为 SKI 组合子演算中的表达式: + +1. `λx.x = I` +2. `λx.c = Kc` +3. `λx.(y z) = S (λx.y) (λx.z)` + +以邱奇数 2 为例: + +`2 = λf.λx.f(f x)` + +对于里面的部分 `λx.f(f x)`: + +``` + λx.f(f x) += S (λx.f) (λx.(f x)) (case 3) += S (K f) (S (λx.f) (λx.x)) (case 2, 3) += S (K f) (S (K f) I) (case 2, 1) +``` + +所以: + +``` + 2 += λf.λx.f(f x) += λf.(S (K f) (S (K f) I)) += λf.((S (K f)) (S (K f) I)) += S (λf.(S (K f))) (λf.(S (K f) I)) (case 3) +``` + +对于第一个参数`λf.(S (K f))`有: + +``` + λf.(S (K f)) += S (λf.S) (λf.(K f)) (case 3) += S (K S) (S (λf.K) (λf.f)) (case 2, 3) += S (K S) (S (K K) I) (case 2, 3) +``` + +对于第二个参数`λf.(S (K f) I)`有: + +``` + λf.(S (K f) I) += λf.((S (K f)) I) += S (λf.(S (K f))) (λf.I) (case 3) += S (S (λf.S) (λf.(K f))) (K I) (case 2, 3) += S (S (K S) (S (λf.K) (λf.f))) (K I) (case 1, 3) += S (S (K S) (S (K K) I)) (K I) (case 1, 2) +``` + +综上: + +``` + 2 += S (λf.(S (K f))) (λf.(S (K f) I)) += S (S (K S) (S (K K) I)) (S (S (K S) (S (K K) I)) (K I)) +``` + +如果展开这个表达式, 我们最终又会得到邱奇数 2 的相同的表达式. + +### SK 组合子演算 + +SKI 组合子演算还可以进一步简化. 我们可以通过`I = SKK`移除 I 组合子. +我们可以将所有的 `I` 替换为 `SKK`. + +### ι 组合子 + +SK 组合子仍不是最简的. 定义: + +``` +ι = λf.((f S) K) +``` + +我们有: + +``` +I = ιι +K = ι(ιI) = ι(ι(ιι)) +S = ι(K) = ι(ι(ι(ιι))) +``` + +## 更多阅读: + +1. [A Tutorial Introduction to the Lambda Calculus](http://www.inf.fu-berlin.de/lehre/WS03/alpi/lambda.pdf)(英文) +2. [Cornell CS 312 Recitation 26: The Lambda Calculus](https://courses.cs.cornell.edu/cs312/2008sp/recitations/rec26.html)(英文) +3. [Wikipedia - Lambda Calculus](https://en.wikipedia.org/wiki/Lambda_calculus)(英文) +4. [Wikipedia - SKI combinator calculus](https://en.wikipedia.org/wiki/SKI_combinator_calculus)(英文) +5. [Wikipedia - Iota and Jot](https://en.wikipedia.org/wiki/Iota_and_Jot)(英文) +6. [λ演算 - 维基百科,自由的百科全书](https://zh.wikipedia.org/wiki/SKI%E7%BB%84%E5%90%88%E5%AD%90%E6%BC%94%E7%AE%97) +7. [SKI组合子演算 - 维基百科,自由的百科全书](https://zh.wikipedia.org/wiki/SKI%E7%BB%84%E5%90%88%E5%AD%90%E6%BC%94%E7%AE%97) diff --git a/zh-cn/make-cn.html.markdown b/zh-cn/make-cn.html.markdown index 281537d6..76dde941 100644 --- a/zh-cn/make-cn.html.markdown +++ b/zh-cn/make-cn.html.markdown @@ -39,7 +39,7 @@ Makefile 用于定义如何创建目标文件, 比如如何从源码到可执行 # … # prerequisites(依赖) 是可选的, recipe(做法) 也可以多个或者不给. -# 下面这个任务没有给 prerequisites, 只会在目标文件 file0.txt 文件不存在是跑 +# 下面这个任务没有给 prerequisites, 只会在目标文件 file0.txt 文件不存在时执行 file0.txt: echo "foo" > file0.txt # 试试 `make file0.txt` @@ -47,12 +47,12 @@ file0.txt: # 注意: 即使是这些注释, 如果前面有 TAB, 也会发送给 shell, 注意看 `make file0.txt` 输出 # 如果提供 prerequisites, 则只有 prerequisites 比 target 新时会执行 -# 比如下面这个任务只有当 file1.txt 比 file0.txt 新时才会执行. +# 比如下面这个任务只有当 file0.txt 比 file1.txt 新时才会执行. file1.txt: file0.txt cat file0.txt > file1.txt - # 这里跟shell里的命令式一毛一样的. + # 这里跟shell里的命令式一模一样. @cat file0.txt >> file1.txt - # @ 不会把命令往 stdout 打印. + # @ 不会把命令打印到 stdout. -@echo 'hello' # - 意思是发生错误了也没关系. # 试试 `make file1.txt` 吧. @@ -235,7 +235,7 @@ ls: * # include foo.mk sport = tennis -# 一些逻辑语句 if else 什么的, 顶个写 +# 流程控制语句 (如if else 等等) 顶格写 report: ifeq ($(sport),tennis) @echo 'game, set, match' diff --git a/zh-cn/markdown-cn.html.markdown b/zh-cn/markdown-cn.html.markdown index 2bd8d11a..9b3d96ab 100644 --- a/zh-cn/markdown-cn.html.markdown +++ b/zh-cn/markdown-cn.html.markdown @@ -5,6 +5,7 @@ contributors: translators: - ["Fangzhou Chen","https://github.com/FZSS"] - ["Luffy Zhong", "https://github.com/mengzhongshi"] + - ["Yuchen Liu", "https://github.com/smallg0at"] filename: learnmarkdown-cn.md lang: zh-cn --- @@ -46,6 +47,16 @@ Markdown 是 HTML 的父集,所以任何 HTML 文件都是有效的 Markdown ##### 这是一个 <h5> ###### 这是一个 <h6> ``` + +实际效果(最终显示时会因设置而看起来不同): +# 这是一个 +## 这也是一个 +### 这还是一个 +#### 这依旧是一个 +##### 这真的是一个 +###### 这...是一个 + + 对于 `<h1>` 和 `<h2>` 元素,Markdown 额外提供了两种添加方式。 ```md @@ -58,7 +69,7 @@ Markdown 是 HTML 的父集,所以任何 HTML 文件都是有效的 Markdown ## 文本样式 -文本的斜体,粗体在 Markdown 中可以轻易实现。 +文本的*斜体*,**粗体**在 Markdown 中可以轻易实现。 ```md *此文本为斜体。* @@ -72,7 +83,7 @@ __此文本也是__ *__这个也是!__* ``` -GitHub 也支持 Markdown,在 GitHub 的 Markdown 解析器中,我们可以使用删除线: +GitHub 也支持 Markdown,在 GitHub 的 Markdown 解析器中,我们可以使用~~删除线~~: ```md ~~此文本为删除线效果。~~ @@ -80,6 +91,7 @@ GitHub 也支持 Markdown,在 GitHub 的 Markdown 解析器中,我们可以 ## 段落 段落由一个句子或是多个中间没有空行的句子组成,每个段落由一个或是多个空行分隔开来。 +(注:部分解析器有无需空行就能换行的设置,这个主要看个人喜好) ```md 这是第一段落. 这句话在同一个段落里,好玩么? @@ -92,7 +104,9 @@ GitHub 也支持 Markdown,在 GitHub 的 Markdown 解析器中,我们可以 ``` 如果你想插入一个 `<br />` 标签,你可以在段末加入两个以上的空格,然后另起一 -段。(译者注:试了一下,很多解析器,并不需要空两个空格,直接换行就会添加一个`<br />`) +段。 + +(译者注:试了一下,很多解析器,并不需要空两个空格,直接换行就会添加一个`<br />`) ```md 此段落结尾有两个空格(选中以显示)。 @@ -102,6 +116,8 @@ GitHub 也支持 Markdown,在 GitHub 的 Markdown 解析器中,我们可以 段落引用可由 `>` 字符轻松实现。 +> 对的很轻松 + ```md > 这是一个段落引用。 你可以 > 手动断开你的句子,然后在每句句子前面添加 `>` 字符。或者让你的句子变得很长,以至于他们自动得换行。 @@ -113,7 +129,7 @@ GitHub 也支持 Markdown,在 GitHub 的 Markdown 解析器中,我们可以 ``` ## 列表 -无序列表可由星号,加号或者减号来创建 +- 无序列表可由星号,加号或者减号来创建 ```md * 项目 @@ -172,6 +188,7 @@ GitHub 也支持 Markdown,在 GitHub 的 Markdown 解析器中,我们可以 下面这个选择框将会是选中状态 - [x] 这个任务已经完成 ``` +- [ ] 你看完了这个任务(注:此选择框是无法直接更改的,即禁用状态。) ## 代码块 @@ -217,7 +234,10 @@ end --- - - - **************** + +下面这个就是示例 ``` +--- ## 链接 @@ -294,33 +314,45 @@ Markdown同样支持引用形式的链接 我希望 *将这段文字置于星号之间* 但是我不希望它被 斜体化, 这么做: \*这段置文字于星号之间\*。 ``` +对比一下:*将这段文字置于星号之间* 和 \*将这段文字置于星号之间\* ### 键盘上的功能键 -在 GitHub 的 Markdown中,你可以使用 `<kbd>` 标签来表示功能键。 +在 GitHub 的 Markdown 中,你可以使用 `<kbd>` 标签来表示功能键。 ```md 你的电脑死机了?试试 <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>Del</kbd> ``` <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>Del</kbd> + +(译注:可能由于网站本身样式问题,效果不明显) + ### 表格 -表格只被 GitHub 的 Markdown 支持,并且有一点笨重,但如果你真的要用的话: (译者注:其实现在大部分markdown都已经支持) +下面示例的表格长这样: + +| 第一列 | 第二列 | 第三列 | +| :----------- | :-------: | ----------: | +| 我是左对齐 | 居个中 | 右对齐 | +| 注意 | 冒 | 号 | + +工整一点的写法是这样的: ```md | 第一列 | 第二列 | 第三列 | -| :--------- | :------: | ----------: | -| 左对齐 | 居个中 | 右对齐 | -| 某某某 | 某某某 | 某某某 | +| :----------- | :-------: | ----------: | +| 我是左对齐 | 居个中 | 右对齐 | +| 注意 | 冒 | 号 | ``` - -或者, 同样的 +好吧,强行对齐字符是很难的。但是,至少比下面这种写法好一点—— ```md -第一列 | 第二列 | 第三列 +我是超级超级长的第一列 | 第二列 | 第三列 :-- | :-: | --: -这太丑了 | 药不能 | 停 +这真的太丑了 | 药不能 | 停!!!! ``` +真的是*看着令人头晕* + 更多信息, 请于[此处](http://daringfireball.net/projects/Markdown/syntax)参见 John Gruber 关于语法的官方帖子,及于[此处](https://github.com/adam-p/Markdown-here/wiki/Markdown-Cheatsheet) 参见 Adam Pritchard 的摘要笔记。 diff --git a/zh-cn/ruby-cn.html.markdown b/zh-cn/ruby-cn.html.markdown index 657a913d..9918c022 100644 --- a/zh-cn/ruby-cn.html.markdown +++ b/zh-cn/ruby-cn.html.markdown @@ -6,11 +6,25 @@ contributors: - ["David Underwood", "http://theflyingdeveloper.com"] - ["Joel Walden", "http://joelwalden.net"] - ["Luke Holder", "http://twitter.com/lukeholder"] + - ["Tristan Hume", "http://thume.ca/"] + - ["Nick LaMuro", "https://github.com/NickLaMuro"] + - ["Marcos Brizeno", "http://www.about.me/marcosbrizeno"] + - ["Ariel Krakowski", "http://www.learneroo.com"] + - ["Dzianis Dashkevich", "https://github.com/dskecse"] + - ["Levi Bostian", "https://github.com/levibostian"] + - ["Rahil Momin", "https://github.com/iamrahil"] + - ["Gabriel Halley", "https://github.com/ghalley"] + - ["Persa Zula", "http://persazula.com"] + - ["Jake Faris", "https://github.com/farisj"] + - ["Corey Ward", "https://github.com/coreyward"] + - ["Jannik Siebert", "https://github.com/janniks"] + - ["Keith Miyake", "https://github.com/kaymmm"] - ["lidashuang", "https://github.com/lidashuang"] - ["ftwbzhao", "https://github.com/ftwbzhao"] translators: - ["Lin Xiangyu", "https://github.com/oa414"] - ["Jiang Haiyun", "https://github.com/haiiiiiyun"] + - ["woclass", "https://github.com/inkydragon"] --- ```ruby @@ -18,26 +32,27 @@ translators: =begin 这是多行注释 -没人用这个 -你也不该用 =end -# 首先,也是最重要的,所有东西都是对象 +# 在 Ruby 中,(几乎)所有东西都是对象 # 数字是对象 - -3.class #=> Fixnum - +3.class #=> Integer 3.to_s #=> "3" +# 字符串是对象 +"Hello".class #=> String + +# 甚至方法也是对象 +"Hello".method(:class).class #=> Method -# 一些基本的算术符号 -1 + 1 #=> 2 -8 - 1 #=> 7 -10 * 2 #=> 20 -35 / 5 #=> 7 -2**5 #=> 32 -5 % 3 #=> 2 +# 一些基本的算术操作 +1 + 1 #=> 2 +8 - 1 #=> 7 +10 * 2 #=> 20 +35 / 5 #=> 7 +2 ** 5 #=> 32 +5 % 3 #=> 2 # 位运算符 3 & 5 #=> 1 @@ -48,6 +63,7 @@ translators: # 实际上是调用对象的方法 1.+(3) #=> 4 10.* 5 #=> 50 +100.methods.include?(:/) #=> true # 特殊的值也是对象 nil # 相当于其它语言中的 null @@ -66,11 +82,11 @@ false.class #=> FalseClass 1 != 1 #=> false 2 != 1 #=> true -# 除了false自己,nil是唯一的另一个值为false的对象 - -!nil #=> true -!false #=> true -!0 #=> false +# 除了 false 自己,nil 是唯一的另一个值为 false 的对象 +!!nil #=> false +!!false #=> false +!!0 #=> true +!!"" #=> true # 更多比较 1 < 10 #=> true @@ -90,11 +106,11 @@ true || false #=> true !true #=> false # 也有优先级更低的逻辑运算符 -# 它们用于控制流结构中,用来串接语句,直到返回true或false。 +# 它们用于控制流结构中,用来串接语句,直到返回 true 或 false。 -# `do_something_else` 只当 `do_something` 返回true时才会被调用 +# `do_something_else` 只当 `do_something` 返回 true 时才会被调用 do_something() and do_something_else() -# `log_error` 只当 `do_something` 返回false时才会被调用 +# `log_error` 只当 `do_something` 返回 false 时才会被调用 do_something() or log_error() @@ -114,6 +130,7 @@ placeholder = "use string interpolation" 'hello ' + 'world' #=> "hello world" 'hello ' + 3 #=> TypeError: can't convert Fixnum into String 'hello ' + 3.to_s #=> "hello 3" +"hello #{3}" #=> "hello 3" # 合并字符串及其运算符 'hello ' * 3 #=> "hello hello hello " @@ -141,7 +158,7 @@ x = y = 10 #=> 10 x #=> 10 y #=> 10 -# 按照惯例,使用类似snake_case风格的变量名 +# 按照惯例,使用类似 snake_case 风格的变量名 snake_case = true # 使用有意义的变量名 @@ -174,6 +191,7 @@ array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5] # 数组可以被索引 # 从前面开始 array[0] #=> 1 +array.first #=> 1 array[12] #=> nil # 像运算符一样,[var] 形式的访问 @@ -189,13 +207,13 @@ array.last #=> 5 # 同时指定开始的位置和长度 array[2, 3] #=> [3, 4, 5] +# 或者指定一个区间 +array[1..3] #=> [2, 3, 4] + # 将数组逆序 a=[1,2,3] a.reverse! #=> [3,2,1] -# 或者指定一个区间 -array[1..3] #=> [2, 3, 4] - # 像这样往数组增加一个元素 array << 6 #=> [1, 2, 3, 4, 5, 6] # 或者像这样 @@ -217,14 +235,18 @@ hash['number'] #=> 5 # 查询一个不存在的键将会返回nil hash['nothing here'] #=> nil -# 从Ruby 1.9开始,用符号作为键的时候有特别的记号表示: +# 从 Ruby 1.9 开始,用符号作为键的时候有特别的记号表示: new_hash = { defcon: 3, action: true } new_hash.keys #=> [:defcon, :action] +# 检查键值是否存在 +hash.key?(:defcon) #=> true +hash.value?(3) #=> true + # 小贴士:数组和哈希表都是可枚举的 -# 它们共享一些有用的方法,比如each,map,count等等 +# 它们共享一些有用的方法,比如 each, map, count 等等 # 控制流 @@ -236,6 +258,8 @@ else "else, also optional" end +# 循环 + for counter in 1..5 puts "iteration #{counter}" end @@ -246,14 +270,14 @@ end #=> iteration 5 -# 但是,没有人用for循环。 -# 你应该使用"each"方法,然后再传给它一个块。 -# 所谓块就是可以传给像"each"这样的方法的代码段。 -# 它类似于其它语言中的lambdas, 匿名函数或闭包。 +# 但是,没有人用 for 循环。 +# 你应该使用 "each" 方法,然后再传给它一个块。 +# 所谓块就是可以传给像 "each" 这样的方法的代码段。 +# 它类似于其它语言中的 lambdas, 匿名函数或闭包。 # -# 区间上的"each"方法会对区间中的每个元素运行一次块代码。 -# 我们将counter作为一个参数传给了块。 -# 调用带有块的"each"方法看起来如下: +# 区间上的 "each" 方法会对区间中的每个元素运行一次块代码。 +# 我们将 counter 作为一个参数传给了块。 +# 调用带有块的 "each" 方法看起来如下: (1..5).each do |counter| puts "iteration #{counter}" @@ -275,7 +299,7 @@ hash.each do |key, value| puts "#{key} is #{value}" end -# 如果你还需要索引值,可以使用"each_with_index",并且定义 +# 如果你还需要索引值,可以使用 "each_with_index",并且定义 # 一个索引变量 array.each_with_index do |element, index| puts "#{element} is number #{index} in the array" @@ -293,7 +317,7 @@ end #=> iteration 5 # Ruby 中还有很多有用的循环遍历函数, -# 如"map","reduce","inject"等等。 +# 如 "map", "reduce", "inject" 等等。 # 以map为例,它会遍历数组,并根据你在 # 块中定义的逻辑对它进行处理,然后返回 # 一个全新的数组。 @@ -388,19 +412,26 @@ surround { puts 'hello world' } # { # hello world # } +# => nil # 可以向函数传递一个块 # "&"标记传递的块是一个引用 def guests(&block) - block.call 'some_argument' + block.class #=> Proc + block.call(4) end +guests { |n| "You have #{n} guests." } +# => "You have 4 guests." + # 可以传递多个参数,这些参数会转成一个数组, # 这也是使用星号符 ("*") 的原因: def guests(*array) array.each { |guest| puts guest } end +# 结构 + # 如果函数返回一个数组,在赋值时可以进行拆分: def foods ['pancake', 'sandwich', 'quesadilla'] @@ -409,21 +440,42 @@ breakfast, lunch, dinner = foods breakfast #=> 'pancake' dinner #=> 'quesadilla' -# 按照惯例,所有返回布尔值的方法都以?结尾 +# 有些情况下,你会想使用解构操作符 `*` 来解构数组 +ranked_competitors = ["John", "Sally", "Dingus", "Moe", "Marcy"] + +def best(first, second, third) + puts "Winners are #{first}, #{second}, and #{third}." +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." +end + +best *ranked_competitors +#=> Winners are John, Sally, and Dingus. +#=> There were 2 other participants. + +# 按照惯例,所有返回布尔值的方法都以 ? 结尾 5.even? # false 5.odd? # true -# 如果方法名末尾有!,表示会做一些破坏性的操作,比如修改调用者自身。 -# 很多方法都会有一个!的版本来进行修改,和一个非!的版本 -# 只用来返回更新了的结果 +# 如果方法名末尾有感叹号 !,表示会做一些破坏性的操作,比如修改调用者自身。 +# 很多方法都会有一个 ! 的版本来进行修改, +# 和一个只返回更新结果的非 ! 版本 company_name = "Dunder Mifflin" company_name.upcase #=> "DUNDER MIFFLIN" company_name #=> "Dunder Mifflin" -company_name.upcase! # we're mutating company_name this time! +# 这次我们修改了 company_name +company_name.upcase! #=> "DUNDER MIFFLIN" company_name #=> "DUNDER MIFFLIN" +# 类 -# 用class关键字定义一个类 +# 用 class 关键字定义一个类 class Human # 一个类变量,它被这个类的所有实例变量共享 @@ -431,30 +483,30 @@ class Human # 基本构造函数 def initialize(name, age = 0) - # 将参数值赋给实例变量"name" + # 将参数值赋给实例变量 "name" @name = name - # 如果没有给出age,那么会采用参数列表中的默认值 + # 如果没有给出 age,那么会采用参数列表中的默认值 @age = age end - # 基本的setter方法 + # 基本的 setter 方法 def name=(name) @name = name end - # 基本地getter方法 + # 基本地 getter 方法 def name @name end - # 以上的功能也可以用下面的attr_accessor来封装 + # 以上的功能也可以用下面的 attr_accessor 来封装 attr_accessor :name - # Getter/setter方法也可以像这样单独创建 + # Getter/setter 方法也可以像这样单独创建 attr_reader :name attr_writer :name - # 类方法通过使用self与实例方法区别开来。 + # 类方法通过使用 self 与实例方法区别开来。 # 它只能通过类来调用,不能通过实例调用。 def self.say(msg) puts "#{msg}" @@ -468,7 +520,6 @@ end # 初始化一个类 jim = Human.new("Jim Halpert") - dwight = Human.new("Dwight K. Schrute") # 让我们来调用一些方法 @@ -483,15 +534,15 @@ dwight.name #=> "Dwight K. Schrute" Human.say('Hi') #=> "Hi" # 变量的作用域由它们的名字格式定义 -# 以$开头的变量具有全局域 +# 以 $ 开头的变量具有全局域 $var = "I'm a global var" defined? $var #=> "global-variable" -# 以@开头的变量具有实例作用域 +# 以 @ 开头的变量具有实例作用域 @var = "I'm an instance var" defined? @var #=> "instance-variable" -# 以@@开头的变量具有类作用域 +# 以 @@ 开头的变量具有类作用域 @@var = "I'm a class var" defined? @@var #=> "class variable" @@ -568,7 +619,6 @@ Book.foo # => 'foo' Book.new.foo # => NoMethodError: undefined method `foo' # 当包含或扩展一个模块时,相应的回调代码会被执行。 - module ConcernExample def self.included(base) base.extend(ClassMethods) |