diff options
-rw-r--r-- | ansible.html.markdown | 2 | ||||
-rw-r--r-- | awk.html.markdown | 2 | ||||
-rw-r--r-- | bc.html.markdown | 98 | ||||
-rw-r--r-- | cypher.html.markdown | 2 | ||||
-rw-r--r-- | de-de/c++-de.html.markdown | 1161 | ||||
-rw-r--r-- | es-es/dart-es.html.markdown | 529 | ||||
-rw-r--r-- | es-es/kotlin-es.html.markdown | 68 | ||||
-rw-r--r-- | es-es/scala-es.html.markdown | 741 | ||||
-rw-r--r-- | fr-fr/erlang-fr.html.markdown | 4 | ||||
-rw-r--r-- | it-it/rust-it.html.markdown | 4 | ||||
-rw-r--r-- | prolog.html.markdown | 2 | ||||
-rw-r--r-- | pt-br/clojure-pt.html.markdown | 2 | ||||
-rw-r--r-- | pug.html.markdown | 204 | ||||
-rw-r--r-- | python3.html.markdown | 2 | ||||
-rw-r--r-- | rst.html.markdown | 16 | ||||
-rw-r--r-- | th-th/pascal.th.html.markdown | 236 | ||||
-rw-r--r-- | typescript.html.markdown | 24 | ||||
-rw-r--r-- | zh-cn/ruby-cn.html.markdown | 160 |
18 files changed, 3175 insertions, 82 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/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/c++-de.html.markdown b/de-de/c++-de.html.markdown new file mode 100644 index 00000000..eec11d61 --- /dev/null +++ b/de-de/c++-de.html.markdown @@ -0,0 +1,1161 @@ +--- +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 verbeitet, weil sie in Maschinen-Code compiliert, 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. (wie C) +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 and 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 Ineteger 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: + +// In C++ sind Zeichen-Literale chars +sizeof('c') == sizeof(char) == 1 + +// In C sind Zeichen-Literale ints +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 headers 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 "ints" 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 Namespaces "Nested" +} // Ende des Namespaces "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 Synthax 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 Ausnahme, dass die "am Ende des Ausdrucks" Regel ist gültig, +// wenn das temporäre Objekt an eine konstante Referenz gebunden ist, in welchem Fall das +// Leben 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 wird 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. +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 enums 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-Funktonensdeklaration (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 sollte 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 implmentiert. +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" + +// Vererbung: + +// 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 Kompiler 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 definiert 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 Aufäumen wird definitv 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 Tenplate 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 gesmten 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-primitve 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 bools. +// 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 Tuples alten Datenstrukturen sehr ähnlich, allerdings haben diese keine +// benamten 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/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/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/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/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/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/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/th-th/pascal.th.html.markdown b/th-th/pascal.th.html.markdown new file mode 100644 index 00000000..05e37a28 --- /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"] +translator: + - ["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/typescript.html.markdown b/typescript.html.markdown index ba4a9e71..55d8cefe 100644 --- a/typescript.html.markdown +++ b/typescript.html.markdown @@ -223,6 +223,30 @@ 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 + +// 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/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) |