Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Geoff Liu 2015-04-17 14:06:47 -04:00
commit 49e8dd4263
24 changed files with 2817 additions and 631 deletions

View File

@ -8,6 +8,8 @@ contributors:
Brainfuck (not capitalized except at the start of a sentence) is an extremely Brainfuck (not capitalized except at the start of a sentence) is an extremely
minimal Turing-complete programming language with just 8 commands. minimal Turing-complete programming language with just 8 commands.
You can try brainfuck on your browser with [brainfuck-visualizer](http://fatiherikli.github.io/brainfuck-visualizer/).
``` ```
Any character not "><+-.,[]" (excluding quotation marks) is ignored. Any character not "><+-.,[]" (excluding quotation marks) is ignored.

View File

@ -555,7 +555,7 @@ void doSomethingWithAFile(const char* filename)
// Compare this to the use of C++'s file stream class (fstream) // Compare this to the use of C++'s file stream class (fstream)
// fstream uses its destructor to close the file. // fstream uses its destructor to close the file.
// Recall from above that destructors are automatically called // Recall from above that destructors are automatically called
// whenver an object falls out of scope. // whenever an object falls out of scope.
void doSomethingWithAFile(const std::string& filename) void doSomethingWithAFile(const std::string& filename)
{ {
// ifstream is short for input file stream // ifstream is short for input file stream

View File

@ -234,7 +234,7 @@ int main() {
// same with j-- and --j // same with j-- and --j
// Bitwise operators! // Bitwise operators!
~0x0F; // => 0xF0 (bitwise negation, "1's complement") ~0x0F; // => 0xFFFFFFF0 (bitwise negation, "1's complement", example result for 32-bit int)
0x0F & 0xF0; // => 0x00 (bitwise AND) 0x0F & 0xF0; // => 0x00 (bitwise AND)
0x0F | 0xF0; // => 0xFF (bitwise OR) 0x0F | 0xF0; // => 0xFF (bitwise OR)
0x04 ^ 0x0F; // => 0x0B (bitwise XOR) 0x04 ^ 0x0F; // => 0x0B (bitwise XOR)
@ -242,7 +242,7 @@ int main() {
0x02 >> 1; // => 0x01 (bitwise right shift (by 1)) 0x02 >> 1; // => 0x01 (bitwise right shift (by 1))
// Be careful when shifting signed integers - the following are undefined: // Be careful when shifting signed integers - the following are undefined:
// - shifting into the sign bit of a signed integer (int a = 1 << 32) // - shifting into the sign bit of a signed integer (int a = 1 << 31)
// - left-shifting a negative number (int a = -1 << 2) // - left-shifting a negative number (int a = -1 << 2)
// - shifting by an offset which is >= the width of the type of the LHS: // - shifting by an offset which is >= the width of the type of the LHS:
// int a = 1 << 32; // UB if int is 32 bits wide // int a = 1 << 32; // UB if int is 32 bits wide

View File

@ -5,34 +5,34 @@ contributors:
- ["Joseph Adams", "https://github.com/jcla1"] - ["Joseph Adams", "https://github.com/jcla1"]
lang: de-de lang: de-de
--- ---
Go wurde entwickelt um probleme zu lösen. Sie ist zwar nicht der neuste Trend in Go wurde entwickelt, um Probleme zu lösen. Sie ist zwar nicht der neueste Trend in
der Informatik, aber sie ist eine der neusten und schnellsten Wege um Aufgabe in der Informatik, aber sie ist einer der neuesten und schnellsten Wege, um Aufgabe in
der realen Welt zu lösen. der realen Welt zu lösen.
Sie hat vertraute Elemente von imperativen Sprachen mit statisher Typisierung Sie hat vertraute Elemente von imperativen Sprachen mit statischer Typisierung
und kann schnell kompiliert und ausgeführt werden. Verbunden mit leicht zu und kann schnell kompiliert und ausgeführt werden. Verbunden mit leicht zu
verstehenden Parallelitäts-Konstrukten, um die heute üblichen mehrkern verstehenden Parallelitäts-Konstrukten, um die heute üblichen mehrkern
Prozessoren optimal nutzen zu können, eignet sich Go äußerst gut für große Prozessoren optimal nutzen zu können, eignet sich Go äußerst gut für große
Programmierprojekte. Programmierprojekte.
Außerdem beinhaltet Go eine gut ausgestattete standard bibliothek und hat eine Außerdem beinhaltet Go eine gut ausgestattete Standardbibliothek und hat eine
aktive community. aktive Community.
```go ```go
// Einzeiliger Kommentar // Einzeiliger Kommentar
/* Mehr- /* Mehr-
zeiliger Kommentar */ zeiliger Kommentar */
// Eine jede Quelldatei beginnt mit einer Packet-Klausel. // Eine jede Quelldatei beginnt mit einer Paket-Klausel.
// "main" ist ein besonderer Packetname, da er ein ausführbares Programm // "main" ist ein besonderer Pkaetname, da er ein ausführbares Programm
// einleitet, im Gegensatz zu jedem anderen Namen, der eine Bibliothek // einleitet, im Gegensatz zu jedem anderen Namen, der eine Bibliothek
// deklariert. // deklariert.
package main package main
// Ein "import" wird verwendet um Packte zu deklarieren, die in dieser // Ein "import" wird verwendet, um Pakete zu deklarieren, die in dieser
// Quelldatei Anwendung finden. // Quelldatei Anwendung finden.
import ( import (
"fmt" // Ein Packet in der Go standard Bibliothek "fmt" // Ein Paket in der Go Standardbibliothek
"net/http" // Ja, ein Webserver. "net/http" // Ja, ein Webserver.
"strconv" // Zeichenkettenmanipulation "strconv" // Zeichenkettenmanipulation
) )
@ -42,10 +42,10 @@ import (
// Programms. Vergessen Sie nicht die geschweiften Klammern! // Programms. Vergessen Sie nicht die geschweiften Klammern!
func main() { func main() {
// Println gibt eine Zeile zu stdout aus. // Println gibt eine Zeile zu stdout aus.
// Der Prefix "fmt" bestimmt das Packet aus welchem die Funktion stammt. // Der Prefix "fmt" bestimmt das Paket aus welchem die Funktion stammt.
fmt.Println("Hello world!") fmt.Println("Hello world!")
// Aufruf einer weiteren Funktion definiert innerhalb dieses Packets. // Aufruf einer weiteren Funktion definiert innerhalb dieses Pakets.
beyondHello() beyondHello()
} }
@ -54,7 +54,7 @@ func main() {
func beyondHello() { func beyondHello() {
var x int // Deklaration einer Variable, muss vor Gebrauch geschehen. var x int // Deklaration einer Variable, muss vor Gebrauch geschehen.
x = 3 // Zuweisung eines Werts. x = 3 // Zuweisung eines Werts.
// Kurze Deklaration: Benutzen Sie ":=" um die Typisierung automatisch zu // Kurze Deklaration: Benutzen Sie ":=", um die Typisierung automatisch zu
// folgern, die Variable zu deklarieren und ihr einen Wert zu zuweisen. // folgern, die Variable zu deklarieren und ihr einen Wert zu zuweisen.
y := 4 y := 4
@ -70,7 +70,7 @@ func learnMultiple(x, y int) (sum, prod int) {
return x + y, x * y // Wiedergabe zweier Werte return x + y, x * y // Wiedergabe zweier Werte
} }
// Überblick ueber einige eingebaute Typen und Literale. // Überblick über einige eingebaute Typen und Literale.
func learnTypes() { func learnTypes() {
// Kurze Deklarationen sind die Norm. // Kurze Deklarationen sind die Norm.
s := "Lernen Sie Go!" // Zeichenketten-Typ s := "Lernen Sie Go!" // Zeichenketten-Typ
@ -111,7 +111,7 @@ Zeilenumbrüche beinhalten.` // Selber Zeichenketten-Typ
m["eins"] = 1 m["eins"] = 1
// Ungebrauchte Variablen sind Fehler in Go // Ungebrauchte Variablen sind Fehler in Go
// Der Unterstrich wird verwendet um einen Wert zu verwerfen. // Der Unterstrich wird verwendet, um einen Wert zu verwerfen.
_, _, _, _, _, _, _, _, _ = s2, g, f, u, pi, n, a3, s4, bs _, _, _, _, _, _, _, _, _ = s2, g, f, u, pi, n, a3, s4, bs
// Die Ausgabe zählt natürlich auch als Gebrauch // Die Ausgabe zählt natürlich auch als Gebrauch
fmt.Println(s, c, a4, s3, d2, m) fmt.Println(s, c, a4, s3, d2, m)
@ -142,7 +142,7 @@ func learnFlowControl() {
if true { if true {
fmt.Println("hab's dir ja gesagt!") fmt.Println("hab's dir ja gesagt!")
} }
// Die Formattierung ist durch den Befehl "go fmt" standardisiert // Die Formatierung ist durch den Befehl "go fmt" standardisiert
if false { if false {
// nicht hier // nicht hier
} else { } else {
@ -170,7 +170,7 @@ func learnFlowControl() {
continue // wird nie ausgeführt continue // wird nie ausgeführt
} }
// Wie bei for, bedeutet := in einer Bedingten Anweisung zunächst die // Wie bei for, bedeutet := in einer bedingten Anweisung zunächst die
// Zuweisung und erst dann die Überprüfung der Bedingung. // Zuweisung und erst dann die Überprüfung der Bedingung.
if y := expensiveComputation(); y > x { if y := expensiveComputation(); y > x {
x = y x = y
@ -217,8 +217,8 @@ func learnInterfaces() {
// Aufruf der String Methode von i, gleiche Ausgabe wie zuvor. // Aufruf der String Methode von i, gleiche Ausgabe wie zuvor.
fmt.Println(i.String()) fmt.Println(i.String())
// Funktionen des fmt-Packets rufen die String() Methode auf um eine // Funktionen des fmt-Pakets rufen die String() Methode auf um eine
// druckbare variante des Empfängers zu erhalten. // druckbare Variante des Empfängers zu erhalten.
fmt.Println(p) // gleiche Ausgabe wie zuvor fmt.Println(p) // gleiche Ausgabe wie zuvor
fmt.Println(i) // und wieder die gleiche Ausgabe wie zuvor fmt.Println(i) // und wieder die gleiche Ausgabe wie zuvor
@ -244,18 +244,18 @@ func learnErrorHandling() {
learnConcurrency() learnConcurrency()
} }
// c ist ein Kannal, ein sicheres Kommunikationsmedium. // c ist ein Kanal, ein sicheres Kommunikationsmedium.
func inc(i int, c chan int) { func inc(i int, c chan int) {
c <- i + 1 // <- ist der "send" Operator, wenn ein Kannal auf der Linken ist c <- i + 1 // <- ist der "send" Operator, wenn ein Kanal auf der Linken ist
} }
// Wir verwenden "inc" um Zahlen parallel zu erhöhen. // Wir verwenden "inc" um Zahlen parallel zu erhöhen.
func learnConcurrency() { func learnConcurrency() {
// Die selbe "make"-Funktion wie vorhin. Sie initialisiert Speicher für // Die selbe "make"-Funktion wie vorhin. Sie initialisiert Speicher für
// maps, slices und Kannäle. // maps, slices und Kanäle.
c := make(chan int) c := make(chan int)
// Starte drei parallele "Goroutines". Die Zahlen werden parallel (concurrently) // Starte drei parallele "Goroutines". Die Zahlen werden parallel (concurrently)
// erhöht. Alle drei senden ihr Ergebnis in den gleichen Kannal. // erhöht. Alle drei senden ihr Ergebnis in den gleichen Kanal.
go inc(0, c) // "go" ist das Statement zum Start einer neuen Goroutine go inc(0, c) // "go" ist das Statement zum Start einer neuen Goroutine
go inc(10, c) go inc(10, c)
go inc(-805, c) go inc(-805, c)
@ -269,16 +269,16 @@ func learnConcurrency() {
// Start einer neuen Goroutine, nur um einen Wert zu senden // Start einer neuen Goroutine, nur um einen Wert zu senden
go func() { c <- 84 }() go func() { c <- 84 }()
go func() { cs <- "wortreich" }() // schon wider, diesmal für go func() { cs <- "wortreich" }() // schon wieder, diesmal für
// "select" hat eine Syntax wie ein switch Statement, aber jeder Fall ist // "select" hat eine Syntax wie ein switch Statement, aber jeder Fall ist
// eine Kannaloperation. Es wählt eine Fall zufällig aus allen die // eine Kanaloperation. Es wählt einen Fall zufällig aus allen, die
// kommunikationsbereit sind aus. // kommunikationsbereit sind, aus.
select { select {
case i := <-c: // der empfangene Wert kann einer Variable zugewiesen werden case i := <-c: // der empfangene Wert kann einer Variable zugewiesen werden
fmt.Printf("es ist ein: %T", i) fmt.Printf("es ist ein: %T", i)
case <-cs: // oder der Wert kann verworfen werden case <-cs: // oder der Wert kann verworfen werden
fmt.Println("es ist eine Zeichenkette!") fmt.Println("es ist eine Zeichenkette!")
case <-cc: // leerer Kannal, nicht bereit für den Empfang case <-cc: // leerer Kanal, nicht bereit für den Empfang
fmt.Println("wird nicht passieren.") fmt.Println("wird nicht passieren.")
} }
// Hier wird eine der beiden Goroutines fertig sein, die andere nicht. // Hier wird eine der beiden Goroutines fertig sein, die andere nicht.
@ -287,16 +287,16 @@ func learnConcurrency() {
learnWebProgramming() // Go kann es und Sie hoffentlich auch bald. learnWebProgramming() // Go kann es und Sie hoffentlich auch bald.
} }
// Eine einzige Funktion aus dem http-Packet kann einen Webserver starten. // Eine einzige Funktion aus dem http-Paket kann einen Webserver starten.
func learnWebProgramming() { func learnWebProgramming() {
// Der erste Parameter von "ListenAndServe" ist eine TCP Addresse an die // Der erste Parameter von "ListenAndServe" ist eine TCP Addresse, an die
// sich angeschlossen werden soll. // sich angeschlossen werden soll.
// Der zweite Parameter ist ein Interface, speziell: ein http.Handler // Der zweite Parameter ist ein Interface, speziell: ein http.Handler
err := http.ListenAndServe(":8080", pair{}) err := http.ListenAndServe(":8080", pair{})
fmt.Println(err) // Fehler sollte man nicht ignorieren! fmt.Println(err) // Fehler sollte man nicht ignorieren!
} }
// Wir lassen "pair" das http.Handler Interface erfüllen indem wir seine einzige // Wir lassen "pair" das http.Handler Interface erfüllen, indem wir seine einzige
// Methode implementieren: ServeHTTP // Methode implementieren: ServeHTTP
func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Senden von Daten mit einer Methode des http.ResponseWriter // Senden von Daten mit einer Methode des http.ResponseWriter
@ -313,6 +313,6 @@ Auch zu empfehlen ist die Spezifikation von Go, die nach heutigen Standards sehr
kurz und auch gut verständlich formuliert ist. Auf der Leseliste von Go-Neulingen kurz und auch gut verständlich formuliert ist. Auf der Leseliste von Go-Neulingen
ist außerdem der Quelltext der [Go standard Bibliothek](http://golang.org/src/pkg/). ist außerdem der Quelltext der [Go standard Bibliothek](http://golang.org/src/pkg/).
Gut documentiert, demonstriert sie leicht zu verstehendes und im idiomatischen Stil Gut documentiert, demonstriert sie leicht zu verstehendes und im idiomatischen Stil
verfasstes Go. Erreichbar ist der Quelltext auch durch das Klicken der Funktions- verfasstes Go. Erreichbar ist der Quelltext auch durch das Klicken der Funktionsnamen
Namen in der [offiziellen Dokumentation von Go](http://golang.org/pkg/). in der [offiziellen Dokumentation von Go](http://golang.org/pkg/).

View File

@ -149,7 +149,7 @@ li[0] #=> 1
# Das letzte Element ansehen # Das letzte Element ansehen
li[-1] #=> 3 li[-1] #=> 3
# Bei Zugriffen außerhal der Liste kommt es jedoch zu einem IndexError # Bei Zugriffen außerhalb der Liste kommt es jedoch zu einem IndexError
li[4] # Raises an IndexError li[4] # Raises an IndexError
# Wir können uns Ranges mit Slice-Syntax ansehen # Wir können uns Ranges mit Slice-Syntax ansehen
@ -188,7 +188,7 @@ tup[:2] #=> (1, 2)
# Wir können Tupel (oder Listen) in Variablen entpacken # Wir können Tupel (oder Listen) in Variablen entpacken
a, b, c = (1, 2, 3) # a ist jetzt 1, b ist jetzt 2 und c ist jetzt 3 a, b, c = (1, 2, 3) # a ist jetzt 1, b ist jetzt 2 und c ist jetzt 3
# Tuple werden standardmäßig erstellt, wenn wir uns die Klammern sparen # Tupel werden standardmäßig erstellt, wenn wir uns die Klammern sparen
d, e, f = 4, 5, 6 d, e, f = 4, 5, 6
# Es ist kinderleicht zwei Werte zu tauschen # Es ist kinderleicht zwei Werte zu tauschen
e, d = d, e # d is now 5 and e is now 4 e, d = d, e # d is now 5 and e is now 4

View File

@ -206,7 +206,7 @@ max(X, Y) ->
if if
X > Y -> X; X > Y -> X;
X < Y -> Y; X < Y -> Y;
true -> nil; true -> nil
end. end.
% Warning: at least one of the guards in the `if` expression must evaluate to true; % Warning: at least one of the guards in the `if` expression must evaluate to true;

439
fr-fr/go-fr.html.markdown Normal file
View File

@ -0,0 +1,439 @@
---
name: Go
category: language
language: Go
lang: fr-fr
filename: learngo.go
contributors:
- ["Sonia Keys", "https://github.com/soniakeys"]
- ["Christopher Bess", "https://github.com/cbess"]
- ["Jesse Johnson", "https://github.com/holocronweaver"]
- ["Quint Guvernator", "https://github.com/qguv"]
- ["Jose Donizetti", "https://github.com/josedonizetti"]
- ["Alexej Friesen", "https://github.com/heyalexej"]
- ["Jean-Philippe Monette", "http://blogue.jpmonette.net/"]
---
Go a été créé dans l'optique de développer de façon efficace. Ce n'est pas la
dernière tendance en ce qui est au développement, mais c'est la nouvelle façon
de régler des défis réels de façon rapide.
Le langage possède des concepts familiers à la programmation impérative avec
typage. Il est rapide à compiler et exécuter, ajoute une concurrence facile à
comprendre, pour les processeurs multi coeurs d'aujourd'hui et apporte des
fonctionnalités facilitant le développement à grande échelle.
Développer avec Go, c'est bénéficier d'une riche bibliothèque standard et d'une
communauté active.
```go
// Commentaire ligne simple
/* Commentaire
multiligne */
// Un paquet débute avec une clause "package"
// "Main" est un nom spécial déclarant un paquet de type exécutable plutôt
// qu'une bibliothèque
package main
// "Import" déclare les paquets référencés dans ce fichier.
import (
"fmt" // Un paquet dans la bibliothèque standard.
"io/ioutil" // Implémente des fonctions utilitaires I/O.
m "math" // Bibliothèque mathématique utilisant un alias local "m".
"net/http" // Un serveur Web!
"strconv" // Bibliothèque pour convertir les chaînes de caractères.
)
// Une définition de fonction. La fonction "main" est spéciale - c'est le point
// d'entrée du binaire.
func main() {
// Println retournera la valeur à la console.
// Associez la fonction avec son paquet respectif, fmt.
fmt.Println("Hello world!")
// Appelez une fonction différente à partir de ce paquet.
beyondHello()
}
// Les fonctions ont des paramètres entre parenthèses.
// Les parenthèses sont nécessaires avec ou sans paramètre.
func beyondHello() {
var x int // Déclaration de variable. Les variables doivent être déclarées
// avant leur utilisation.
x = 3 // Assignation de valeur.
// Les déclarations courtes utilisent := pour inférer le type, déclarer et
// assigner.
y := 4
sum, prod := learnMultiple(x, y) // La fonction retourne deux valeurs.
fmt.Println("sum:", sum, "prod:", prod) // Affichage simple.
learnTypes() // < y minutes, en savoir plus!
}
// Les fonctions peuvent avoir des paramètres et plusieurs valeurs retournées.
func learnMultiple(x, y int) (sum, prod int) {
return x + y, x * y // Deux valeurs retournées.
}
// Quelques types inclus et littéraux.
func learnTypes() {
// Une déclaration courte infère généralement le type désiré.
str := "Learn Go!" // Type string.
s2 := `Une chaîne de caractères peut contenir des
sauts de ligne.` // Chaîne de caractère.
// Littéral non-ASCII. Les sources Go utilisent le charset UTF-8.
g := 'Σ' // type rune, un alias pour le type int32, contenant un caractère
// unicode.
f := 3.14195 // float64, un nombre flottant IEEE-754 de 64-bit.
c := 3 + 4i // complex128, considéré comme deux float64 par le compilateur.
// Syntaxe "var" avec une valeur d'initialisation.
var u uint = 7 // Non signé, mais la taille dépend selon l'entier.
var pi float32 = 22. / 7
// Conversion avec syntaxe courte.
n := byte('\n') // byte est un alias du type uint8.
// Les tableaux ont une taille fixe déclarée à la compilation.
var a4 [4]int // Un tableau de 4 ints, tous initialisés à 0.
a3 := [...]int{3, 1, 5} // Un tableau initialisé avec une taille fixe de 3
// éléments, contenant les valeurs 3, 1 et 5.
// Les slices ont des tailles dynamiques. Les tableaux et slices ont chacun
// des avantages, mais les cas d'utilisation des slices sont plus fréquents.
s3 := []int{4, 5, 9} // Comparable à a3.
s4 := make([]int, 4) // Alloue un slice de 4 ints, initialisés à 0.
var d2 [][]float64 // Déclaration seulement, sans allocation de mémoire.
bs := []byte("a slice") // Conversion d'une chaîne en slice de bytes.
// Parce qu'elles sont dynamiques, les slices peuvent être jointes sur
// demande. Pour joindre un élément à une slice, la fonction standard append()
// est utilisée. Le premier argument est la slice à utiliser. Habituellement,
// la variable tableau est mise à jour sur place, voir ci-bas.
s := []int{1, 2, 3} // Le résultat est une slice de taille 3.
s = append(s, 4, 5, 6) // Ajout de 3 valeurs. La taille est de 6.
fmt.Println(s) // La valeur est de [1 2 3 4 5 6]
// Pour ajouter une slice à une autre, au lieu d'utiliser une liste de valeurs
// atomiques, il est possible de mettre en argument une référence de
// slice littérale grâce aux points de suspension.
s = append(s, []int{7, 8, 9}...) // Le deuxième argument est une slice
// littérale.
fmt.Println(s) // La slice contient [1 2 3 4 5 6 7 8 9]
p, q := learnMemory() // Déclare p, q comme étant des pointeurs de type int.
fmt.Println(*p, *q) // * suit un pointeur. Ceci retourne deux ints.
// Les maps sont des tableaux associatifs de taille dynamique, comme les
// hash ou les types dictionnaires de certains langages.
m := map[string]int{"trois": 3, "quatre": 4}
m["un"] = 1
// Les valeurs inutilisées sont considérées comme des erreurs en Go.
// Un tiret bas permet d'ignorer une valeur inutilisée, évitant une erreur.
_, _, _, _, _, _, _, _, _, _ = str, s2, g, f, u, pi, n, a3, s4, bs
// Cependant, son affichage en console est considéré comme une utilisation,
// ce qui ne sera pas considéré comme une erreur à la compilation.
fmt.Println(s, c, a4, s3, d2, m)
learnFlowControl() // De retour dans le flux.
}
// Il est possible, à l'opposé de plusieurs autres langages, de retourner des
// variables par leur nom à partir de fonctions.
// Assigner un nom à un type retourné par une fonction permet de retrouver sa
// valeur ainsi que d'utiliser le mot-clé "return" uniquement, sans plus.
func learnNamedReturns(x, y int) (z int) {
z = x * y
return // z est implicite, car la variable a été définie précédemment.
}
// La récupération de la mémoire est automatique en Go. Le langage possède des
// pointeurs, mais aucune arithmétique des pointeurs (*(a + b) en C). Vous
// pouvez produire une erreur avec un pointeur nil, mais pas en incrémentant un
// pointeur.
func learnMemory() (p, q *int) {
// Les valeurs retournées p et q auront le type pointeur int.
p = new(int) // Fonction standard "new" alloue la mémoire.
// Le int alloué est initialisé à 0, p n'est plus nil.
s := make([]int, 20) // Alloue 20 ints en un seul bloc de mémoire.
s[3] = 7 // Assigne l'un des entiers.
r := -2 // Déclare une autre variable locale.
return &s[3], &r // & retourne l'adresse d'un objet.
}
func expensiveComputation() float64 {
return m.Exp(10)
}
func learnFlowControl() {
// Bien que les "if" requièrent des accolades, les parenthèses ne sont pas
// nécessaires pour contenir le test booléen.
if true {
fmt.Println("voilà!")
}
// Le formatage du code est standardisé par la commande shell "go fmt."
if false {
// bing.
} else {
// bang.
}
// Utilisez "switch" au lieu des "if" en chaîne
x := 42.0
switch x {
case 0:
case 1:
case 42:
// Les "case" n'ont pas besoin de "break;".
case 43:
// Non-exécuté.
}
// Comme les "if", les "for" n'utilisent pas de parenthèses.
// Les variables déclarées dans les "for" et les "if" sont locales à leur
// portée.
for x := 0; x < 3; x++ { // ++ est une incrémentation.
fmt.Println("itération ", x)
}
// x == 42 ici.
// "For" est le seul type de boucle en Go, mais possède différentes formes.
for { // Boucle infinie
break // C'est une farce
continue // Non atteint.
}
// Vous pouvez utiliser une "range" pour itérer dans un tableau, une slice, une
// chaîne, une map ou un canal. Les "range" retournent un canal ou deux
// valeurs (tableau, slice, chaîne et map).
for key, value := range map[string]int{"une": 1, "deux": 2, "trois": 3} {
// pour chaque pair dans une map, affichage de la valeur et clé
fmt.Printf("clé=%s, valeur=%d\n", key, value)
}
// À l'opposé du "for", := dans un "if" signifie la déclaration et
// l'assignation y en premier, et ensuite y > x
if y := expensiveComputation(); y > x {
x = y
}
// Les fonctions littérales sont des fermetures.
xBig := func() bool {
return x > 10000
}
fmt.Println("xBig:", xBig()) // true (la valeur e^10 a été assignée à x).
x = 1.3e3 // Ceci fait x == 1300
fmt.Println("xBig:", xBig()) // Maintenant false.
// De plus, les fonctions littérales peuvent être définies et appelées
// sur la même ligne, agissant comme argument à cette fonction, tant que:
// a) la fonction littérale est appelée suite à (),
// b) le résultat correspond au type de l'argument.
fmt.Println("Ajoute + multiplie deux nombres : ",
func(a, b int) int {
return (a + b) * 2
}(10, 2)) // Appelle la fonction avec les arguments 10 et 2
// => Ajoute + double deux nombres : 24
// Quand vous en aurez besoin, vous allez l'adorer.
goto love
love:
learnFunctionFactory() // func retournant func correspondant à fun(3)(3).
learnDefer() // Un survol de cette instruction importante.
learnInterfaces() // Incontournable !
}
func learnFunctionFactory() {
// Les deux syntaxes sont identiques, bien que la seconde soit plus pratique.
fmt.Println(sentenceFactory("été")("Une matinée d'", "agréable!"))
d := sentenceFactory("été")
fmt.Println(d("Une matinée d'", "agréable!"))
fmt.Println(d("Une soirée d'", "relaxante!"))
}
// Le décorateur est un patron de conception commun dans d'autres langages.
// Il est possible de faire de même en Go avec des fonctions littérales
// acceptant des arguments.
func sentenceFactory(mystring string) func(before, after string) string {
return func(before, after string) string {
return fmt.Sprintf("%s %s %s", before, mystring, after) // nouvelle chaîne
}
}
func learnDefer() (ok bool) {
// Les déclarations différées sont exécutées avant la sortie d'une fonction.
defer fmt.Println("les déclarations différées s'exécutent en ordre LIFO.")
defer fmt.Println("\nCette ligne est affichée en premier parce que")
// Les déclarations différées sont utilisées fréquemment pour fermer un
// fichier, afin que la fonction ferme le fichier en fin d'exécution.
return true
}
// Défini Stringer comme étant une interface avec une méthode, String.
type Stringer interface {
String() string
}
// Défini pair comme étant une structure contenant deux entiers, x et y.
type pair struct {
x, y int
}
// Défini une méthode associée au type pair. Pair implémente maintenant Stringer
func (p pair) String() string { // p s'appelle le "destinataire"
// Sprintf est une autre fonction publique dans le paquet fmt.
// La syntaxe avec point permet de faire référence aux valeurs de p.
return fmt.Sprintf("(%d, %d)", p.x, p.y)
}
func learnInterfaces() {
// La syntaxe avec accolade défini une "structure littérale". Celle-ci
// s'évalue comme étant une structure. La syntaxe := déclare et initialise p
// comme étant une instance.
p := pair{3, 4}
fmt.Println(p.String()) // Appelle la méthode String de p, de type pair.
var i Stringer // Déclare i instance de l'interface Stringer.
i = p // Valide, car pair implémente Stringer.
// Appelle la méthode String de i, de type Stringer. Retourne la même valeur
// que ci-haut.
fmt.Println(i.String())
// Les fonctions dans le paquet fmt appellent la méthode String, demandant
// aux objets d'afficher une représentation de leur structure.
fmt.Println(p) // Affiche la même chose que ci-haut. Println appelle la
// méthode String.
fmt.Println(i) // Affiche la même chose que ci-haut.
learnVariadicParams("apprentissage", "génial", "ici!")
}
// Les fonctions peuvent être définie de façon à accepter un ou plusieurs
// paramètres grâce aux points de suspension, offrant une flexibilité lors de
// son appel.
func learnVariadicParams(myStrings ...interface{}) {
// Itère chaque paramètre dans la range.
// Le tiret bas sert à ignorer l'index retourné du tableau.
for _, param := range myStrings {
fmt.Println("paramètre:", param)
}
// Passe une valeur variadique comme paramètre variadique.
fmt.Println("paramètres:", fmt.Sprintln(myStrings...))
learnErrorHandling()
}
func learnErrorHandling() {
// ", ok" idiome utilisée pour définir si l'opération s'est déroulée avec
// succès ou non
m := map[int]string{3: "trois", 4: "quatre"}
if x, ok := m[1]; !ok { // ok sera faux, car 1 n'est pas dans la map.
fmt.Println("inexistant")
} else {
fmt.Print(x) // x serait la valeur, si elle se trouvait dans la map.
}
// Une erreur ne retourne qu'un "ok", mais également plus d'information
// par rapport à un problème survenu.
if _, err := strconv.Atoi("non-int"); err != nil { // _ discarte la valeur
// retourne: 'strconv.ParseInt: parsing "non-int": invalid syntax'
fmt.Println(err)
}
// Nous réviserons les interfaces un peu plus tard. Pour l'instant,
learnConcurrency()
}
// c est un canal, un objet permettant de communiquer en simultané de façon
// sécurisée.
func inc(i int, c chan int) {
c <- i + 1 // <- est l'opérateur "envoi" quand un canal apparaît à
// gauche.
}
// Nous utiliserons inc pour incrémenter des nombres en même temps.
func learnConcurrency() {
// La fonction "make" utilisée précédemment pour générer un slice. Elle
// alloue et initialise les slices, maps et les canaux.
c := make(chan int)
// Démarrage de trois goroutines simultanées. Les nombres seront incrémentés
// simultanément, peut-être en paralèle si la machine le permet et configurée
// correctement. Les trois utilisent le même canal.
go inc(0, c) // go est une instruction démarrant une nouvelle goroutine.
go inc(10, c)
go inc(-805, c)
// Lis et affiche trois résultats du canal - impossible de savoir dans quel
// ordre !
fmt.Println(<-c, <-c, <-c) // Canal à droite, <- est l'opérateur de
// "réception".
cs := make(chan string) // Un autre canal, celui-ci gère des chaînes.
ccs := make(chan chan string) // Un canal de canaux de chaînes.
go func() { c <- 84 }() // Démarre une nouvelle goroutine, pour
// envoyer une valeur.
go func() { cs <- "wordy" }() // De nouveau, pour cs cette fois-ci.
// Select possède une syntaxe similaire au switch, mais chaque cas requiert
// une opération impliquant un canal. Il sélectionne un cas aléatoirement
// prêt à communiquer.
select {
case i := <-c: // La valeur reçue peut être assignée à une variable,
fmt.Printf("c'est un %T", i)
case <-cs: // ou la valeur reçue peut être ignorée.
fmt.Println("c'est une chaîne")
case <-ccs: // Un canal vide, indisponible à la communication.
fmt.Println("ne surviendra pas.")
}
// À ce point, une valeur a été prise de c ou cs. L'une des deux goroutines
// démarrée plus haut a complétée, la seconde restera bloquée.
learnWebProgramming() // Go permet la programmation Web.
}
// Une seule fonction du paquet http démarre un serveur Web.
func learnWebProgramming() {
// Le premier paramètre de ListenAndServe est une adresse TCP à écouter.
// Le second est une interface, de type http.Handler.
go func() {
err := http.ListenAndServe(":8080", pair{})
fmt.Println(err) // n'ignorez pas les erreurs !
}()
requestServer()
}
// Implémente la méthode ServeHTTP de http.Handler à pair, la rendant compatible
// avec les opérations utilisant l'interface http.Handler.
func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Répondez à une requête à l'aide de la méthode http.ResponseWriter.
w.Write([]byte("Vous avez appris Go en Y minutes!"))
}
func requestServer() {
resp, err := http.Get("http://localhost:8080")
fmt.Println(err)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Printf("\nLe serveur Web a dit: `%s`", string(body))
}
```
## En savoir plus
La référence Go se trouve sur [le site officiel de Go](http://golang.org/).
Vous pourrez y suivre le tutoriel interactif et en apprendre beaucoup plus.
Une lecture de la documentation du langage est grandement conseillée. C'est
facile à lire et très court (comparé aux autres langages).
Vous pouvez exécuter et modifier le code sur [Go playground](https://play.golang.org/p/tnWMjr16Mm). Essayez de le modifier et de l'exécuter à partir de votre navigateur! Prennez en note que vous pouvez utiliser [https://play.golang.org](https://play.golang.org) comme un [REPL](https://en.wikipedia.org/wiki/Read-eval-print_loop) pour tester et coder dans votre navigateur, sans même avoir à installer Go.
Sur la liste de lecteur des étudiants de Go se trouve le [code source de la
librairie standard](http://golang.org/src/pkg/). Bien documentée, elle démontre
le meilleur de la clarté de Go, le style ainsi que ses expressions. Sinon, vous
pouvez cliquer sur le nom d'une fonction dans [la
documentation](http://golang.org/pkg/) et le code source apparaît!
Une autre excellente ressource pour apprendre est [Go par l'exemple](https://gobyexample.com/).

View File

@ -202,19 +202,20 @@ foo = (*5) . (+10)
foo 5 -- 75 foo 5 -- 75
-- fixing precedence -- fixing precedence
-- Haskell has another function called `$`. This changes the precedence -- Haskell has another operator called `$`. This operator applies a function
-- so that everything to the left of it gets computed first and then applied -- to a given parameter. In contrast to standard function application, which
-- to everything on the right. You can use `$` (often in combination with `.`) -- has highest possible priority of 10 and is left-associative, the `$` operator
-- to get rid of a lot of parentheses: -- has priority of 0 and is right-associative. Such a low priority means that
-- the expression on its right is applied as the parameter to the function on its left.
-- before -- before
(even (fib 7)) -- true (even (fib 7)) -- false
-- after -- after
even . fib $ 7 -- true even . fib $ 7 -- false
-- equivalently -- equivalently
even $ fib 7 -- true even $ fib 7 -- false
---------------------------------------------------- ----------------------------------------------------
-- 5. Type signatures -- 5. Type signatures

View File

@ -3,6 +3,7 @@ language: haxe
filename: LearnHaxe3.hx filename: LearnHaxe3.hx
contributors: contributors:
- ["Justin Donaldson", "https://github.com/jdonaldson/"] - ["Justin Donaldson", "https://github.com/jdonaldson/"]
- ["Dan Korostelev", "https://github.com/nadako/"]
--- ---
Haxe is a web-oriented language that provides platform support for C++, C#, Haxe is a web-oriented language that provides platform support for C++, C#,
@ -34,16 +35,20 @@ references.
/* /*
This is your first actual haxe code coming up, it's declaring an empty This is your first actual haxe code coming up, it's declaring an empty
package. A package isn't necessary, but it's useful if you want to create a package. A package isn't necessary, but it's useful if you want to create a
namespace for your code (e.g. org.module.ClassName). namespace for your code (e.g. org.yourapp.ClassName).
Omitting package declaration is the same as declaring an empty package.
*/ */
package; // empty package, no namespace. package; // empty package, no namespace.
/* /*
Packages define modules for your code. Each module (e.g. org.module) must Packages are directories that contain modules. Each module is a .hx file
be lower case, and should exist as a folder structure containing the class. that contains types defined in a package. Package names (e.g. org.yourapp)
Class (and type) names must be capitalized. E.g, the class "org.module.Foo" must be lower case while module names are capitalized. A module contain one
should have the folder structure org/module/Foo.hx, as accessible from the or more types whose names are also capitalized.
compiler's working directory or class path.
E.g, the class "org.yourapp.Foo" should have the folder structure org/module/Foo.hx,
as accessible from the compiler's working directory or class path.
If you import code from other files, it must be declared before the rest of If you import code from other files, it must be declared before the rest of
the code. Haxe provides a lot of common default classes to get you started: the code. Haxe provides a lot of common default classes to get you started:
@ -53,6 +58,12 @@ import haxe.ds.ArraySort;
// you can import many classes/modules at once with "*" // you can import many classes/modules at once with "*"
import haxe.ds.*; import haxe.ds.*;
// you can import static fields
import Lambda.array;
// you can also use "*" to import all static fields
import Math.*;
/* /*
You can also import classes in a special way, enabling them to extend the You can also import classes in a special way, enabling them to extend the
functionality of other classes like a "mixin". More on 'using' later. functionality of other classes like a "mixin". More on 'using' later.
@ -172,7 +183,8 @@ class LearnHaxe3{
Regexes are also supported, but there's not enough space to go into Regexes are also supported, but there's not enough space to go into
much detail. much detail.
*/ */
trace((~/foobar/.match('foo')) + " is the value for (~/foobar/.match('foo')))"); var re = ~/foobar/;
trace(re.match('foo') + " is the value for (~/foobar/.match('foo')))");
/* /*
Arrays are zero-indexed, dynamic, and mutable. Missing values are Arrays are zero-indexed, dynamic, and mutable. Missing values are
@ -383,11 +395,7 @@ class LearnHaxe3{
*/ */
// if statements // if statements
var k = if (true){ var k = if (true) 10 else 20;
10;
} else {
20;
}
trace("K equals ", k); // outputs 10 trace("K equals ", k); // outputs 10
@ -628,6 +636,7 @@ enum ComplexEnum{
ComplexEnumEnum(c:ComplexEnum); ComplexEnumEnum(c:ComplexEnum);
} }
// Note: The enum above can include *other* enums as well, including itself! // Note: The enum above can include *other* enums as well, including itself!
// Note: This is what's called *Algebraic data type* in some other languages.
class ComplexEnumTest{ class ComplexEnumTest{
public static function example(){ public static function example(){

View File

@ -253,7 +253,9 @@ given "foo bar" {
when $_.chars > 50 { # smart matching anything with True (`$a ~~ True`) is True, when $_.chars > 50 { # smart matching anything with True (`$a ~~ True`) is True,
# so you can also put "normal" conditionals. # so you can also put "normal" conditionals.
# This when is equivalent to this `if`: # This when is equivalent to this `if`:
# if ($_.chars > 50) ~~ True {...} # if $_ ~~ ($_.chars > 50) {...}
# Which means:
# if $_.chars > 50 {...}
say "Quite a long string !"; say "Quite a long string !";
} }
default { # same as `when *` (using the Whatever Star) default { # same as `when *` (using the Whatever Star)
@ -305,37 +307,9 @@ if long-computation() -> $result {
say "The result is $result"; say "The result is $result";
} }
# Now that you've seen how to traverse a list, you need to be aware of something:
# List context (@) flattens. If you traverse nested lists, you'll actually be traversing a
# shallow list.
for 1, 2, (3, (4, ((5)))) {
say "Got $_.";
} #=> Got 1. Got 2. Got 3. Got 4. Got 5.
# ... However: (forcing item context with `$`)
for 1, 2, $(3, 4) {
say "Got $_.";
} #=> Got 1. Got 2. Got 3 4.
# Note that the last one actually joined 3 and 4.
# While `$(...)` will apply item to context to just about anything, you can also create
# an array using `[]`:
for [1, 2, 3, 4] {
say "Got $_.";
} #=> Got 1 2 3 4.
# You need to be aware of when flattening happens exactly.
# The general guideline is that argument lists flatten, but not method calls.
# Also note that `.list` and array assignment flatten (`@ary = ...`) flatten.
((1,2), 3, (4,5)).map({...}); # iterates over three elements (method call)
map {...}, ((1,2),3,(4,5)); # iterates over five elements (argument list is flattened)
(@a, @b, @c).pick(1); # picks one of three arrays (method call)
pick 1, @a, @b, @c; # flattens argument list and pick one element
### Operators ### Operators
## Since Perl languages are very much operator-based languages ## Since Perl languages are very much operator-based languages,
## Perl 6 operators are actually just funny-looking subroutines, in syntactic ## Perl 6 operators are actually just funny-looking subroutines, in syntactic
## categories, like infix:<+> (addition) or prefix:<!> (bool not). ## categories, like infix:<+> (addition) or prefix:<!> (bool not).
@ -394,17 +368,21 @@ say @array[^10]; # you can pass arrays as subscripts and it'll return
# "1 2 3 4 5 6 7 8 9 10" (and not run out of memory !) # "1 2 3 4 5 6 7 8 9 10" (and not run out of memory !)
# Note : when reading an infinite list, Perl 6 will "reify" the elements # Note : when reading an infinite list, Perl 6 will "reify" the elements
# it needs, then keep them in memory. They won't be calculated more than once. # it needs, then keep them in memory. They won't be calculated more than once.
# It also will never calculate more elements that are needed.
# Warning, though: if you try this example in the REPL and just put `1..*`, # An array subscript can also be a closure.
# Perl 6 will be forced to try and evaluate the whole array (to print it), # It'll be called with the length as the argument
# so you'll end with an infinite loop. say join(' ', @array[15..*]); #=> 15 16 17 18 19
# which is equivalent to:
say join(' ', @array[-> $n { 15..$n }]);
# You can use that in most places you'd expect, even assigning to an array # You can use that in most places you'd expect, even assigning to an array
my @numbers = ^20; my @numbers = ^20;
@numbers[5..*] = 3, 9 ... * > 90; # The right hand side could be infinite as well. my @seq = 3, 9 ... * > 95; # 3 9 15 21 27 [...] 81 87 93 99
# (but not both, as this would be an infinite loop) @numbers[5..*] = 3, 9 ... *; # even though the sequence is infinite,
say @numbers; #=> 3 9 15 21 27 [...] 81 87 # only the 15 needed values will be calculated.
say @numbers; #=> 0 1 2 3 4 3 9 15 21 [...] 81 87
# (only 20 values)
## * And, Or ## * And, Or
3 && 4; # 4, which is Truthy. Calls `.Bool` on `4` and gets `True`. 3 && 4; # 4, which is Truthy. Calls `.Bool` on `4` and gets `True`.
@ -416,7 +394,7 @@ $a && $b && $c; # Returns the first argument that evaluates to False,
$a || $b; $a || $b;
# And because you're going to want them, # And because you're going to want them,
# you also have composed assignment operators: # you also have compound assignment operators:
$a *= 2; # multiply and assignment $a *= 2; # multiply and assignment
$b %%= 5; # divisible by and assignment $b %%= 5; # divisible by and assignment
@array .= sort; # calls the `sort` method and assigns the result back @array .= sort; # calls the `sort` method and assigns the result back
@ -426,7 +404,7 @@ $b %%= 5; # divisible by and assignment
# a few more key concepts that make them better than in any other language :-). # a few more key concepts that make them better than in any other language :-).
## Unpacking ! ## Unpacking !
# It's the ability to "extract" arrays and keys. # It's the ability to "extract" arrays and keys (AKA "destructuring").
# It'll work in `my`s and in parameter lists. # It'll work in `my`s and in parameter lists.
my ($a, $b) = 1, 2; my ($a, $b) = 1, 2;
say $a; #=> 1 say $a; #=> 1
@ -560,7 +538,7 @@ subset VeryBigInteger of Int where * > 500;
multi sub sayit(Int $n) { # note the `multi` keyword here multi sub sayit(Int $n) { # note the `multi` keyword here
say "Number: $n"; say "Number: $n";
} }
multi sayit(Str $s) } # a multi is a `sub` by default multi sayit(Str $s) { # a multi is a `sub` by default
say "String: $s"; say "String: $s";
} }
sayit("foo"); # prints "String: foo" sayit("foo"); # prints "String: foo"
@ -963,7 +941,7 @@ say join ',', gather if False {
# But consider: # But consider:
constant thrice = gather for ^3 { say take $_ }; # Doesn't print anything constant thrice = gather for ^3 { say take $_ }; # Doesn't print anything
# versus: # versus:
constant thrice = eager gather for ^3 { say take $_ }; #=> 0 1 2 3 4 constant thrice = eager gather for ^3 { say take $_ }; #=> 0 1 2
# - `lazy` - Defer actual evaluation until value is fetched (forces lazy context) # - `lazy` - Defer actual evaluation until value is fetched (forces lazy context)
# Not yet implemented !! # Not yet implemented !!

View File

@ -0,0 +1,84 @@
---
language: brainfuck
contributors:
- ["Prajit Ramachandran", "http://prajitr.github.io/"]
- ["Mathias Bynens", "http://mathiasbynens.be/"]
translators:
- ["Suzane Sant Ana", "http://github.com/suuuzi"]
lang: pt-br
---
Brainfuck (em letras minúsculas, eceto no início de frases) é uma linguagem de
programação Turing-completa extremamente simples com apenas 8 comandos.
```
Qualquer caractere exceto "><+-.,[]" (sem contar as aspas) é ignorado.
Brainfuck é representado por um vetor com 30 000 células inicializadas em zero
e um ponteiro de dados que aponta para a célula atual.
Existem 8 comandos:
+ : Incrementa o vaor da célula atual em 1.
- : Decrementa o valor da célula atual em 1.
> : Move o ponteiro de dados para a célula seguinte (célula à direita).
< : Move o ponteiro de dados para a célula anterior (célula à esquerda).
. : Imprime o valor ASCII da célula atual. (ex. 65 = 'A').
, : Lê um único caractere para a célula atual.
[ : Se o valor da célula atual for zero, salta para o ] correspondente.
Caso contrário, passa para a instrução seguinte.
] : Se o valor da célula atual for zero, passa para a instrução seguinte.
Caso contrário, volta para a instrução relativa ao [ correspondente.
[ e ] formam um ciclo while. Obviamente, devem ser equilibrados.
Vamos ver alguns exemplos básicos em brainfuck:
++++++ [ > ++++++++++ < - ] > +++++ .
Este programa imprime a letra 'A'. Primeiro incrementa a célula #1 para 6.
A célula #1 será usada num ciclo. Depois é iniciado o ciclo ([) e move-se
o ponteiro de dados para a célula #2. O valor da célula #2 é incrementado 10
vezes, move-se o ponteiro de dados de volta para a célula #1, e decrementa-se
a célula #1. Este ciclo acontece 6 vezes (são necessários 6 decrementos para
a célula #1 chegar a 0, momento em que se salta para o ] correspondente,
continuando com a instrução seguinte).
Nesta altura estamos na célula #1, cujo valor é 0, enquanto a célula #2
tem o valor 60. Movemos o ponteiro de dados para a célula #2, incrementa-se 5
vezes para um valor final de 65, e então é impresso o valor da célula #2. O valor
65 corresponde ao caractere 'A' em ASCII, então 'A' é impresso no terminal.
, [ > + < - ] > .
Este programa lê um caractere e copia o seu valor para a célula #1. Um ciclo é
iniciado. Movemos o ponteiro de dados para a célula #2, incrementamos o valor na
célula #2, movemos o ponteiro de dados de volta para a célula #1 e finalmente
decrementamos o valor na célula #1. Isto continua até o valor na célula #1 ser
igual a 0 e a célula #2 ter o antigo valor da célula #1. Como o ponteiro de
dados está apontando para a célula #1 no fim do ciclo, movemos o ponteiro para a
célula #2 e imprimimos o valor em ASCII.
Os espaços servem apenas para tornar o programa mais legível. Podemos escrever
o mesmo programa da seguinte maneira:
,[>+<-]>.
Tente descobrir o que este programa faz:
,>,< [ > [ >+ >+ << -] >> [- << + >>] <<< -] >>
Este programa lê dois números e os multiplica.
Basicamente o programa pede dois caracteres ao usuário. Depois é iniciado um
ciclo exterior controlado pelo valor da célula #1. Movemos o ponteiro de dados
para a célula #2 e inicia-se o ciclo interior controlado pelo valor da célula
#2, incrementando o valor da célula #3. Porém existe um problema, no final do
ciclo interior: a célula #2 tem o valor 0. Para resolver este problema o valor da
célula #4 é também incrementado e copiado para a célula #2.
```
E isto é brainfuck. Simples, não? Por divertimento você pode escrever os
seus próprios programas em brainfuck, ou então escrever um interpretador de
brainfuck em outra linguagem. O interpretador é relativamente fácil de se
implementar, mas caso você seja masoquista, tente escrever um interpretador de
brainfuck… em brainfuck.

View File

@ -1,110 +1,119 @@
--- ---
category: tool category: tool
tool: git tool: git
lang: pt-br
filename: LearnGit.txt
contributors: contributors:
- ["Jake Prather", "http://github.com/JakeHP"] - ["Jake Prather", "http://github.com/JakeHP"]
translators: translators:
- ["Miguel Araújo", "https://github.com/miguelarauj1o"] - ["Suzane Sant Ana", "http://github.com/suuuzi"]
lang: pt-br
filename: learngit-pt.txt
--- ---
Git é um sistema de controle de versão distribuído e de gerenciamento de código-fonte. Git é um sistema distribuido de gestão para código fonte e controle de versões.
Ele faz isso através de uma série de momentos instantâneos de seu projeto, e ele funciona Funciona através de uma série de registos de estado do projeto e usa esse
com esses momentos para lhe fornecer a funcionalidade para a versão e registo para permitir funcionalidades de versionamento e gestão de código
gerenciar o seu código-fonte. fonte.
## Versionando Conceitos ## Conceitos de versionamento
### O que é controle de versão? ### O que é controle de versão
O controle de versão é um sistema que registra alterações em um arquivo ou conjunto Controle de versão (*source control*) é um processo de registo de alterações
de arquivos, ao longo do tempo. a um arquivo ou conjunto de arquivos ao longo do tempo.
### Versionamento Centralizado VS Versionamento Distribuído ### Controle de versão: Centralizado VS Distribuído
* Controle de versão centralizado concentra-se na sincronização, controle e backup de arquivos. * Controle de versão centralizado foca na sincronização, registo e *backup*
* Controle de versão distribuído concentra-se na partilha de mudanças. Toda mudança tem um ID único. de arquivos.
* Sistemas Distribuídos não têm estrutura definida. Você poderia facilmente ter um estilo SVN, * Controle de versão distribuído foca em compartilhar alterações. Cada
sistema centralizado, com git. alteração é associada a um *id* único.
* Sistemas distribuídos não tem estrutura definida. É possivel ter um sistema
centralizado ao estilo SVN usando git.
[Informação Adicional](http://git-scm.com/book/en/Getting-Started-About-Version-Control) [Informação adicional (EN)](http://git-scm.com/book/en/Getting-Started-About-Version-Control)
### Porque usar o Git? ### Por que usar git?
* Possibilidade de trabalhar offline * Permite trabalhar offline.
* Colaborar com os outros é fácil! * Colaborar com outros é fácil!
* Ramificação é fácil * Criar *branches* é fácil!
* Mesclagem é fácil * Fazer *merge* é fácil!
* Git é rápido * Git é rápido.
* Git é flexível. * Git é flexivel.
## Git - Arquitetura
## Arquitetura Git
### Repositório ### Repositório
Um conjunto de arquivos, diretórios, registros históricos, cometes, e cabeças. Imagine-o Um conjunto de arquivos, diretórios, registos históricos, *commits* e
como uma estrutura de dados de código-fonte, com o atributo que cada "elemento" do referências. Pode ser descrito como uma estrutura de dados de código fonte
código-fonte dá-lhe acesso ao seu histórico de revisão, entre outras coisas. com a particularidade de cada elemento do código fonte permitir acesso ao
histórico das suas alterações, entre outras coisas.
Um repositório git é composto do diretório git. e árvore de trabalho. Um repositório git é constituido pelo diretório .git e a *working tree*
### Diretório .git (componente do repositório) ### Diretório .git (componente do repositório)
O diretório git. contém todas as configurações, registros, galhos, cabeça(HEAD) e muito mais. O repositório .git contém todas as configurações, *logs*, *branches*,
[Lista Detalhada](http://gitready.com/advanced/2009/03/23/whats-inside-your-git-directory.html) referências e outros.
### Árvore de trabalho (componente do repositório) [Lista detalhada (EN)](http://gitready.com/advanced/2009/03/23/whats-inside-your-git-directory.html)
Esta é, basicamente, os diretórios e arquivos no seu repositório. Ele é muitas vezes referida ### *Working Tree* (componente do repositório)
como seu diretório de trabalho.
### Índice (componente do diretório .git) A *Working Tree* é basicamente a listagem dos diretórios e arquivos do repositório. É chamada também de diretório do projeto.
O Índice é a área de teste no git. É basicamente uma camada que separa a sua árvore de trabalho ### *Index* (componente do diretório .git)
a partir do repositório Git. Isso dá aos desenvolvedores mais poder sobre o que é enviado para o
repositório Git.
### Comete (commit) O *Index* é a camada da interface no git. É o elemento que separa
o diretório do projeto do repositório git. Isto permite aos programadores um
maior controle sobre o que é registado no repositório git.
A commit git é um instantâneo de um conjunto de alterações ou manipulações a sua árvore de trabalho. ### *Commit*
Por exemplo, se você adicionou 5 imagens, e removeu outros dois, estas mudanças serão contidas
em um commit (ou instantâneo). Esta confirmação pode ser empurrado para outros repositórios, ou não!
### Ramo (branch) Um *commit** de git é um registo de um cojunto de alterações ou manipulações nos arquivos do projeto.
Por exemplo, ao adicionar cinco arquivos e remover outros 2, estas alterações
serão gravadas num *commit* (ou registo). Este *commit* pode então ser enviado
para outros repositórios ou não!
Um ramo é, essencialmente, um ponteiro que aponta para o último commit que você fez. Como ### *Branch*
você se comprometer, este ponteiro irá atualizar automaticamente e apontar para o último commit.
### Cabeça (HEAD) e cabeça (head) (componente do diretório .git) Um *branch* é essencialmente uma referência que aponta para o último *commit*
efetuado. Na medida que são feitos novos commits, esta referência é atualizada
automaticamente e passa a apontar para o commit mais recente.
HEAD é um ponteiro que aponta para o ramo atual. Um repositório tem apenas 1 * ativo * HEAD. ### *HEAD* e *head* (componentes do diretório .git)
head é um ponteiro que aponta para qualquer commit. Um repositório pode ter qualquer número de commits.
### Recursos Conceituais *HEAD* é a referência que aponta para o *branch* em uso. Um repositório só tem
uma *HEAD* activa.
*head* é uma referência que aponta para qualquer *commit*. Um repositório pode
ter um número indefinido de *heads*
* [Git para Cientistas da Computação](http://eagain.net/articles/git-for-computer-scientists/) ### Recursos conceituais (EN)
* [Git para Cientistas de Computação](http://eagain.net/articles/git-for-computer-scientists/)
* [Git para Designers](http://hoth.entp.com/output/git_for_designers.html) * [Git para Designers](http://hoth.entp.com/output/git_for_designers.html)
## Comandos ## Comandos
### init ### *init*
Criar um repositório Git vazio. As configurações do repositório Git, informações armazenadas, Cria um repositório Git vazio. As definições, informação guardada e outros do
e mais são armazenados em um diretório (pasta) com o nome ". git". repositório git são guardados em uma pasta chamada ".git".
```bash ```bash
$ git init $ git init
``` ```
### config ### *config*
Para configurar as definições. Quer seja para o repositório, o próprio sistema, ou Permite configurar as definições, sejam as definições do repositório, sistema
configurações globais. ou configurações globais.
```bash ```bash
# Impressão e definir algumas variáveis de configuração básica (global) # Imprime e define algumas variáveis de configuração básicas (global)
$ git config --global user.email $ git config --global user.email
$ git config --global user.name $ git config --global user.name
@ -112,22 +121,21 @@ $ git config --global user.email "MyEmail@Zoho.com"
$ git config --global user.name "My Name" $ git config --global user.name "My Name"
``` ```
[Saiba mais sobre o git config.](http://git-scm.com/docs/git-config) [Aprenda mais sobre git config. (EN)](http://git-scm.com/docs/git-config)
### help ### help
Para lhe dar um acesso rápido a um guia extremamente detalhada de cada comando. ou Para visualizar rapidamente o detalhamento de cada comando ou apenas lembrar da semântica.
apenas dar-lhe um rápido lembrete de algumas semânticas.
```bash ```bash
# Rapidamente verificar os comandos disponíveis # Ver rapidamente os comandos disponiveis
$ git help $ git help
# Confira todos os comandos disponíveis # Ver todos os comandos disponiveis
$ git help -a $ git help -a
# Ajuda específica de comando - manual do usuário # Usar o *help* para um comando especifico
# git help <command_here> # git help <comando_aqui>
$ git help add $ git help add
$ git help commit $ git help commit
$ git help init $ git help init
@ -135,85 +143,89 @@ $ git help init
### status ### status
Para mostrar as diferenças entre o arquivo de índice (basicamente o trabalho de Apresenta as diferenças entre o arquivo *index* (a versão corrente
copiar/repo) e a HEAD commit corrente. do repositório) e o *commit* da *HEAD* atual.
```bash ```bash
# Irá exibir o ramo, os arquivos não monitorados, as alterações e outras diferenças # Apresenta o *branch*, arquivos não monitorados, alterações e outras
# difereças
$ git status $ git status
# Para saber outras "tid bits" sobre git status # Para aprender mais detalhes sobre git *status*
$ git help status $ git help status
``` ```
### add ### add
Para adicionar arquivos para a atual árvore/directory/repo trabalho. Se você não Adiciona arquivos ao repositório corrente. Se os arquivos novos não forem
der `git add` nos novos arquivos para o trabalhando árvore/diretório, eles não serão adicionados através de `git add` ao repositório, então eles não serão
incluídos em commits! incluidos nos commits!
```bash ```bash
# Adicionar um arquivo no seu diretório de trabalho atual # adiciona um arquivo no diretório do projeto atual
$ git add HelloWorld.java $ git add HelloWorld.java
# Adicionar um arquivo em um diretório aninhado # adiciona um arquivo num sub-diretório
$ git add /path/to/file/HelloWorld.c $ git add /path/to/file/HelloWorld.c
# Suporte a expressões regulares! # permite usar expressões regulares!
$ git add ./*.java $ git add ./*.java
``` ```
### branch ### branch
Gerenciar seus ramos. Você pode visualizar, editar, criar, apagar ramos usando este comando. Gerencia os *branches*. É possível ver, editar, criar e apagar branches com este
comando.
```bash ```bash
# Lista ramos e controles remotos existentes # listar *branches* existentes e remotos
$ git branch -a $ git branch -a
# Criar um novo ramo # criar um novo *branch*
$ git branch myNewBranch $ git branch myNewBranch
# Apagar um ramo # apagar um *branch*
$ git branch -d myBranch $ git branch -d myBranch
# Renomear um ramo # alterar o nome de um *branch*
# git branch -m <oldname> <newname> # git branch -m <oldname> <newname>
$ git branch -m myBranchName myNewBranchName $ git branch -m myBranchName myNewBranchName
# Editar a descrição de um ramo # editar a descrição de um *branch*
$ git branch myBranchName --edit-description $ git branch myBranchName --edit-description
``` ```
### checkout ### checkout
Atualiza todos os arquivos na árvore de trabalho para corresponder à versão no Atualiza todos os arquivos no diretório do projeto para que fiquem iguais
índice, ou árvore especificada. à versão do index ou do *branch* especificado.
```bash ```bash
# Finalizar um repo - padrão de ramo mestre # Checkout de um repositório - por padrão para o branch master
$ git checkout $ git checkout
# Checa um ramo especificado # Checkout de um branch especifico
$ git checkout branchName $ git checkout branchName
# Criar um novo ramo e mudar para ela, como: "<nome> git branch; git checkout <nome>" # Cria um novo branch e faz checkout para ele.
# Equivalente a: "git branch <name>; git checkout <name>"
$ git checkout -b newBranch $ git checkout -b newBranch
``` ```
### clone ### clone
Clones, ou cópias, de um repositório existente para um novo diretório. Ele também adiciona Clona ou copia um repositório existente para um novo diretório. Também
filiais remotas de rastreamento para cada ramo no repo clonado, que permite que você empurre adiciona *branches* de monitoramento remoto para cada *branch* no repositório
a um ramo remoto. clonado o que permite enviar alterações para um *branch* remoto.
```bash ```bash
# Clone learnxinyminutes-docs # Clona learnxinyminutes-docs
$ git clone https://github.com/adambard/learnxinyminutes-docs.git $ git clone https://github.com/adambard/learnxinyminutes-docs.git
``` ```
### commit ### commit
Armazena o conteúdo atual do índice em um novo "commit". Este commit contém Guarda o conteudo atual do index num novo *commit*. Este *commit* contém
as alterações feitas e uma mensagem criada pelo utilizador. as alterações feitas e a mensagem criada pelo usuário.
```bash ```bash
# commit com uma mensagem # commit com uma mensagem
@ -222,170 +234,170 @@ $ git commit -m "Added multiplyNumbers() function to HelloWorld.c"
### diff ### diff
Mostra as diferenças entre um arquivo no diretório, o índice de trabalho e commits. Apresenta as diferenças entre um arquivo no repositório do projeto, *index*
e *commits*
```bash ```bash
# Mostrar diferença entre o seu diretório de trabalho e o índice. # Apresenta a diferença entre o diretório atual e o index
$ git diff $ git diff
# Mostrar diferenças entre o índice e o commit mais recente. # Apresenta a diferença entre o index e os commits mais recentes
$ git diff --cached $ git diff --cached
# Mostrar diferenças entre o seu diretório de trabalho e o commit mais recente. # Apresenta a diferença entre o diretório atual e o commit mais recente
$ git diff HEAD $ git diff HEAD
``` ```
### grep ### grep
Permite procurar rapidamente um repositório. Permite procurar facilmente num repositório
Configurações opcionais: Configurações opcionais:
```bash ```bash
# Obrigado ao Travis Jeffery por isto # Define a apresentação de números de linha nos resultados do grep
# Configure os números de linha a serem mostrados nos resultados de busca grep
$ git config --global grep.lineNumber true $ git config --global grep.lineNumber true
# Fazer resultados de pesquisa mais legível, incluindo agrupamento # Agrupa os resultados da pesquisa para facilitar a leitura
$ git config --global alias.g "grep --break --heading --line-number" $ git config --global alias.g "grep --break --heading --line-number"
``` ```
```bash ```bash
# Procure por "variableName" em todos os arquivos java # Pesquisa por "variableName" em todos os arquivos java
$ git grep 'variableName' -- '*.java' $ git grep 'variableName' -- '*.java'
# Procure por uma linha que contém "arrayListName" e "adicionar" ou "remover" # Pesquisa por uma linha que contém "arrayListName" e "add" ou "remove"
$ git grep -e 'arrayListName' --and \( -e add -e remove \) $ git grep -e 'arrayListName' --and \( -e add -e remove \)
``` ```
Google é seu amigo; para mais exemplos O Google é seu amigo; para mais exemplos:
[Git Grep Ninja](http://travisjeffery.com/b/2012/02/search-a-git-repo-like-a-ninja) [Git Grep Ninja (EN)](http://travisjeffery.com/b/2012/02/search-a-git-repo-like-a-ninja)
### log ### log
Mostrar commits para o repositório. Apresenta commits do repositório.
```bash ```bash
# Mostrar todos os commits # Apresenta todos os commits
$ git log $ git log
# Mostrar um número X de commits # Apresenta X commits
$ git log -n 10 $ git log -n 10
# Mostrar somente commits mesclados # Apresenta apenas commits de merge
$ git log --merges $ git log --merges
``` ```
### merge ### merge
"Merge" em mudanças de commits externos no branch atual. "Merge" junta as alterações de commits externos com o *branch* atual.
```bash ```bash
# Mesclar o ramo especificado para o atual. # Junta o branch especificado com o atual
$ git merge branchName $ git merge branchName
# Gera sempre uma mesclagem commit ao mesclar # Para gerar sempre um commit ao juntar os branches
$ git merge --no-ff branchName $ git merge --no-ff branchName
``` ```
### mv ### mv
Renomear ou mover um arquivo Alterar o nome ou mover um arquivo.
```bash ```bash
# Renomear um arquivo # Alterar o nome de um arquivo
$ git mv HelloWorld.c HelloNewWorld.c $ git mv HelloWorld.c HelloNewWorld.c
# Mover um arquivo # Mover um arquivo
$ git mv HelloWorld.c ./new/path/HelloWorld.c $ git mv HelloWorld.c ./new/path/HelloWorld.c
# Força renomear ou mover # Forçar a alteração de nome ou mudança local
# "ExistingFile" já existe no diretório, será substituído # "existingFile" já existe no directório, será sobrescrito.
$ git mv -f myFile existingFile $ git mv -f myFile existingFile
``` ```
### pull ### pull
Puxa de um repositório e se funde com outro ramo. Puxa alterações de um repositório e as junta com outro branch
```bash ```bash
# Atualize seu repo local, através da fusão de novas mudanças # Atualiza o repositório local, juntando as novas alterações
# A partir da "origem" remoto e ramo "master (mestre)". # do repositório remoto 'origin' e branch 'master'
# git pull <remote> <branch> # git pull <remote> <branch>
# git pull => implícito por padrão => git pull origin master # git pull => aplica a predefinição => git pull origin master
$ git pull origin master $ git pull origin master
# Mesclar em mudanças de ramo remoto e rebase # Juntar alterações do branch remote e fazer rebase commits do branch
# Ramo commita em seu repo local, como: "git pull <remote> <branch>, git rebase <branch>" # no repositório local, como: "git pull <remote> <branch>, git rebase <branch>"
$ git pull origin master --rebase $ git pull origin master --rebase
``` ```
### push ### push
Empurre e mesclar as alterações de uma ramificação para uma remota e ramo. Enviar e juntar alterações de um branch para o seu branch correspondente
num repositório remoto.
```bash ```bash
# Pressione e mesclar as alterações de um repo local para um # Envia e junta as alterações de um repositório local
# Chamado remoto "origem" e ramo de "mestre". # para um remoto denominado "origin" no branch "master".
# git push <remote> <branch> # git push <remote> <branch>
# git push => implícito por padrão => git push origin master # git push => aplica a predefinição => git push origin master
$ git push origin master $ git push origin master
# Para ligar atual filial local com uma filial remota, bandeira add-u:
$ git push -u origin master
# Agora, a qualquer hora que você quer empurrar a partir desse mesmo ramo local, uso de atalho:
$ git push
``` ```
### rebase (CAUTELA) ### rebase (cautela!)
Tire todas as alterações que foram commitadas em um ramo, e reproduzi-las em outro ramo. Pega em todas as alterações que foram registadas num branch e volta a
* Não rebase commits que você tenha empurrado a um repo público *. aplicá-las em outro branch.
*Não deve ser feito rebase de commits que foram enviados para um repositório
público*
```bash ```bash
# Rebase experimentBranch para mestre # Faz Rebase de experimentBranch para master
# git rebase <basebranch> <topicbranch> # git rebase <basebranch> <topicbranch>
$ git rebase master experimentBranch $ git rebase master experimentBranch
``` ```
[Leitura Adicional.](http://git-scm.com/book/en/Git-Branching-Rebasing) [Leitura adicional (EN).](http://git-scm.com/book/en/Git-Branching-Rebasing)
### reset (CAUTELA) ### reset (cuidado!)
Repor o atual HEAD de estado especificado. Isto permite-lhe desfazer fusões (merge), Restabelece a HEAD atual ao estado definido. Isto permite reverter *merges*,
puxa (push), commits, acrescenta (add), e muito mais. É um grande comando, mas também *pulls*, *commits*, *adds* e outros. É um comando muito poderoso mas também
perigoso se não saber o que se está fazendo. perigoso quando não há certeza do que se está fazendo.
```bash ```bash
# Repor a área de teste, para coincidir com o último commit (deixa diretório inalterado) # Restabelece a camada intermediária de registo para o último
# commit (o directório fica sem alterações)
$ git reset $ git reset
# Repor a área de teste, para coincidir com o último commit, e substituir diretório trabalhado # Restabelece a camada intermediária de registo para o último commit, e
# sobrescreve o projeto atual
$ git reset --hard $ git reset --hard
# Move a ponta ramo atual para o especificado commit (deixa diretório inalterado) # Move a head do branch atual para o commit especificado, sem alterar o projeto.
# Todas as alterações ainda existem no diretório. # todas as alterações ainda existem no projeto
$ git reset 31f2bb1 $ git reset 31f2bb1
# Move a ponta ramo atual para trás, para o commit especificado # Inverte a head do branch atual para o commit especificado
# E faz o jogo dir trabalho (exclui mudanças não commitadas e todos os commits # fazendo com que este esteja em sintonia com o diretório do projeto
# Após o commit especificado). # Remove alterações não registadas e todos os commits após o commit especificado
$ git reset --hard 31f2bb1 $ git reset --hard 31f2bb1
``` ```
### rm ### rm
O oposto do git add, git rm remove arquivos da atual árvore de trabalho. O oposto de git add, git rm remove arquivos do branch atual.
```bash ```bash
# remove HelloWorld.c # remove HelloWorld.c
$ git rm HelloWorld.c $ git rm HelloWorld.c
# Remove um arquivo de um diretório aninhado # Remove um arquivo de um sub-directório
$ git rm /pather/to/the/file/HelloWorld.c $ git rm /pather/to/the/file/HelloWorld.c
``` ```
# # Mais informações ## Informação complementar (EN)
* [tryGit - A fun interactive way to learn Git.](http://try.github.io/levels/1/challenges/1) * [tryGit - A fun interactive way to learn Git.](http://try.github.io/levels/1/challenges/1)
@ -398,5 +410,3 @@ $ git rm /pather/to/the/file/HelloWorld.c
* [SalesForce Cheat Sheet](https://na1.salesforce.com/help/doc/en/salesforce_git_developer_cheatsheet.pdf) * [SalesForce Cheat Sheet](https://na1.salesforce.com/help/doc/en/salesforce_git_developer_cheatsheet.pdf)
* [GitGuys](http://www.gitguys.com/) * [GitGuys](http://www.gitguys.com/)
* [Git - guia prático](http://rogerdudler.github.io/git-guide/index.pt_BR.html)

View File

@ -74,8 +74,7 @@ maior controlo sobre o que é registado no repositório git.
### *Commit* ### *Commit*
Um *commit** de git é um registo de um cojunto de alterações ou manipulações Um *commit** de git é um registo de um cojunto de alterações ou manipulações nos ficheiros do projecto.
no nos ficheiros do projecto.
Por exemplo, ao adicionar cinco ficheiros e remover outros 2, estas alterações Por exemplo, ao adicionar cinco ficheiros e remover outros 2, estas alterações
serão gravadas num *commit* (ou registo). Este *commit* pode então ser enviado serão gravadas num *commit* (ou registo). Este *commit* pode então ser enviado
para outros repositórios ou não! para outros repositórios ou não!
@ -83,7 +82,7 @@ para outros repositórios ou não!
### *Branch* ### *Branch*
Um *branch* é essencialmente uma referência que aponta para o último *commit* Um *branch* é essencialmente uma referência que aponta para o último *commit*
efetuado. à medida que são feitos novos commits, esta referência é atualizada efetuado. À medida que são feitos novos commits, esta referência é atualizada
automaticamente e passa a apontar para o commit mais recente. automaticamente e passa a apontar para o commit mais recente.
### *HEAD* e *head* (componentes do directório .git) ### *HEAD* e *head* (componentes do directório .git)
@ -115,7 +114,7 @@ Permite configurar as definições, sejam as definições do repositório, siste
ou configurações globais. ou configurações globais.
```bash ```bash
# Imprime & Define Algumas Variáveis de Configuração Básicas (Global) # Imprime e define algumas variáveis de configuração básicas (global)
$ git config --global user.email $ git config --global user.email
$ git config --global user.name $ git config --global user.name
@ -123,7 +122,7 @@ $ git config --global user.email "MyEmail@Zoho.com"
$ git config --global user.name "My Name" $ git config --global user.name "My Name"
``` ```
[Aprenda Mais Sobre git config. (EN)](http://git-scm.com/docs/git-config) [Aprenda mais sobre git config. (EN)](http://git-scm.com/docs/git-config)
### help ### help
@ -166,7 +165,7 @@ adicionados através de `git add` ao repositório, então eles não serão
incluidos nos commits! incluidos nos commits!
```bash ```bash
# adiciona um ficheiro no directório do project atual # adiciona um ficheiro no directório do projecto atual
$ git add HelloWorld.java $ git add HelloWorld.java
# adiciona um ficheiro num sub-directório # adiciona um ficheiro num sub-directório
@ -371,7 +370,7 @@ Restabelece a HEAD atual ao estado definido. Isto permite reverter *merges*,
perigoso se não há certeza quanto ao que se está a fazer. perigoso se não há certeza quanto ao que se está a fazer.
```bash ```bash
# Restabelece a camada intermediária dr registo para o último # Restabelece a camada intermediária de registo para o último
# commit (o directório fica sem alterações) # commit (o directório fica sem alterações)
$ git reset $ git reset

View File

@ -14,7 +14,7 @@ executable pseudocode.
Feedback would be highly appreciated! You can reach me at [@louiedinh](http://twitter.com/louiedinh) or louiedinh [at] [google's email service] Feedback would be highly appreciated! You can reach me at [@louiedinh](http://twitter.com/louiedinh) or louiedinh [at] [google's email service]
Note: This article applies to Python 2.7 specifically, but should be applicable Note: This article applies to Python 2.7 specifically, but should be applicable
to Python 2.x. For Python 3.x, take a look at the Python 3 tutorial. to Python 2.x. For Python 3.x, take a look at the [Python 3 tutorial](http://learnxinyminutes.com/docs/python3/).
```python ```python

View File

@ -13,7 +13,7 @@ executable pseudocode.
Feedback would be highly appreciated! You can reach me at [@louiedinh](http://twitter.com/louiedinh) or louiedinh [at] [google's email service] Feedback would be highly appreciated! You can reach me at [@louiedinh](http://twitter.com/louiedinh) or louiedinh [at] [google's email service]
Note: This article applies to Python 3 specifically. Check out the other tutorial if you want to learn the old Python 2.7 Note: This article applies to Python 3 specifically. Check out [here](http://learnxinyminutes.com/docs/python/) if you want to learn the old Python 2.7
```python ```python
@ -276,7 +276,7 @@ empty_set = set()
# Initialize a set with a bunch of values. Yeah, it looks a bit like a dict. Sorry. # Initialize a set with a bunch of values. Yeah, it looks a bit like a dict. Sorry.
some_set = {1, 1, 2, 2, 3, 4} # some_set is now {1, 2, 3, 4} some_set = {1, 1, 2, 2, 3, 4} # some_set is now {1, 2, 3, 4}
#Can set new variables to a set # Can set new variables to a set
filled_set = some_set filled_set = some_set
# Add one more item to the set # Add one more item to the set
@ -394,7 +394,6 @@ our_iterator.__next__() # Raises StopIteration
list(filled_dict.keys()) #=> Returns ["one", "two", "three"] list(filled_dict.keys()) #=> Returns ["one", "two", "three"]
#################################################### ####################################################
## 4. Functions ## 4. Functions
#################################################### ####################################################
@ -410,7 +409,6 @@ add(5, 6) # => prints out "x is 5 and y is 6" and returns 11
# Another way to call functions is with keyword arguments # Another way to call functions is with keyword arguments
add(y=6, x=5) # Keyword arguments can arrive in any order. add(y=6, x=5) # Keyword arguments can arrive in any order.
# You can define functions that take a variable number of # You can define functions that take a variable number of
# positional arguments # positional arguments
def varargs(*args): def varargs(*args):
@ -418,7 +416,6 @@ def varargs(*args):
varargs(1, 2, 3) # => (1, 2, 3) varargs(1, 2, 3) # => (1, 2, 3)
# You can define functions that take a variable number of # You can define functions that take a variable number of
# keyword arguments, as well # keyword arguments, as well
def keyword_args(**kwargs): def keyword_args(**kwargs):
@ -501,7 +498,9 @@ class Human(object):
# Basic initializer, this is called when this class is instantiated. # Basic initializer, this is called when this class is instantiated.
# Note that the double leading and trailing underscores denote objects # Note that the double leading and trailing underscores denote objects
# or attributes that are used by python but that live in user-controlled # or attributes that are used by python but that live in user-controlled
# namespaces. You should not invent such names on your own. # namespaces. Methods(or objects or attributes) like: __init__, __str__,
# __repr__ etc. are called magic methods (or sometimes called dunder methods)
# You should not invent such names on your own.
def __init__(self, name): def __init__(self, name):
# Assign the argument to the instance's name attribute # Assign the argument to the instance's name attribute
self.name = name self.name = name
@ -636,6 +635,7 @@ print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :(
* [The Official Docs](http://docs.python.org/3/) * [The Official Docs](http://docs.python.org/3/)
* [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/) * [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/)
* [A Crash Course in Python for Scientists](http://nbviewer.ipython.org/5920182) * [A Crash Course in Python for Scientists](http://nbviewer.ipython.org/5920182)
* [Python Course](http://www.python-course.eu/index.php)
### Dead Tree ### Dead Tree

View File

@ -22,8 +22,8 @@ Google Chrome, становится все более популярной.
```js ```js
// Си-подобные комментарии. Однострочные комментарии начинаются с двух символов слэш, // Си-подобные комментарии. Однострочные комментарии начинаются с двух символов слэш,
/* а многострочные комментарии начинаются с звёздочка-слэш /* а многострочные комментарии начинаются с последовательности слэш-звёздочка
и заканчиваются символами слэш-звёздочка */ и заканчиваются символами звёздочка-слэш */
// Инструкции могут заканчиваться точкой с запятой ; // Инструкции могут заканчиваться точкой с запятой ;
doStuff(); doStuff();

View File

@ -593,7 +593,7 @@ def double_numbers(iterable):
range_ = range(1, 900000000) range_ = range(1, 900000000)
# Будет удваивать все числа, пока результат не превысит 30 # Будет удваивать все числа, пока результат не превысит 30
for i in double_numbers(xrange_): for i in double_numbers(range_):
print(i) print(i)
if i >= 30: if i >= 30:
break break

View File

@ -11,6 +11,7 @@ contributors:
- ["Ariel Krakowski", "http://www.learneroo.com"] - ["Ariel Krakowski", "http://www.learneroo.com"]
- ["Dzianis Dashkevich", "https://github.com/dskecse"] - ["Dzianis Dashkevich", "https://github.com/dskecse"]
- ["Levi Bostian", "https://github.com/levibostian"] - ["Levi Bostian", "https://github.com/levibostian"]
- ["Rahil Momin", "https://github.com/iamrahil"]
--- ---
@ -169,6 +170,9 @@ array[1..3] #=> [2, 3, 4]
# Add to an array like this # Add to an array like this
array << 6 #=> [1, 2, 3, 4, 5, 6] array << 6 #=> [1, 2, 3, 4, 5, 6]
# Check if an item exists in an array
array.include?(1) #=> true
# Hashes are Ruby's primary dictionary with keys/value pairs. # Hashes are Ruby's primary dictionary with keys/value pairs.
# Hashes are denoted with curly braces: # Hashes are denoted with curly braces:
hash = { 'color' => 'green', 'number' => 5 } hash = { 'color' => 'green', 'number' => 5 }
@ -188,6 +192,10 @@ new_hash = { defcon: 3, action: true }
new_hash.keys #=> [:defcon, :action] new_hash.keys #=> [:defcon, :action]
# Check existence of keys and values in hash
new_hash.has_key?(:defcon) #=> true
new_hash.has_value?(3) #=> true
# Tip: Both Arrays and Hashes are Enumerable # Tip: Both Arrays and Hashes are Enumerable
# They share a lot of useful methods such as each, map, count, and more # They share a lot of useful methods such as each, map, count, and more

View File

@ -186,7 +186,7 @@ val sq: Int => Int = x => x * x
// Anonymous functions can be called as usual: // Anonymous functions can be called as usual:
sq(10) // => 100 sq(10) // => 100
// If your anonymous function has one or two arguments, and each argument is // If each argument in your anonymous function is
// used only once, Scala gives you an even shorter way to define them. These // used only once, Scala gives you an even shorter way to define them. These
// anonymous functions turn out to be extremely common, as will be obvious in // anonymous functions turn out to be extremely common, as will be obvious in
// the data structure section. // the data structure section.
@ -465,6 +465,7 @@ val patternFunc: Person => String = {
// Scala allows methods and functions to return, or take as parameters, other // Scala allows methods and functions to return, or take as parameters, other
// functions or methods. // functions or methods.
val add10: Int => Int = _ + 10 // A function taking an Int and returning an Int
List(1, 2, 3) map add10 // List(11, 12, 13) - add10 is applied to each element List(1, 2, 3) map add10 // List(11, 12, 13) - add10 is applied to each element
// Anonymous functions can be used instead of named functions: // Anonymous functions can be used instead of named functions:

View File

@ -0,0 +1,251 @@
---
language: markdown
contributors:
- ["Dan Turkel", "http://danturkel.com/"]
translators:
- ["Eray AYDIN", "http://erayaydin.me/"]
lang: tr-tr
filename: markdown-tr.md
---
Markdown, 2004 yılında John Gruber tarafından oluşturuldu. Asıl amacı kolay okuma ve yazmayı sağlamakla beraber kolayca HTML (artık bir çok diğer formatlara) dönüşüm sağlamaktır.
```markdown
<!-- Markdown, HTML'i kapsar, yani her HTML dosyası geçerli bir Markdown dosyasıdır, bu demektir
ki Markdown içerisinde HTML etiketleri kullanabiliriz, örneğin bu yorum elementi, ve
markdown işleyicisinde etki etmezler. Fakat, markdown dosyası içerisinde HTML elementi oluşturursanız,
bu elementin içeriğinde markdown söz dizimlerini kullanamazsınız. -->
<!-- Markdown ayrıca işleyiciden işleyiciye farklılık gösterebilir. Bu rehberde
evrensel özelliklere uygun anlatımlar olacaktır. Bir çok işleyici bu rehberdeki
anlatımları destekler -->
<!-- Başlıklar -->
<!-- Kolayca <h1>'den <h6>'ya HTML etiketleri oluşturabilirsiniz.
Kare (#) sayısı bu elementin numarasını belirleyecek ve devamında getirdiğiniz
yazı bu elementin içeriği olacaktır
-->
# Bu bir <h1>
## Bu bir <h2>
### Bu bir <h3>
#### Bu bir <h4>
##### Bu bir <h5>
###### Bu bir <h6>
<!-- Markdown ayrıca h1 ve h2 için 2 alternatif yol daha taşır -->
Bu bir h1
=========
Bu bir h2
---------
<!-- Basit yazı stilleri -->
<!-- Markdown ile yazılar kolayca italik ve kalın belirtilebilir -->
*Bu yazı italik.*
_Bu yazı da italik._
**Bu yazı kalın.**
__Bu yazı da kalın.__
***Bu yazı hem kalın hem italik.***
**_Bu da öyle!_**
*__Hatta bu bile!__*
<!-- Github Flavored Markdown'da ayrıca üstü çizgili karakter de desteklenir: -->
~~Bu yazı üstü çizili olarak gözükecek.~~
<!-- Paragraflar bir veya daha fazla boş satırla ayrılır. -->
Bu bir paragraf. Paragrafın içeriğine devam ediyorum, eğlenceli değil mi?
Şimdi 2. paragrafıma geçtim.
Hala 2. paragraftayım, çünkü boş bir satır bırakmadım.
Bu da 3. paragrafım!
<!-- HTML'de her satır için <br /> etiketi kullanmak ister misiniz, Bir
paragrafı bitirdikten sonra 2 veya daha fazla boşluk bırakın ve yeni paragrafa
başlayın, bu bir <br /> etiketi sayılacaktır -->
Bu yazının sonunda 2 boşluk var (bu satırı seçerek kontrol edebilirsiniz).
Bir üst satırda <br /> etiketi var!
<!-- Blok yazılarının yapımı oldukça kolay, (>) karakteri ile yapabilirsiniz -->
> Bu bir blok etiketi. Satırlara ayırmak için
> her satırın başında `>` karakter yerleştirmeli veya tek satırda bütün içeriği yazabilirsiniz.
> Satır `>` karakteri ile başladığı sürece sorun yok.
> Ayrıca alt alta da blok elementi açabilirsiniz
>> iç içe yani
> düzgün değil mi ?
<!-- Listeler -->
<!-- Numarasız listeler için yıldız, artı, veya tire kullanabilirsiniz -->
* Nesne
* Nesne
* Bir başka nesne
veya
+ Nesne
+ Nesne
+ Bir başka nesne
veya
- Nesne
- Nesne
- Son bir nesne
<!-- Numaralı liste için başına sıralı bir şekilde sayı eklemeniz yeterli -->
1. İlk nesne
2. İkinci nesne
3. Üçüncü nesne
<!-- İsterseniz sıralı bir şekilde yazmak zorunda değilsiniz, markdown
biçimlendirirken sizin için sıralayacaktır, fakat bunu önermiyorum. Markdown dosyasının
düzgün gözükmesi için önerilen metodu uygulamanızı tavsiye ederim -->
1. İlk nesne
1. İkinci nesne
1. Üçüncü nesne
<!-- (Bunun çıktısı ile, sıralı olarak yazdığımız örneğin çıktısı aynı olacaktır) -->
<!-- Ayrıca alt alta liste oluşturabilirsiniz -->
1. İlk nesne
2. İkinci nesne
3. Üçüncü nesne
* Alt nesne
* Alt nesne
4. Dördüncü nesne
<!-- Ayrıca görev listeleri de bulunmakta. HTML seçim kutusu(checkbox) oluşturacaktır. -->
Kutunun içerisinde `x` yoksa eğer seçim kutusu boş olacaktır.
- [ ] Yapılacak ilk görev.
- [ ] Yapılması gereken bir başka görev
Aşağıdaki seçim kutusu ise içi dolu olacaktır.
- [x] Bu görev başarıyla yapıldı
<!-- Kod blokları -->
<!-- Kod bloklarını(<code> elementi) belirtmek için 4 adet boşluk veya bir
tab karakterini kullanabilirsiniz -->
Bu bir kod
öyle mi?
<!-- Ayrıca kod içerisinde girinti kullanmak istiyorsanız tekrar `tab` veya `4 boşluk`
kullanabilirsiniz -->
my_array.each do |item|
puts item
end
<!-- Yazı içerisinde kod belirtmek için sorgu tırnağı (`) kullanabilirsiniz -->
Ahmet `go_to()` fonksiyonun ne yaptığını bilmiyor!
<!-- Github Flavored Markdown'da, kod içerisinde aydınlatma kullanabilirsiniz -->
\`\`\`ruby <!-- buradaki ters slaş (\) işaretlerini kullanmayın, sadece ```ruby ! -->
def foobar
puts "Hello world!"
end
\`\`\` <!-- burada da (\) işaretlerini kullanmayın, sadece ``` -->
<!-- Yukarıdaki örnekte girinti kullanmanıza gerek yok, Github da
``` işaretinden sonra belirttiğiniz yazılım diline göre gerekli
syntax aydınlatmaları uygulanacaktır -->
<!-- Düz çizgi (<hr />) -->
<!-- Düz çizgiler 3 veya daha fazla yıldız/çizgi ile yapılabilir. Boşluklar önemsiz. -->
***
---
- - -
****************
<!-- Linkler -->
<!-- Markdown'daki en güzel şeylerden biri kolayca link oluşturmaktır.
Linkte göstermek istediğiniz yazıyı [] içerisine yerleştirin ve sonuna parantezler içerisinde ()
gideceği adresi belirtin -->
[Bana tıkla!](http://test.com)
<!-- Ayrıca linke `title` özelliği eklemek için tırnakları kullanabilirsiniz -->
[Bana tıkla!](http://test.com "Test.com'a gider")
<!-- Bağıl yollar da çalışıyor. -->
[Müzik dinle](/muzik/).
<!-- Markdown ayrıca referans linklerini de destekler -->
[Bu linke tıklayarak][link1] daha detaylı bilgi alabilirsiniz!
[Ayrıca bu linki de inceleyin][foobar] tabi istiyorsanız.
[link1]: http://test.com/ "harika!"
[foobar]: http://foobar.biz/ "okey!"
<!--Başlık ayrıca tek tırnak veya parantez içinde olabilir, veya direk yazılabilir.
Referans döküman içerisindeki herhangi bir yer olabilir ve referans IDsi
benzersiz olduğu sürece sorunsuz çalışacaktır. -->
<!-- Ayrıca "dolaylı adlandırma" bulunmaktadır, "dolaylı adlandırma", linkin yazısının
aynı zamanda onun idsi olmasıdır -->
[Bu][] bir link.
[bu]: http://bubirlink.com
<!-- Fakat bu çok tercih edilen bir yöntem değil. -->
<!-- Resimler -->
<!-- Resimler aslında linklere çok benziyor fakat başında ünlem bulunuyor! -->
![Bu alt etiketine gelecek içerik](http://imgur.com/resmim.jpg "Bu da isteğe bağlı olan bir başlık")
<!-- Referanslar resimler için de geçerli -->
![Bu alt etiketi.][resmim]
[resmim]: bagil/linkler/de/calisiyor.jpg "Başlık isterseniz buraya girebilirsiniz"
<!-- Çeşitli -->
<!-- Oto-linkler -->
<http://testwebsite.com/> ile
[http://testwebsite.com/](http://testwebsite.com) aynı şeyler
<!-- Oto-linkler epostaları da destekler -->
<foo@bar.com>
<!-- Kaçış karakterleri -->
Bu yazının *yıldızlar arasında gözükmesini* istiyorum fakat italik olmamasını istiyorum,
bunun için, şu şekilde: \*bu yazı italik değil, yıldızlar arasında\*.
<!-- Tablolar -->
<!-- Tablolar sadece Github Flavored Markdown'da destekleniyor ve açıkçası
performansı çok yoruyorlar, fakat illa ki kullanmak isterseniz: -->
| Sütun1 | Sütun 2 | Sütün 3 |
| :----------- | :------: | ------------: |
| Sola dayalı | Ortalı | Sağa dayalı |
| test | test | test |
<!-- ayrıca, bunun aynısı -->
Sütun 1 | Sütun 2 | Sütun 3
:-- | :-: | --:
Çok çirkin göözüküyor | değil | mi?
<!-- Bitiş! -->
```
Daha detaylı bilgi için, John Gruber'in resmi söz dizimi yazısını [buradan](http://daringfireball.net/projects/markdown/syntax) veya Adam Pritchard'ın mükemmel hatırlatma kağıdını [buradan](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) inceleyebilirsiniz.

View File

@ -0,0 +1,635 @@
---
language: python3
contributors:
- ["Louie Dinh", "http://pythonpracticeprojects.com"]
- ["Steven Basart", "http://github.com/xksteven"]
- ["Andre Polykanine", "https://github.com/Oire"]
- ["Andre Polykanine", "https://github.com/Oire"]
translators:
- ["Eray AYDIN", "http://erayaydin.me/"]
lang: tr-tr
filename: learnpython3-tr.py
---
Python,90ların başlarında Guido Van Rossum tarafından oluşturulmuştur. En popüler olan dillerden biridir. Beni Python'a aşık eden sebep onun syntax beraklığı. Çok basit bir çalıştırılabilir söz koddur.
Not: Bu makale Python 3 içindir. Eğer Python 2.7 öğrenmek istiyorsanız [burayı](http://learnxinyminutes.com/docs/python/) kontrol edebilirsiniz.
```python
# Tek satırlık yorum satırı kare(#) işareti ile başlamaktadır.
""" Çok satırlı olmasını istediğiniz yorumlar
üç adet tırnak(") işareti ile
yapılmaktadır
"""
####################################################
## 1. Temel Veri Türleri ve Operatörler
####################################################
# Sayılar
3 # => 3
# Tahmin edebileceğiniz gibi matematik
1 + 1 # => 2
8 - 1 # => 7
10 * 2 # => 20
# Bölme işlemi varsayılan olarak onluk döndürür
35 / 5 # => 7.0
# Tam sayı bölmeleri, pozitif ve negatif sayılar için aşağıya yuvarlar
5 // 3 # => 1
5.0 // 3.0 # => 1.0 # onluklar için de bu böyledir
-5 // 3 # => -2
-5.0 // 3.0 # => -2.0
# Onluk kullanırsanız, sonuç da onluk olur
3 * 2.0 # => 6.0
# Kalan operatörü
7 % 3 # => 1
# Üs (2 üzeri 4)
2**4 # => 16
# Parantez ile önceliği değiştirebilirsiniz
(1 + 3) * 2 # => 8
# Boolean(Doğru-Yanlış) değerleri standart
True
False
# 'değil' ile terse çevirme
not True # => False
not False # => True
# Boolean Operatörleri
# "and" ve "or" büyük küçük harf duyarlıdır
True and False #=> False
False or True #=> True
# Bool operatörleri ile sayı kullanımı
0 and 2 #=> 0
-5 or 0 #=> -5
0 == False #=> True
2 == True #=> False
1 == True #=> True
# Eşitlik kontrolü ==
1 == 1 # => True
2 == 1 # => False
# Eşitsizlik Kontrolü !=
1 != 1 # => False
2 != 1 # => True
# Diğer karşılaştırmalar
1 < 10 # => True
1 > 10 # => False
2 <= 2 # => True
2 >= 2 # => True
# Zincirleme şeklinde karşılaştırma da yapabilirsiniz!
1 < 2 < 3 # => True
2 < 3 < 2 # => False
# Yazı(Strings) " veya ' işaretleri ile oluşturulabilir
"Bu bir yazı."
'Bu da bir yazı.'
# Yazılar da eklenebilir! Fakat bunu yapmanızı önermem.
"Merhaba " + "dünya!" # => "Merhaba dünya!"
# Bir yazı(string) karakter listesi gibi işlenebilir
"Bu bir yazı"[0] # => 'B'
# .format ile yazıyı biçimlendirebilirsiniz, şu şekilde:
"{} da ayrıca {}".format("yazılar", "işlenebilir")
# Biçimlendirme işleminde aynı argümanı da birden fazla kullanabilirsiniz.
"{0} çeviktir, {0} hızlıdır, {0} , {1} üzerinden atlayabilir".format("Ahmet", "şeker çubuğu")
#=> "Ahmet çeviktir, Ahmet hızlıdır, Ahmet , şeker çubuğu üzerinden atlayabilir"
# Argümanın sırasını saymak istemiyorsanız, anahtar kelime kullanabilirsiniz.
"{isim} yemek olarak {yemek} istiyor".format(isim="Ahmet", yemek="patates") #=> "Ahmet yemek olarak patates istiyor"
# Eğer Python 3 kodunuz ayrıca Python 2.5 ve üstünde çalışmasını istiyorsanız,
# eski stil formatlamayı kullanabilirsiniz:
"%s bu %s yolla da %s" % ("yazılar", "eski", "biçimlendirilebilir")
# Hiçbir şey(none) da bir objedir
None # => None
# Bir değerin none ile eşitlik kontrolü için "==" sembolünü kullanmayın
# Bunun yerine "is" kullanın. Obje türünün eşitliğini kontrol edecektir.
"vb" is None # => False
None is None # => True
# None, 0, ve boş yazılar/listeler/sözlükler hepsi False değeri döndürü.
# Diğer veriler ise True değeri döndürür
bool(0) # => False
bool("") # => False
bool([]) #=> False
bool({}) #=> False
####################################################
## 2. Değişkenler ve Koleksiyonlar
####################################################
# Python bir yazdırma fonksiyonuna sahip
print("Ben Python. Tanıştığıma memnun oldum!")
# Değişkenlere veri atamak için önce değişkeni oluşturmanıza gerek yok.
# Düzenli bir değişken için hepsi_kucuk_ve_alt_cizgi_ile_ayirin
bir_degisken = 5
bir_degisken # => 5
# Önceden tanımlanmamış değişkene erişmek hata oluşturacaktır.
# Kontrol akışları başlığından hata kontrolünü öğrenebilirsiniz.
bir_bilinmeyen_degisken # NameError hatası oluşturur
# Listeler ile sıralamaları tutabilirsiniz
li = []
# Önceden doldurulmuş listeler ile başlayabilirsiniz
diger_li = [4, 5, 6]
# 'append' ile listenin sonuna ekleme yapabilirsiniz
li.append(1) # li artık [1] oldu
li.append(2) # li artık [1, 2] oldu
li.append(4) # li artık [1, 2, 4] oldu
li.append(3) # li artık [1, 2, 4, 3] oldu
# 'pop' ile listenin son elementini kaldırabilirsiniz
li.pop() # => 3 ve li artık [1, 2, 4]
# Çıkarttığımız tekrardan ekleyelim
li.append(3) # li yeniden [1, 2, 4, 3] oldu.
# Dizi gibi listeye erişim sağlayın
li[0] # => 1
# Son elemente bakın
li[-1] # => 3
# Listede olmayan bir elemente erişim sağlamaya çalışmak IndexError hatası oluşturur
li[4] # IndexError hatası oluşturur
# Bir kısmını almak isterseniz.
li[1:3] # => [2, 4]
# Başlangıç belirtmezseniz
li[2:] # => [4, 3]
# Sonu belirtmesseniz
li[:3] # => [1, 2, 4]
# Her ikişer objeyi seçme
li[::2] # =>[1, 4]
# Listeyi tersten almak
li[::-1] # => [3, 4, 2, 1]
# Kombinasyonları kullanarak gelişmiş bir şekilde listenin bir kısmını alabilirsiniz
# li[baslangic:son:adim]
# "del" ile isteğe bağlı, elementleri listeden kaldırabilirsiniz
del li[2] # li artık [1, 2, 3] oldu
# Listelerde de ekleme yapabilirsiniz
# Not: değerler üzerinde değişiklik yapılmaz.
li + diger_li # => [1, 2, 3, 4, 5, 6]
# Listeleri birbirine bağlamak için "extend()" kullanılabilir
li.extend(diger_li) # li artık [1, 2, 3, 4, 5, 6] oldu
# Listedeki bir elementin olup olmadığı kontrolü "in" ile yapılabilir
1 in li # => True
# Uzunluğu öğrenmek için "len()" kullanılabilir
len(li) # => 6
# Tüpler listeler gibidir fakat değiştirilemez.
tup = (1, 2, 3)
tup[0] # => 1
tup[0] = 3 # TypeError hatası oluşturur
# Diğer liste işlemlerini tüplerde de uygulayabilirsiniz
len(tup) # => 3
tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6)
tup[:2] # => (1, 2)
2 in tup # => True
# Tüpleri(veya listeleri) değişkenlere açabilirsiniz
a, b, c = (1, 2, 3) # 'a' artık 1, 'b' artık 2 ve 'c' artık 3
# Eğer parantez kullanmazsanız varsayılan oalrak tüpler oluşturulur
d, e, f = 4, 5, 6
# 2 değeri birbirine değiştirmek bu kadar kolay
e, d = d, e # 'd' artık 5 ve 'e' artık 4
# Sözlükler anahtar kodlarla verileri tutar
bos_sozl = {}
# Önceden doldurulmuş sözlük oluşturma
dolu_sozl = {"bir": 1, "iki": 2, "uc": 3}
# Değere bakmak için [] kullanalım
dolu_sozl["bir"] # => 1
# Bütün anahtarları almak için "keys()" kullanılabilir.
# Listelemek için list() kullanacağınız çünkü dönen değerin işlenmesi gerekiyor. Bu konuya daha sonra değineceğiz.
# Not - Sözlük anahtarlarının sıralaması kesin değildir.
# Beklediğiniz çıktı sizinkiyle tam uyuşmuyor olabilir.
list(dolu_sozl.keys()) # => ["uc", "iki", "bir"]
# Tüm değerleri almak için "values()" kullanacağız. Dönen değeri biçimlendirmek için de list() kullanmamız gerekiyor
# Not - Sıralama değişebilir.
list(dolu_sozl.values()) # => [3, 2, 1]
# Bir anahtarın sözlükte olup olmadığını "in" ile kontrol edebilirsiniz
"bir" in dolu_sozl # => True
1 in dolu_sozl # => False
# Olmayan bir anahtardan değer elde etmek isterseniz KeyError sorunu oluşacaktır.
dolu_sozl["dort"] # KeyError hatası oluşturur
# "get()" metodu ile değeri almaya çalışırsanız KeyError sorunundan kurtulursunuz
dolu_sozl.get("bir") # => 1
dolu_sozl.get("dort") # => None
# "get" metoduna parametre belirterek değerin olmaması durumunda varsayılan bir değer döndürebilirsiniz.
dolu_sozl.get("bir", 4) # => 1
dolu_sozl.get("dort", 4) # => 4
# "setdefault()" metodu sözlükte, belirttiğiniz anahtarın [olmaması] durumunda varsayılan bir değer atayacaktır
dolu_sozl.setdefault("bes", 5) # dolu_sozl["bes"] artık 5 değerine sahip
dolu_sozl.setdefault("bes", 6) # dolu_sozl["bes"] değişmedi, hala 5 değerine sahip
# Sözlüğe ekleme
dolu_sozl.update({"dort":4}) #=> {"bir": 1, "iki": 2, "uc": 3, "dort": 4}
#dolu_sozl["dort"] = 4 #sözlüğe eklemenin bir diğer yolu
# Sözlükten anahtar silmek için 'del' kullanılabilir
del dolu_sozl["bir"] # "bir" anahtarını dolu sözlükten silecektir
# Setler ... set işte :D
bos_set = set()
# Seti bir veri listesi ile de oluşturabilirsiniz. Evet, biraz sözlük gibi duruyor. Üzgünüm.
bir_set = {1, 1, 2, 2, 3, 4} # bir_set artık {1, 2, 3, 4}
# Sete yeni setler ekleyebilirsiniz
dolu_set = bir_set
# Sete bir diğer öğe ekleme
dolu_set.add(5) # dolu_set artık {1, 2, 3, 4, 5} oldu
# Setlerin çakışan kısımlarını almak için '&' kullanabilirsiniz
diger_set = {3, 4, 5, 6}
dolu_set & diger_set # => {3, 4, 5}
# '|' ile aynı olan elementleri almayacak şekilde setleri birleştirebilirsiniz
dolu_set | diger_set # => {1, 2, 3, 4, 5, 6}
# Farklılıkları almak için "-" kullanabilirsiniz
{1, 2, 3, 4} - {2, 3, 5} # => {1, 4}
# Bir değerin olup olmadığının kontrolü için "in" kullanılabilir
2 in dolu_set # => True
10 in dolu_set # => False
####################################################
## 3. Kontrol Akışları ve Temel Soyutlandırma
####################################################
# Bir değişken oluşturalım
bir_degisken = 5
# Burada bir "if" ifadesi var. Girinti(boşluk,tab) python için önemlidir!
# çıktı olarak "bir_degisken 10 dan küçük" yazar
if bir_degisken > 10:
print("bir_degisken 10 dan büyük")
elif bir_degisken < 10: # Bu 'elif' ifadesi zorunlu değildir.
print("bir_degisken 10 dan küçük")
else: # Bu ifade de zorunlu değil.
print("bir_degisken değeri 10")
"""
Döngülerle lsiteleri döngüye alabilirsiniz
çıktı:
köpek bir memeli hayvandır
kedi bir memeli hayvandır
fare bir memeli hayvandır
"""
for hayvan in ["köpek", "kedi, "fare"]:
# format ile kolayca yazıyı biçimlendirelim
print("{} bir memeli hayvandır".format(hayvan))
"""
"range(sayi)" bir sayı listesi döndür
0'dan belirttiğiniz sayıyıa kadar
çıktı:
0
1
2
3
"""
for i in range(4):
print(i)
"""
'While' döngüleri koşul çalıştıkça işlemleri gerçekleştirir.
çıktı:
0
1
2
3
"""
x = 0
while x < 4:
print(x)
x += 1 # Uzun hali x = x + 1
# Hataları kontrol altına almak için try/except bloklarını kullanabilirsiniz
try:
# Bir hata oluşturmak için "raise" kullanabilirsiniz
raise IndexError("Bu bir index hatası")
except IndexError as e:
pass # Önemsiz, devam et.
except (TypeError, NameError):
pass # Çoklu bir şekilde hataları kontrol edebilirsiniz, tabi gerekirse.
else: # İsteğe bağlı bir kısım. Eğer hiçbir hata kontrol mekanizması desteklemiyorsa bu blok çalışacaktır
print("Her şey iyi!") # IndexError, TypeError ve NameError harici bir hatada bu blok çalıştı
# Temel Soyutlandırma, bir objenin işlenmiş halidir.
# Aşağıdaki örnekte; Obje, range fonksiyonuna temel soyutlandırma gönderdi.
dolu_sozl = {"bir": 1, "iki": 2, "uc": 3}
temel_soyut = dolu_sozl.keys()
print(temel_soyut) #=> range(1,10). Bu obje temel soyutlandırma arayüzü ile oluşturuldu
# Temel Soyutlandırılmış objeyi döngüye sokabiliriz.
for i in temel_soyut:
print(i) # Çıktısı: bir, iki, uc
# Fakat, elementin anahtarına değerine.
temel_soyut[1] # TypeError hatası!
# 'iterable' bir objenin nasıl temel soyutlandırıldığıdır.
iterator = iter(temel_soyut)
# 'iterator' o obje üzerinde yaptığımız değişiklikleri hatırlayacaktır
# Bir sonraki objeyi almak için __next__ fonksiyonunu kullanabilirsiniz.
iterator.__next__() #=> "bir"
# Bir önceki __next__ fonksiyonumuzu hatırlayıp bir sonraki kullanımda bu sefer ondan bir sonraki objeyi döndürecektir
iterator.__next__() #=> "iki"
iterator.__next__() #=> "uc"
# Bütün nesneleri aldıktan sonra bir daha __next__ kullanımınızda, StopIterator hatası oluşturacaktır.
iterator.__next__() # StopIteration hatası
# iterator'deki tüm nesneleri almak için list() kullanabilirsiniz.
list(dolu_sozl.keys()) #=> Returns ["bir", "iki", "uc"]
####################################################
## 4. Fonksiyonlar
####################################################
# "def" ile yeni fonksiyonlar oluşturabilirsiniz
def topla(x, y):
print("x = {} ve y = {}".format(x, y))
return x + y # Değer döndürmek için 'return' kullanmalısınız
# Fonksiyonu parametleri ile çağırıyoruz
topla(5, 6) # => çıktı "x = 5 ve y = 6" ve değer olarak 11 döndürür
# Bir diğer fonksiyon çağırma yöntemi de anahtar değerleri ile belirtmek
topla(y=6, x=5) # Anahtar değeri belirttiğiniz için parametre sıralaması önemsiz.
# Sınırsız sayıda argüman da alabilirsiniz
def argumanlar(*argumanlar):
return argumanlar
argumanlar(1, 2, 3) # => (1, 2, 3)
# Parametrelerin anahtar değerlerini almak isterseniz
def anahtar_par(**anahtarlar):
return anahtar
# Çalıştırdığımızda
anahtar_par(anah1="deg1", anah2="deg2") # => {"anah1": "deg1", "anah2": "deg2"}
# İsterseniz, bu ikisini birden kullanabilirsiniz
def tum_argumanlar(*argumanlar, **anahtarla):
print(argumanlar)
print(anahtarla)
"""
tum_argumanlar(1, 2, a=3, b=4) çıktı:
(1, 2)
{"a": 3, "b": 4}
"""
# Fonksiyonu çağırırken de aynısını kullanabilirsiniz
argumanlar = (1, 2, 3, 4)
anahtarla = {"a": 3, "b": 4}
tum_argumanlar(*argumanlar) # = foo(1, 2, 3, 4)
tum_argumanlar(**anahtarla) # = foo(a=3, b=4)
tum_argumanlar(*argumanlar, **anahtarla) # = foo(1, 2, 3, 4, a=3, b=4)
# Fonksiyonlarda kullanacağımız bir değişken oluşturalım
x = 5
def belirleX(sayi):
# Fonksiyon içerisindeki x ile global tanımladığımız x aynı değil
x = sayi # => 43
print (x) # => 43
def globalBelirleX(sayi):
global x
print (x) # => 5
x = sayi # global olan x değişkeni artık 6
print (x) # => 6
belirleX(43)
globalBelirleX(6)
# Sınıf fonksiyonları oluşturma
def toplama_olustur(x):
def topla(y):
return x + y
return topla
ekle_10 = toplama_olustur(10)
ekle_10(3) # => 13
# Bilinmeyen fonksiyon
(lambda x: x > 2)(3) # => True
# TODO - Fix for iterables
# Belirli sayıdan yükseğini alma fonksiyonu
map(ekle_10, [1, 2, 3]) # => [11, 12, 13]
filter(lambda x: x > 5, [3, 4, 5, 6, 7]) # => [6, 7]
# Filtreleme işlemi için liste comprehensions da kullanabiliriz
[ekle_10(i) for i in [1, 2, 3]] # => [11, 12, 13]
[x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7]
####################################################
## 5. Sınıflar
####################################################
# Sınıf oluşturmak için objeden alt sınıf oluşturacağız.
class Insan(obje):
# Sınıf değeri. Sınıfın tüm nesneleri tarafından kullanılabilir
tur = "H. sapiens"
# Basit başlatıcı, Sınıf çağrıldığında tetiklenecektir.
# Dikkat edin, iki adet alt çizgi(_) bulunmakta. Bunlar
# python tarafından tanımlanan isimlerdir.
# Kendinize ait bir fonksiyon oluştururken __fonksiyon__ kullanmayınız!
def __init__(self, isim):
# Parametreyi sınıfın değerine atayalım
self.isim = isim
# Bir metot. Bütün metotlar ilk parametre olarak "self "alır.
def soyle(self, mesaj):
return "{isim}: {mesaj}".format(isim=self.name, mesaj=mesaj)
# Bir sınıf metotu bütün nesnelere paylaştırılır
# İlk parametre olarak sınıf alırlar
@classmethod
def getir_tur(snf):
return snf.tur
# Bir statik metot, sınıf ve nesnesiz çağrılır
@staticmethod
def grunt():
return "*grunt*"
# Sınıfı çağıralım
i = Insan(isim="Ahmet")
print(i.soyle("merhaba")) # çıktı "Ahmet: merhaba"
j = Insan("Ali")
print(j.soyle("selam")) # çıktı "Ali: selam"
# Sınıf metodumuzu çağıraim
i.getir_tur() # => "H. sapiens"
# Paylaşılan değeri değiştirelim
Insan.tur = "H. neanderthalensis"
i.getir_tur() # => "H. neanderthalensis"
j.getir_tur() # => "H. neanderthalensis"
# Statik metodumuzu çağıralım
Insan.grunt() # => "*grunt*"
####################################################
## 6. Moduller
####################################################
# Modülleri içe aktarabilirsiniz
import math
print(math.sqrt(16)) # => 4
# Modülden belirli bir fonksiyonları alabilirsiniz
from math import ceil, floor
print(ceil(3.7)) # => 4.0
print(floor(3.7)) # => 3.0
# Modüldeki tüm fonksiyonları içe aktarabilirsiniz
# Dikkat: bunu yapmanızı önermem.
from math import *
# Modül isimlerini değiştirebilirsiniz.
# Not: Modül ismini kısaltmanız çok daha iyi olacaktır
import math as m
math.sqrt(16) == m.sqrt(16) # => True
# Python modulleri aslında birer python dosyalarıdır.
# İsterseniz siz de yazabilir ve içe aktarabilirsiniz Modulün
# ismi ile dosyanın ismi aynı olacaktır.
# Moduldeki fonksiyon ve değerleri öğrenebilirsiniz.
import math
dir(math)
####################################################
## 7. Gelişmiş
####################################################
# Oluşturucular uzun uzun kod yazmamanızı sağlayacak ve yardımcı olacaktır
def kare_sayilar(nesne):
for i in nesne:
yield i + i
# Bir oluşturucu(generator) değerleri anında oluşturur.
# Bir seferde tüm değerleri oluşturup göndermek yerine teker teker her oluşumdan
# sonra geri döndürür. Bu demektir ki, kare_sayilar fonksiyonumuzda 15'ten büyük
# değerler işlenmeyecektir.
# Not: range() da bir oluşturucu(generator)dur. 1-900000000 arası bir liste yapmaya çalıştığınızda
# çok fazla vakit alacaktır.
# Python tarafından belirlenen anahtar kelimelerden kaçınmak için basitçe alt çizgi(_) kullanılabilir.
range_ = range(1, 900000000)
# kare_sayilar'dan dönen değer 30'a ulaştığında durduralım
for i in kare_sayilar(range_):
print(i)
if i >= 30:
break
# Dekoratörler
# Bu örnekte,
# Eğer lutfen_soyle True ise dönen değer değişecektir.
from functools import wraps
def yalvar(hedef_fonksiyon):
@wraps(hedef_fonksiyon)
def metot(*args, **kwargs):
msj, lutfen_soyle = hedef_fonksiyon(*args, **kwargs)
if lutfen_soyle:
return "{} {}".format(msj, "Lütfen! Artık dayanamıyorum :(")
return msj
return metot
@yalvar
def soyle(lutfen_soyle=False):
msj = "Bana soda alır mısın?"
return msj, lutfen_soyle
print(soyle()) # Bana soda alır mısın?
print(soyle(lutfen_soyle=True)) # Ban soda alır mısın? Lutfen! Artık dayanamıyorum :(
```
## Daha Fazlasına Hazır Mısınız?
### Ücretsiz Online
* [Learn Python The Hard Way](http://learnpythonthehardway.org/book/)
* [Dive Into Python](http://www.diveintopython.net/)
* [Ideas for Python Projects](http://pythonpracticeprojects.com)
* [The Official Docs](http://docs.python.org/3/)
* [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/)
* [A Crash Course in Python for Scientists](http://nbviewer.ipython.org/5920182)
* [Python Course](http://www.python-course.eu/index.php)
### Kitaplar
* [Programming Python](http://www.amazon.com/gp/product/0596158106/ref=as_li_qf_sp_asin_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596158106&linkCode=as2&tag=homebits04-20)
* [Dive Into Python](http://www.amazon.com/gp/product/1441413022/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1441413022&linkCode=as2&tag=homebits04-20)
* [Python Essential Reference](http://www.amazon.com/gp/product/0672329786/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0672329786&linkCode=as2&tag=homebits04-20)

572
zh-cn/c++-cn.html.markdown Normal file
View File

@ -0,0 +1,572 @@
---
language: c++
filename: learncpp-cn.cpp
contributors:
- ["Steven Basart", "http://github.com/xksteven"]
- ["Matt Kline", "https://github.com/mrkline"]
translators:
- ["Arnie97", "https://github.com/Arnie97"]
lang: zh-cn
---
C++是一种系统编程语言。用它的发明者,
[Bjarne Stroustrup的话](http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Keynote)来说C++的设计目标是:
- 成为“更好的C语言”
- 支持数据的抽象与封装
- 支持面向对象编程
- 支持泛型编程
C++提供了对硬件的紧密控制正如C语言一样
能够编译为机器语言,由处理器直接执行。
与此同时,它也提供了泛型、异常和类等高层功能。
虽然C++的语法可能比某些出现较晚的语言更复杂,它仍然得到了人们的青睞——
功能与速度的平衡使C++成为了目前应用最广泛的系统编程语言之一。
```c++
////////////////
// 与C语言的比较
////////////////
// C++_几乎_是C语言的一个超集它与C语言的基本语法有许多相同之处
// 例如变量和函数的声明,原生数据类型等等。
// 和C语言一样在C++中你的程序会从main()开始执行,
// 该函数的返回值应当为int型这个返回值会作为程序的退出状态值。
// 不过大多数的编译器gccclang等也接受 void main() 的函数原型。
// (参见 http://en.wikipedia.org/wiki/Exit_status 来获取更多信息)
int main(int argc, char** argv)
{
// 和C语言一样命令行参数通过argc和argv传递。
// argc代表命令行参数的数量
// 而argv是一个包含“C语言风格字符串”char *)的数组,
// 其中每个字符串代表一个命令行参数的内容,
// 首个命令行参数是调用该程序时所使用的名称。
// 如果你不关心命令行参数的值argc和argv可以被忽略。
// 此时你可以用int main()作为函数原型。
// 退出状态值为0时表示程序执行成功
return 0;
}
// 然而C++和C语言也有一些区别
// 在C++中,字符字面量的大小是一个字节。
sizeof('c') == 1
// 在C语言中字符字面量的大小与int相同。
sizeof('c') == sizeof(10)
// C++的函数原型与函数定义是严格匹配的
void func(); // 这个函数不能接受任何参数
// 而在C语言中
void func(); // 这个函数能接受任意数量的参数
// 在C++中用nullptr代替C语言中的NULL
int* ip = nullptr;
// C++也可以使用C语言的标准头文件
// 但是需要加上前缀“c”并去掉末尾的“.h”。
#include <cstdio>
int main()
{
printf("Hello, world!\n");
return 0;
}
///////////
// 函数重载
///////////
// C++支持函数重载,你可以定义一组名称相同而参数不同的函数。
void print(char const* myString)
{
printf("String %s\n", myString);
}
void print(int myInt)
{
printf("My int is %d", myInt);
}
int main()
{
print("Hello"); // 解析为 void print(const char*)
print(15); // 解析为 void print(int)
}
///////////////////
// 函数参数的默认值
///////////////////
// 你可以为函数的参数指定默认值,
// 它们将会在调用者没有提供相应参数时被使用。
void doSomethingWithInts(int a = 1, int b = 4)
{
// 对两个参数进行一些操作
}
int main()
{
doSomethingWithInts(); // a = 1, b = 4
doSomethingWithInts(20); // a = 20, b = 4
doSomethingWithInts(20, 5); // a = 20, b = 5
}
// 默认参数必须放在所有的常规参数之后。
void invalidDeclaration(int a = 1, int b) // 这是错误的!
{
}
///////////
// 命名空间
///////////
// 命名空间为变量、函数和其他声明提供了分离的的作用域。
// 命名空间可以嵌套使用。
namespace First {
namespace Nested {
void foo()
{
printf("This is First::Nested::foo\n");
}
} // 结束嵌套的命名空间Nested
} // 结束命名空间First
namespace Second {
void foo()
{
printf("This is Second::foo\n")
}
}
void foo()
{
printf("This is global foo\n");
}
int main()
{
// 如果没有特别指定就从“Second”中取得所需的内容。
using namespace Second;
foo(); // 显示“This is Second::foo”
First::Nested::foo(); // 显示“This is First::Nested::foo”
::foo(); // 显示“This is global foo”
}
////////////
// 输入/输出
////////////
// C++使用“流”来输入输出。<<是流的插入运算符>>是流提取运算符。
// cin、cout、和cerr分别代表
// stdin标准输入、stdout标准输出和stderr标准错误
#include <iostream> // 引入包含输入/输出流的头文件
using namespace std; // 输入输出流在std命名空间也就是标准库中。
int main()
{
int myInt;
// 在标准输出(终端/显示器)中显示
cout << "Enter your favorite number:\n";
// 从标准输入(键盘)获得一个值
cin >> myInt;
// cout也提供了格式化功能
cout << "Your favorite number is " << myInt << "\n";
// 显示“Your favorite number is <myInt>
cerr << "Used for error messages";
}
/////////
// 字符串
/////////
// C++中的字符串是对象,它们有很多成员函数
#include <string>
using namespace std; // 字符串也在std命名空间标准库中。
string myString = "Hello";
string myOtherString = " World";
// + 可以用于连接字符串。
cout << myString + myOtherString; // "Hello World"
cout << myString + " You"; // "Hello You"
// C++中的字符串是可变的,具有“值语义”。
myString.append(" Dog");
cout << myString; // "Hello Dog"
/////////////
// 引用
/////////////
// 除了支持C语言中的指针类型以外C++还提供了_引用_。
// 引用是一种特殊的指针类型,一旦被定义就不能重新赋值,并且不能被设置为空值。
// 使用引用时的语法与原变量相同:
// 也就是说,对引用类型进行解引用时,不需要使用*
// 赋值时也不需要用&来取地址。
using namespace std;
string foo = "I am foo";
string bar = "I am bar";
string& fooRef = foo; // 建立了一个对foo的引用。
fooRef += ". Hi!"; // 通过引用来修改foo的值
cout << fooRef; // "I am foo. Hi!"
// 这句话的并不会改变fooRef的指向其效果与“foo = bar”相同。
// 也就是说在执行这条语句之后foo == "I am bar"。
fooRef = bar;
const string& barRef = bar; // 建立指向bar的常量引用。
// 和C语言中一样指针和引用声明为常量时对应的值不能被修改。
barRef += ". Hi!"; // 这是错误的,不能修改一个常量引用的值。
///////////////////
// 类与面向对象编程
///////////////////
// 有关类的第一个示例
#include <iostream>
// 声明一个类。
// 类通常在头文件(.h或.hpp中声明。
class Dog {
// 成员变量和成员函数默认情况下是私有private的。
std::string name;
int weight;
// 在这个标签之后所有声明都是公有public
// 直到重新指定“private:”私有继承或“protected:”(保护继承)为止
public:
// 默认的构造器
Dog();
// 这里是成员函数声明的一个例子。
// 可以注意到我们在此处使用了std::string而不是using namespace std
// 语句using namespace绝不应当出现在头文件当中。
void setName(const std::string& dogsName);
void setWeight(int dogsWeight);
// 如果一个函数不对对象的状态进行修改,
// 应当在声明中加上const。
// 这样,你就可以对一个以常量方式引用的对象执行该操作。
// 同时可以注意到,当父类的成员函数需要被子类重写时,
// 父类中的函数必须被显式声明为_虚函数virtual_。
// 考虑到性能方面的因素,函数默认情况下不会被声明为虚函数。
virtual void print() const;
// 函数也可以在class body内部定义。
// 这样定义的函数会自动成为内联函数。
void bark() const { std::cout << name << " barks!\n" }
// 除了构造器以外C++还提供了析构器。
// 当一个对象被删除或者脱离其定义域时,它的析构函数会被调用。
// 这使得RAII这样的强大范式参见下文成为可能。
// 为了衍生出子类来,基类的析构函数必须定义为虚函数。
virtual ~Dog();
}; // 在类的定义之后,要加一个分号
// 类的成员函数通常在.cpp文件中实现。
void Dog::Dog()
{
std::cout << "A dog has been constructed\n";
}
// 对象(例如字符串)应当以引用的形式传递,
// 对于不需要修改的对象,最好使用常量引用。
void Dog::setName(const std::string& dogsName)
{
name = dogsName;
}
void Dog::setWeight(int dogsWeight)
{
weight = dogsWeight;
}
// 虚函数的virtual关键字只需要在声明时使用不需要在定义时重复
void Dog::print() const
{
std::cout << "Dog is " << name << " and weighs " << weight << "kg\n";
}
void Dog::~Dog()
{
cout << "Goodbye " << name << "\n";
}
int main() {
Dog myDog; // 此时显示“A dog has been constructed”
myDog.setName("Barkley");
myDog.setWeight(10);
myDog.printDog(); // 显示“Dog is Barkley and weighs 10 kg”
return 0;
} // 显示“Goodbye Barkley”
// 继承:
// 这个类继承了Dog类中的公有public和保护protected对象
class OwnedDog : public Dog {
void setOwner(const std::string& dogsOwner)
// 重写OwnedDogs类的print方法。
// 如果你不熟悉子类多态的话,可以参考这个页面中的概述:
// http://zh.wikipedia.org/wiki/%E5%AD%90%E7%B1%BB%E5%9E%8B
// override关键字是可选的它确保你所重写的是基类中的方法。
void print() const override;
private:
std::string owner;
};
// 与此同时,在对应的.cpp文件里
void OwnedDog::setOwner(const std::string& dogsOwner)
{
owner = dogsOwner;
}
void OwnedDog::print() const
{
Dog::print(); // 调用基类Dog中的print方法
// "Dog is <name> and weights <weight>"
std::cout << "Dog is owned by " << owner << "\n";
// "Dog is owned by <owner>"
}
/////////////////////
// 初始化与运算符重载
/////////////////////
// 在C++中,通过定义一些特殊名称的函数,
// 你可以重载+、-、*、/等运算符的行为。
// 当运算符被使用时,这些特殊函数会被调用,从而实现运算符重载。
#include <iostream>
using namespace std;
class Point {
public:
// 可以以这样的方式为成员变量设置默认值。
double x = 0;
double y = 0;
// 定义一个默认的构造器。
// 除了将Point初始化为(0, 0)以外,这个函数什么都不做。
Point() { };
// 下面使用的语法称为初始化列表,
// 这是初始化类中成员变量的正确方式。
Point (double a, double b) :
x(a),
y(b)
{ /* 除了初始化成员变量外,什么都不做 */ }
// 重载 + 运算符
Point operator+(const Point& rhs) const;
// 重载 += 运算符
Point& operator+=(const Point& rhs);
// 增加 - 和 -= 运算符也是有意义的,但这里不再赘述。
};
Point Point::operator+(const Point& rhs) const
{
// 创建一个新的点,
// 其横纵坐标分别为这个点与另一点在对应方向上的坐标之和。
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);
// 这里使用了Point类型的运算符“+”
// 调用upPoint类型的“+”方法并以right作为函数的参数
Point result = up + right;
// 显示“Result is upright (1,1)”
cout << "Result is upright (" << result.x << ',' << result.y << ")\n";
return 0;
}
///////////
// 异常处理
///////////
// 标准库中提供了一些基本的异常类型
// 参见http://en.cppreference.com/w/cpp/error/exception
// 但是,其他任何类型也可以作为一个异常被拋出
#include <exception>
// 在_try_代码块中拋出的异常可以被随后的_catch_捕获。
try {
// 不要用 _new_关键字在堆上为异常分配空间。
throw std::exception("A problem occurred");
}
// 如果拋出的异常是一个对象,可以用常量引用来捕获它
catch (const std::exception& ex)
{
std::cout << ex.what();
// 捕获尚未被_catch_处理的所有错误
} catch (...)
{
std::cout << "Unknown exception caught";
throw; // 重新拋出异常
}
///////
// RAII
///////
// RAII指的是“资源获取就是初始化”Resource Allocation Is Initialization
// 它被视作C++中最强大的编程范式之一。
// 简单说来,它指的是,用构造函数来获取一个对象的资源,
// 相应的,借助析构函数来释放对象的资源。
// 为了理解这一范式的用处,让我们考虑某个函数使用文件句柄时的情况:
void doSomethingWithAFile(const char* filename)
{
// 首先,让我们假设一切都会顺利进行。
FILE* fh = fopen(filename, "r"); // 以只读模式打开文件
doSomethingWithTheFile(fh);
doSomethingElseWithIt(fh);
fclose(fh); // 关闭文件句柄
}
// 不幸的是,随着错误处理机制的引入,事情会变得复杂。
// 假设fopen函数有可能执行失败
// 而doSomethingWithTheFile和doSomethingElseWithIt会在失败时返回错误代码。
// 虽然异常是C++中处理错误的推荐方式,
// 但是某些程序员尤其是有C语言背景的并不认可异常捕获机制的作用
// 现在,我们必须检查每个函数调用是否成功执行,并在问题发生的时候关闭文件句柄。
bool doSomethingWithAFile(const char* filename)
{
FILE* fh = fopen(filename, "r"); // 以只读模式打开文件
if (fh == nullptr) // 当执行失败是返回的指针是nullptr
return false; // 向调用者汇报错误
// 假设每个函数会在执行失败时返回false
if (!doSomethingWithTheFile(fh)) {
fclose(fh); // 关闭文件句柄,避免造成内存泄漏。
return false; // 反馈错误
}
if (!doSomethingElseWithIt(fh)) {
fclose(fh); // 关闭文件句柄
return false; // 反馈错误
}
fclose(fh); // 关闭文件句柄
return true; // 指示函数已成功执行
}
// C语言的程序员通常会借助goto语句简化上面的代码
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); // 关闭文件
return true; // 执行成功
failure:
fclose(fh);
return false; // 反馈错误
}
// 如果用异常捕获机制来指示错误的话,
// 代码会变得清晰一些,但是仍然有优化的余地。
void doSomethingWithAFile(const char* filename)
{
FILE* fh = fopen(filename, "r"); // 以只读模式打开文件
if (fh == nullptr)
throw std::exception("Could not open the file.");
try {
doSomethingWithTheFile(fh);
doSomethingElseWithIt(fh);
}
catch (...) {
fclose(fh); // 保证出错的时候文件被正确关闭
throw; // 之后,重新抛出这个异常
}
fclose(fh); // 关闭文件
// 所有工作顺利完成
}
// 相比之下使用C++中的文件流类fstream
// fstream会利用自己的析构器来关闭文件句柄。
// 只要离开了某一对象的定义域,它的析构函数就会被自动调用。
void doSomethingWithAFile(const std::string& filename)
{
// ifstream是输入文件流input file stream的简称
std::ifstream fh(filename); // 打开一个文件
// 对文件进行一些操作
doSomethingWithTheFile(fh);
doSomethingElseWithIt(fh);
} // 文件已经被析构器自动关闭
// 与上面几种方式相比这种方式有着_明显_的优势
// 1. 无论发生了什么情况,资源(此例当中是文件句柄)都会被正确关闭。
// 只要你正确使用了析构器就_不会_因为忘记关闭句柄造成资源的泄漏。
// 2. 可以注意到,通过这种方式写出来的代码十分简洁。
// 析构器会在后台关闭文件句柄,不再需要你来操心这些琐事。
// 3. 这种方式的代码具有异常安全性。
// 无论在函数中的何处拋出异常,都不会阻碍对文件资源的释放。
// 地道的C++代码应当把RAII的使用扩展到各种类型的资源上包括
// - 用unique_ptr和shared_ptr管理的内存
// - 各种数据容器,例如标准库中的链表、向量(容量自动扩展的数组)、散列表等;
// 当它们脱离作用域时,析构器会自动释放其中储存的内容。
// - 用lock_guard和unique_lock实现的互斥
```
扩展阅读:
<http://cppreference.com/w/cpp> 提供了最新的语法参考。
可以在 <http://cplusplus.com> 找到一些补充资料。

View File

@ -5,24 +5,25 @@ contributors:
- ["Adit Bhargava", "http://adit.io"] - ["Adit Bhargava", "http://adit.io"]
translators: translators:
- ["Peiyong Lin", ""] - ["Peiyong Lin", ""]
- ["chad luo", "http://yuki.rocks"]
lang: zh-cn lang: zh-cn
--- ---
Haskell 被设计成一种实用的纯函数式编程语言。它因为 monads 及其类型系统而出名但是我回归到它本身因为。Haskell 使得编程对于我而言是一种真正的快乐。 Haskell 是一门实用的函数式编程语言,因其 Monads 与类型系统而闻名。而我使用它则是因为它异常优雅。用 Haskell 编程令我感到非常快乐。
```haskell ```haskell
-- 单行注释以两个破折号开头 -- 单行注释以两个号开头
{- 多行注释像这样 {- 多行注释像这样
被一个闭合的块包围 被一个闭合的块包围
-} -}
---------------------------------------------------- ----------------------------------------------------
-- 1. 简单的数据类型和操作符 -- 1. 简单的数据类型和操作符
---------------------------------------------------- ----------------------------------------------------
-- 你有数字 -- 数字
3 -- 3 3 -- 3
-- 数学计算就像你所期待的那样 -- 数学计算
1 + 1 -- 2 1 + 1 -- 2
8 - 1 -- 7 8 - 1 -- 7
10 * 2 -- 20 10 * 2 -- 20
@ -34,7 +35,7 @@ Haskell 被设计成一种实用的纯函数式编程语言。它因为 monads
-- 整除 -- 整除
35 `div` 4 -- 8 35 `div` 4 -- 8
-- 布尔值也简单 -- 布尔值
True True
False False
@ -45,21 +46,22 @@ not False -- True
1 /= 1 -- False 1 /= 1 -- False
1 < 10 -- True 1 < 10 -- True
-- 在上述的例子中,`not` 是一个接受一个值的函数。 -- 在上面的例子中,`not` 是一个接受一个参数的函数。
-- Haskell 不需要括号来调用函数。。。所有的参数 -- Haskell 不需要括号来调用函数,所有的参数都只是在函数名之后列出来
-- 都只是在函数名之后列出来。因此,通常的函数调用模式是: -- 因此,通常的函数调用模式是:
-- func arg1 arg2 arg3... -- func arg1 arg2 arg3...
-- 查看关于函数的章节以获得如何写你自己的函数的相关信息 -- 你可以查看函数部分了解如何自行编写
-- 字符串和字符 -- 字符串和字符
"This is a string." "This is a string." -- 字符串
'a' -- 字符 'a' -- 字符
'对于字符串你不能使用单引号。' -- 错误! '对于字符串你不能使用单引号。' -- 错误!
-- 连字符串 -- 连字符串
"Hello " ++ "world!" -- "Hello world!" "Hello " ++ "world!" -- "Hello world!"
-- 一个字符串是一系列字符 -- 一个字符串是一系列字符
['H', 'e', 'l', 'l', 'o'] -- "Hello"
"This is a string" !! 0 -- 'T' "This is a string" !! 0 -- 'T'
@ -67,162 +69,164 @@ not False -- True
-- 列表和元组 -- 列表和元组
---------------------------------------------------- ----------------------------------------------------
-- 一个列表中的每一个元素都必须是相同的类型 -- 一个列表中的每一个元素都必须是相同的类型
-- 下面两个列表一样 -- 下面两个列表等价
[1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
[1..5] [1..5]
-- 在 Haskell 你可以拥有含有无限元素的列表 -- 区间也可以这样
['A'..'F'] -- "ABCDEF"
-- 你可以在区间中指定步进
[0,2..10] -- [0, 2, 4, 6, 8, 10]
[5..1] -- 这样不行,因为 Haskell 默认递增
[5,4..1] -- [5, 4, 3, 2, 1]
-- 列表下标
[0..] !! 5 -- 5
-- 在 Haskell 你可以使用无限列表
[1..] -- 一个含有所有自然数的列表 [1..] -- 一个含有所有自然数的列表
-- 因为 Haskell 有“懒惰计算”,所以无限元素的列表可以正常运作。这意味着 -- 无限列表的原理是Haskell 有“惰性求值”。
-- Haskell 可以只在它需要的时候计算。所以你可以请求 -- 这意味着 Haskell 只在需要时才会计算。
-- 列表中的第1000个元素Haskell 会返回给你 -- 所以当你获取列表的第 1000 项元素时Haskell 会返回给你:
[1..] !! 999 -- 1000 [1..] !! 999 -- 1000
-- Haskell 计算了列表中第 1 至 1000 项元素,但这个无限列表中剩下的元素还不存在。
-- Haskell 只有在需要时才会计算它们。
-- Haskell 计算了列表中 1 - 1000 个元素。。。但是 -- 连接两个列表
-- 这个无限元素的列表中剩下的元素还不存在! Haskell 不会
-- 真正地计算它们知道它需要。
<FS>- 连接两个列表
[1..5] ++ [6..10] [1..5] ++ [6..10]
-- 往列表头增加元素 -- 往列表头增加元素
0:[1..5] -- [0, 1, 2, 3, 4, 5] 0:[1..5] -- [0, 1, 2, 3, 4, 5]
-- 列表中的下标 -- 其它列表操作
[0..] !! 5 -- 5
-- 更多列表操作
head [1..5] -- 1 head [1..5] -- 1
tail [1..5] -- [2, 3, 4, 5] tail [1..5] -- [2, 3, 4, 5]
init [1..5] -- [1, 2, 3, 4] init [1..5] -- [1, 2, 3, 4]
last [1..5] -- 5 last [1..5] -- 5
-- 列表推导 -- 列表推导 (list comprehension)
[x*2 | x <- [1..5]] -- [2, 4, 6, 8, 10] [x*2 | x <- [1..5]] -- [2, 4, 6, 8, 10]
-- 附带条件 -- 附带条件
[x*2 | x <-[1..5], x*2 > 4] -- [6, 8, 10] [x*2 | x <-[1..5], x*2 > 4] -- [6, 8, 10]
-- 元组中的每一个元素可以是不同类型的,但是一个元组 -- 元组中的每一个元素可以是不同类型,但是一个元组的长度是固定的
-- 的长度是固定的
-- 一个元组 -- 一个元组
("haskell", 1) ("haskell", 1)
-- 获取元组中的元素 -- 获取元组中的元素(例如,一个含有 2 个元素的元祖)
fst ("haskell", 1) -- "haskell" fst ("haskell", 1) -- "haskell"
snd ("haskell", 1) -- 1 snd ("haskell", 1) -- 1
---------------------------------------------------- ----------------------------------------------------
-- 3. 函数 -- 3. 函数
---------------------------------------------------- ----------------------------------------------------
-- 一个接受两个变量的简单函数 -- 一个接受两个变量的简单函数
add a b = a + b add a b = a + b
-- 注意,如果你使用 ghci (Hakell 解释器) -- 注意,如果你使用 ghci (Hakell 解释器),你需要使用 `let`,也就是
-- 你将需要使用 `let`,也就是
-- let add a b = a + b -- let add a b = a + b
-- 使用函数 -- 用函数
add 1 2 -- 3 add 1 2 -- 3
-- 你也可以把函数放置在两个参数之间 -- 你也可以使用反引号中置函数名:
-- 附带倒引号:
1 `add` 2 -- 3 1 `add` 2 -- 3
-- 你也可以定义不带字符的函数!这使得 -- 你也可以定义不带字母的函数名,这样你可以定义自己的操作符。
-- 你定义自己的操作符!这里有一个操作符 -- 这里有一个做整除的操作符
-- 来做整除
(//) a b = a `div` b (//) a b = a `div` b
35 // 4 -- 8 35 // 4 -- 8
-- 守卫:一个简单的方法在函数里做分支 -- Guard一个在函数中做条件判断的简单方法
fib x fib x
| x < 2 = x | x < 2 = x
| otherwise = fib (x - 1) + fib (x - 2) | otherwise = fib (x - 1) + fib (x - 2)
-- 模式匹配是类型的。这里有三种不同的 fib -- 模式匹配与 Guard 类似。
-- 定义。Haskell 将自动调用第一个 -- 这里给出了三个不同的 fib 定义。
-- 匹配值的模式的函数。 -- Haskell 会自动调用第一个符合参数模式的声明
fib 1 = 1 fib 1 = 1
fib 2 = 2 fib 2 = 2
fib x = fib (x - 1) + fib (x - 2) fib x = fib (x - 1) + fib (x - 2)
-- 元组的模式匹配 -- 元组的模式匹配
foo (x, y) = (x + 1, y + 2) foo (x, y) = (x + 1, y + 2)
-- 列表的模式匹配。这里 `x` 是列表中第一个元素, -- 列表的模式匹配
-- 并且 `xs` 是列表剩余的部分。我们可以写 -- 这里 `x` 是列表中第一个元素,`xs` 是列表剩余的部分。
-- 自己的 map 函数: -- 我们可以实现自己的 map 函数:
myMap func [] = [] myMap func [] = []
myMap func (x:xs) = func x:(myMap func xs) myMap func (x:xs) = func x:(myMap func xs)
-- 编写出来的匿名函数带有一个反斜杠,后面跟着 -- 匿名函数带有一个反斜杠,后面跟着所有的参数
-- 所有的参数。
myMap (\x -> x + 2) [1..5] -- [3, 4, 5, 6, 7] myMap (\x -> x + 2) [1..5] -- [3, 4, 5, 6, 7]
-- 使用 fold (在一些语言称为`inject`)随着一个匿名的 -- 在 fold在一些语言称 为`inject`)中使用匿名函数
-- 函数。foldl1 意味着左折叠(fold left), 并且使用列表中第一个值 -- foldl1 意味着左折叠 (fold left), 并且使用列表中第一个值作为累加器的初始值。
-- 作为累加器的初始化值。
foldl1 (\acc x -> acc + x) [1..5] -- 15 foldl1 (\acc x -> acc + x) [1..5] -- 15
---------------------------------------------------- ----------------------------------------------------
-- 4. 更多的函数 -- 4. 其它函数
---------------------------------------------------- ----------------------------------------------------
-- 柯里化(currying):如果你不传递函数中所有的参数, -- 部分调用
-- 它就变成“柯里化的”。这意味着,它返回一个接受剩余参数的函数 -- 如果你调用函数时没有给出所有参数,它就被“部分调用”
-- 它将返回一个接受余下参数的函数。
add a b = a + b add a b = a + b
foo = add 10 -- foo 现在是一个接受一个数并对其加 10 的函数 foo = add 10 -- foo 现在是一个接受一个数并对其加 10 的函数
foo 5 -- 15 foo 5 -- 15
-- 另外一种方式去做同样的事 -- 另一种等价写法
foo = (+10) foo = (+10)
foo 5 -- 15 foo 5 -- 15
-- 函数组 -- 函列表
-- (.) 函数把其它函数链接到一起 -- (.) 函数把其它函数链接到一起
-- 举个列子,这里 foo 是一个接受一个值的函数。它对接受的值加 10 -- 例如,这里 foo 是一个接受一个值的函数。
-- 并对结果乘以 5之后返回最后的值。 -- 它对接受的值加 10并对结果乘以 5之后返回最后的值。
foo = (*5) . (+10) foo = (*5) . (+10)
-- (5 + 10) * 5 = 75 -- (5 + 10) * 5 = 75
foo 5 -- 75 foo 5 -- 75
-- 修复优先级 -- 修正优先级
-- Haskell 有另外一个函数称为 `$`。它改变优先级 -- Haskell 有另外一个函数 `$` 可以改变优先级。
-- 使得其左侧的每一个操作先计算然后应用到 -- `$` 使得 Haskell 先计算其右边的部分,然后调用左边的部分。
-- 右侧的每一个操作。你可以使用 `.``$` 来除去很多 -- 你可以使用 `$` 来移除多余的括号。
-- 括号:
-- before -- 修改前
(even (fib 7)) -- true (even (fib 7)) -- true
-- after -- 修改后
even . fib $ 7 -- true even . fib $ 7 -- true
-- 等价地
even $ fib 7 -- true
---------------------------------------------------- ----------------------------------------------------
-- 5. 类型签名 -- 5. 类型声明
---------------------------------------------------- ----------------------------------------------------
-- Haskell 有一个非常强壮的类型系统,一切都有一个类型签名 -- Haskell 有一个非常强大的类型系统,一切都有一个类型声明
-- 一些基本的类型: -- 一些基本的类型:
5 :: Integer 5 :: Integer
"hello" :: String "hello" :: String
True :: Bool True :: Bool
-- 函数也有类型 -- 函数也有类型
-- `not` 接受一个布尔型返回一个布尔型 -- `not` 接受一个布尔型返回一个布尔型
-- not :: Bool -> Bool -- not :: Bool -> Bool
-- 这是接受两个参数的函数 -- 这是接受两个参数的函数
-- add :: Integer -> Integer -> Integer -- add :: Integer -> Integer -> Integer
-- 当你定义一个值,在其上写明它的类型是一个好实践: -- 当你定义一个值,声明其类型是一个好做法
double :: Integer -> Integer double :: Integer -> Integer
double x = x * 2 double x = x * 2
@ -230,159 +234,148 @@ double x = x * 2
-- 6. 控制流和 If 语句 -- 6. 控制流和 If 语句
---------------------------------------------------- ----------------------------------------------------
-- if 语句 -- if 语句
haskell = if 1 == 1 then "awesome" else "awful" -- haskell = "awesome" haskell = if 1 == 1 then "awesome" else "awful" -- haskell = "awesome"
-- if 语句也可以有多行,缩进是很重要的 -- if 语句也可以有多行,注意缩进:
haskell = if 1 == 1 haskell = if 1 == 1
then "awesome" then "awesome"
else "awful" else "awful"
-- case 语句:这里是你可以怎样去解析命令行参数 -- case 语句
-- 解析命令行参数:
case args of case args of
"help" -> printHelp "help" -> printHelp
"start" -> startProgram "start" -> startProgram
_ -> putStrLn "bad args" _ -> putStrLn "bad args"
-- Haskell 没有循环因为它使用递归取代之。 -- Haskell 没有循环,它使用递归
-- map 应用一个函数到一个数组中的每一个元素 -- map 对一个列表中的每一个元素调用一个函数
map (*2) [1..5] -- [2, 4, 6, 8, 10] map (*2) [1..5] -- [2, 4, 6, 8, 10]
-- 你可以使用 map 来编写 for 函数 -- 你可以使用 map 来编写 for 函数
for array func = map func array for array func = map func array
-- 然后使用它 -- 调用
for [0..5] $ \i -> show i for [0..5] $ \i -> show i
-- 我们也可以像这样写 -- 我们也可以像这样写
for [0..5] show for [0..5] show
-- 你可以使用 foldl 或者 foldr 来分解列表 -- 你可以使用 foldl 或者 foldr 来分解列表
-- foldl <fn> <initial value> <list> -- foldl <fn> <initial value> <list>
foldl (\x y -> 2*x + y) 4 [1,2,3] -- 43 foldl (\x y -> 2*x + y) 4 [1,2,3] -- 43
-- 这和下面是一样的 -- 等价于
(2 * (2 * (2 * 4 + 1) + 2) + 3) (2 * (2 * (2 * 4 + 1) + 2) + 3)
-- foldl 是左手边的foldr 是右手边的- -- foldl 从左开始foldr 从右
foldr (\x y -> 2*x + y) 4 [1,2,3] -- 16 foldr (\x y -> 2*x + y) 4 [1,2,3] -- 16
-- 这和下面是一样的 -- 现在它等价于
(2 * 3 + (2 * 2 + (2 * 1 + 4))) (2 * 3 + (2 * 2 + (2 * 1 + 4)))
---------------------------------------------------- ----------------------------------------------------
-- 7. 数据类型 -- 7. 数据类型
---------------------------------------------------- ----------------------------------------------------
-- 这里展示在 Haskell 中你怎样编写自己的数据类型 -- 在 Haskell 中声明你自己的数据类型:
data Color = Red | Blue | Green data Color = Red | Blue | Green
-- 现在你可以在函数中使用它: -- 现在你可以在函数中使用它:
say :: Color -> String say :: Color -> String
say Red = "You are Red!" say Red = "You are Red!"
say Blue = "You are Blue!" say Blue = "You are Blue!"
say Green = "You are Green!" say Green = "You are Green!"
-- 你的数据类型也可以有参数: -- 你的数据类型也可以有参数:
data Maybe a = Nothing | Just a data Maybe a = Nothing | Just a
-- 类型 Maybe 的所有 -- 这些都是 Maybe 类型:
Just "hello" -- of type `Maybe String` Just "hello" -- `Maybe String` 类型
Just 1 -- of type `Maybe Int` Just 1 -- `Maybe Int` 类型
Nothing -- of type `Maybe a` for any `a` Nothing -- 对任意 `a``Maybe a` 类型
---------------------------------------------------- ----------------------------------------------------
-- 8. Haskell IO -- 8. Haskell IO
---------------------------------------------------- ----------------------------------------------------
-- 虽然在没有解释 monads 的情况下 IO不能被完全地解释 -- 虽然不解释 Monads 就无法完全解释 IO但大致了解并不难。
-- 着手解释到位并不难。
-- 当一个 Haskell 程序被执行,函数 `main` 就被调用。
-- 它必须返回一个类型 `IO ()` 的值。举个列子:
-- 当执行一个 Haskell 程序时,函数 `main` 就被调用。
-- 它必须返回一个类型 `IO ()` 的值。例如:
main :: IO () main :: IO ()
main = putStrLn $ "Hello, sky! " ++ (say Blue) main = putStrLn $ "Hello, sky! " ++ (say Blue)
-- putStrLn has type String -> IO () -- putStrLn 的类型是 String -> IO ()
-- 如果你能实现你的程序依照函数从 String 到 String那样编写 IO 是最简单的。 -- 如果你的程序输入 String 返回 String那样编写 IO 是最简单的。
-- 函数 -- 函数
-- interact :: (String -> String) -> IO () -- interact :: (String -> String) -> IO ()
-- 输入一些文本,在其上运行一个函数,并打印出输出 -- 输入一些文本,对其调用一个函数,并打印输出。
countLines :: String -> String countLines :: String -> String
countLines = show . length . lines countLines = show . length . lines
main' = interact countLines main' = interact countLines
-- 你可以考虑一个 `IO()` 类型的值,当做一系列计算机所完成的动作的代表, -- 你可以认为一个 `IO ()` 类型的值是表示计算机做的一系列操作,类似命令式语言。
-- 就像一个以命令式语言编写的计算机程序。我们可以使用 `do` 符号来把动作链接到一起。 -- 我们可以使用 `do` 声明来把动作连接到一起。
-- 举个列子: -- 举个列子
sayHello :: IO () sayHello :: IO ()
sayHello = do sayHello = do
putStrLn "What is your name?" putStrLn "What is your name?"
name <- getLine -- this gets a line and gives it the name "input" name <- getLine -- 这里接受一行输入并绑定至 "name"
putStrLn $ "Hello, " ++ name putStrLn $ "Hello, " ++ name
-- 练习:编写只读取一行输入的 `interact` -- 练习:编写只读取一行输入的 `interact`
-- 然而,`sayHello` 中的代码将不会被执行。唯一被执行的动作是 `main` 的值。 -- 然而,`sayHello` 中的代码将不会被执行。唯一被执行的动作是 `main` 的值。
-- 为了运行 `sayHello`,注释上面 `main` 的定义,并代替它 -- 为了运行 `sayHello`,注释上面 `main` 的定义,替换为
-- main = sayHello -- main = sayHello
-- 让我们来更好地理解刚才所使用的函数 `getLine` 是怎样工作的。它的类型是: -- 让我们来更进一步理解刚才所使用的函数 `getLine` 是怎样工作的。它的类型是:
-- getLine :: IO String -- getLine :: IO String
-- 你可以考虑一个 `IO a` 类型的值,代表一个当被执行的时候 -- 你可以认为一个 `IO a` 类型的值代表了一个运行时会生成一个 `a` 类型值的程序。
-- 将产生一个 `a` 类型的值的计算机程序(除了它所做的任何事之外)。我们可以保存和重用这个值通过 `<-` -- (可能伴随其它行为)
-- 我们也可以写自己的 `IO String` 类型的动作: -- 我们可以通过 `<-` 保存和重用这个值。
-- 我们也可以实现自己的 `IO String` 类型函数:
action :: IO String action :: IO String
action = do action = do
putStrLn "This is a line. Duh" putStrLn "This is a line. Duh"
input1 <- getLine input1 <- getLine
input2 <- getLine input2 <- getLine
-- The type of the `do` statement is that of its last line. -- `do` 语句的类型是它的最后一行
-- `return` is not a keyword, but merely a function -- `return` 不是关键字,只是一个普通函数
return (input1 ++ "\n" ++ input2) -- return :: String -> IO String return (input1 ++ "\n" ++ input2) -- return :: String -> IO String
-- 我们可以使用这个动作就像我们使用 `getLine`: -- 我们可以像调用 `getLine` 一样调用它
main'' = do main'' = do
putStrLn "I will echo two lines!" putStrLn "I will echo two lines!"
result <- action result <- action
putStrLn result putStrLn result
putStrLn "This was all, folks!" putStrLn "This was all, folks!"
-- `IO` 类型是一个 "monad" 的例子。Haskell 使用一个 monad 来做 IO的方式允许它是一门纯函数式语言 -- `IO` 类型是一个 "Monad" 的例子
-- 任何与外界交互的函数(也就是 IO) 都在它的类型签名处做一个 `IO` 标志 -- Haskell 通过使用 Monad 使得其本身为纯函数式语言。
-- 着让我们推出 什么样的函数是“纯洁的”(不与外界交互,不修改状态) 和 什么样的函数不是 “纯洁的” -- 任何与外界交互的函数(即 IO都在它的类型声明中标记为 `IO`
-- 这告诉我们什么样的函数是“纯洁的”(不与外界交互,不修改状态)
-- 这是一个强有力的特征因为并发地运行纯函数是简单的因此Haskell 中并发是非常简单的 -- 什么样的函数不是 “纯洁的”
-- 这个功能非常强大,因为纯函数并发非常容易,由此在 Haskell 中做并发非常容易。
---------------------------------------------------- ----------------------------------------------------
-- 9. The Haskell REPL -- 9. Haskell REPL
---------------------------------------------------- ----------------------------------------------------
-- 键入 `ghci` 开始 repl -- 键入 `ghci` 开始 REPL
-- 现在你可以键入 Haskell 代码。 -- 现在你可以键入 Haskell 代码。
-- 任何新值都需要通过 `let` 来创建: -- 任何新值都需要通过 `let` 来创建
let foo = 5 let foo = 5
-- 你可以查看任何值的类型,通过命令 `:t` -- 你可以通过命令 `:t` 查看任何值的类型
>:t foo >:t foo
foo :: Integer foo :: Integer
-- 你也可以运行任何 `IO ()`类型的动作 -- 你也可以运行任何 `IO ()`类型的动作
> sayHello > sayHello
What is your name? What is your name?
Friend! Friend!
@ -390,7 +383,7 @@ Hello, Friend!
``` ```
还有很多关于 Haskell包括类型类和 monads。这些是使得编码 Haskell 是如此有趣的主意。我用一个最后的 Haskell 例子来结束:一个 Haskell 的快排实现: Haskell 还有许多内容,包括类型类 (typeclasses) 与 Monads。这些都是令 Haskell 编程非常有趣的好东西。我们最后给出 Haskell 的一个例子,一个快速排序的实现:
```haskell ```haskell
qsort [] = [] qsort [] = []
@ -399,9 +392,9 @@ qsort (p:xs) = qsort lesser ++ [p] ++ qsort greater
greater = filter (>= p) xs greater = filter (>= p) xs
``` ```
安装 Haskell 是简单的。你可以从[这里](http://www.haskell.org/platform/)获得它 安装 Haskell 很简单。你可以[从这里获得](http://www.haskell.org/platform/)
你可以从优秀的 你可以从优秀的
[Learn you a Haskell](http://learnyouahaskell.com/) 或者 [Learn you a Haskell](http://learnyouahaskell.com/) 或者
[Real World Haskell](http://book.realworldhaskell.org/) [Real World Haskell](http://book.realworldhaskell.org/)
找到优雅不少的入门介绍。 找到更平缓的入门介绍。

View File

@ -4,12 +4,15 @@ filename: learnscala-zh.scala
contributors: contributors:
- ["George Petrov", "http://github.com/petrovg"] - ["George Petrov", "http://github.com/petrovg"]
- ["Dominic Bou-Samra", "http://dbousamra.github.com"] - ["Dominic Bou-Samra", "http://dbousamra.github.com"]
- ["Geoff Liu", "http://geoffliu.me"]
translators: translators:
- ["Peiyong Lin", ""] - ["Peiyong Lin", ""]
- ["Jinchang Ye", "http://github.com/alwayswithme"]
- ["Guodong Qu", "https://github.com/jasonqu"]
lang: zh-cn lang: zh-cn
--- ---
Scala - 一门可拓展的语言 Scala - 一门可拓展的语言
```scala ```scala
@ -17,23 +20,31 @@ Scala - 一门可拓展性的语言
自行设置: 自行设置:
1) 下载 Scala - http://www.scala-lang.org/downloads 1) 下载 Scala - http://www.scala-lang.org/downloads
2) unzip/untar 到你喜欢的地方,放在路径中的 bin 目录下 2) unzip/untar 到您喜欢的地方,并把 bin 子目录添加到 path 环境变量
3) 在终端输入 scala开启 Scala 的 REPL会看到提示符: 3) 在终端输入 scala启动 Scala 的 REPL会看到提示符:
scala> scala>
这就是所谓的 REPL你现在可以在其中运行命令让我们做到这一点 这就是所谓的 REPL (读取-求值-输出循环,英语: Read-Eval-Print Loop)
您可以在其中输入合法的表达式,结果会被打印。
在教程中我们会进一步解释 Scala 文件是怎样的,但现在先了解一点基础。
*/ */
println(10) // 打印整数 10
println("Boo!") // 打印字符串 "BOO!" /////////////////////////////////////////////////
// 1. 基础
/////////////////////////////////////////////////
// 单行注释开始于两个斜杠
// 一些基础 /*
多行注释,如您之前所见,看起来像这样
*/
// 打印并强制换行 // 打印并强制换行
println("Hello world!") println("Hello world!")
println(10)
// 没有强制换行的打印 // 没有强制换行的打印
print("Hello world") print("Hello world")
@ -41,13 +52,19 @@ print("Hello world")
// val 声明是不可变的var 声明是可修改的。不可变性是好事。 // val 声明是不可变的var 声明是可修改的。不可变性是好事。
val x = 10 // x 现在是 10 val x = 10 // x 现在是 10
x = 20 // 错误: 对 val 声明的变量重新赋值 x = 20 // 错误: 对 val 声明的变量重新赋值
var x = 10 var y = 10
x = 20 // x 现在是 20 y = 20 // y 现在是 20
// 单行注释开始于两个斜杠
/* /*
多行注释看起来像这样。 Scala 是静态语言,但注意上面的声明方式,我们没有指定类型。
这是因为类型推导的语言特性。大多数情况, Scala 编译器可以推测变量的类型,
所以您不需要每次都输入。可以像这样明确声明变量类型:
*/ */
val z: Int = 10
val a: Double = 1.0
// 注意从 Int 到 Double 的自动转型,结果是 10.0, 不是 10
val b: Double = 10
// 布尔值 // 布尔值
true true
@ -64,9 +81,11 @@ true == false // false
2 - 1 // 1 2 - 1 // 1
5 * 3 // 15 5 * 3 // 15
6 / 2 // 3 6 / 2 // 3
6 / 4 // 1
6.0 / 4 // 1.5
// 在 REPL 计算一个命令会返回给你结果的类型和值 // 在 REPL 计算一个表达式会返回给您结果的类型和值
1 + 7 1 + 7
@ -77,149 +96,134 @@ true == false // false
这意味着计算 1 + 7 的结果是一个 Int 类型的对象,其值为 8 这意味着计算 1 + 7 的结果是一个 Int 类型的对象,其值为 8
1+7 的结果是一样的 注意 "res29" 是一个连续生成的变量名,用以存储您输入的表达式结果,
您看到的输出可能不一样。
*/ */
"Scala strings are surrounded by double quotes"
'a' // Scala 的字符
// '不存在单引号字符串' <= 这会导致错误
// 包括函数在内,每一个事物都是对象。在 REPL 中输入: // String 有常见的 Java 字符串方法
"hello world".length
"hello world".substring(2, 6)
"hello world".replace("C", "3")
7 // 结果 res30: Int = 7 (res30 是一个生成的结果的 var 命名) // 也有一些额外的 Scala 方法另请参见scala.collection.immutable.StringOps
"hello world".take(5)
"hello world".drop(5)
// 下一行给你一个接收一个 Int 类型并返回该数的平方的函数 // 字符串改写:留意前缀 "s"
val n = 45
s"We have $n apples" // => "We have 45 apples"
// 在要改写的字符串中使用表达式也是可以的
val a = Array(11, 9, 6)
s"My second daughter is ${a(0) - a(2)} years old." // => "My second daughter is 5 years old."
s"We have double the amount of ${n / 2.0} in apples." // => "We have double the amount of 22.5 in apples."
s"Power of 2: ${math.pow(2, 2)}" // => "Power of 2: 4"
// 添加 "f" 前缀对要改写的字符串进行格式化
f"Power of 5: ${math.pow(5, 2)}%1.0f" // "Power of 5: 25"
f"Square root of 122: ${math.sqrt(122)}%1.4f" // "Square root of 122: 11.0454"
// 未处理的字符串,忽略特殊字符。
raw"New line feed: \n. Carriage return: \r." // => "New line feed: \n. Carriage return: \r."
// 一些字符需要转义,比如字符串中的双引号
"They stood outside the \"Rose and Crown\"" // => "They stood outside the "Rose and Crown""
// 三个双引号可以使字符串跨越多行,并包含引号
val html = """<form id="daform">
<p>Press belo', Joe</p>
<input type="submit">
</form>"""
/////////////////////////////////////////////////
// 2. 函数
/////////////////////////////////////////////////
// 函数可以这样定义:
//
// def functionName(args...): ReturnType = { body... }
//
// 如果您以前学习过传统的编程语言,注意 return 关键字的省略。
// 在 Scala 中, 函数代码块最后一条表达式就是返回值。
def sumOfSquares(x: Int, y: Int): Int = {
val x2 = x * x
val y2 = y * y
x2 + y2
}
// 如果函数体是单行表达式,{ } 可以省略:
def sumOfSquaresShort(x: Int, y: Int): Int = x * x + y * y
// 函数调用的语法是熟知的:
sumOfSquares(3, 4) // => 25
// 在多数情况下 (递归函数是需要注意的例外), 函数返回值可以省略,
// 变量所用的类型推导一样会应用到函数返回值中:
def sq(x: Int) = x * x // 编译器会推断得知返回值是 Int
// 函数可以有默认参数
def addWithDefault(x: Int, y: Int = 5) = x + y
addWithDefault(1, 2) // => 3
addWithDefault(1) // => 6
// 匿名函数是这样的:
(x:Int) => x * x (x:Int) => x * x
// 你可以分配给函数一个标识符,像这样: // 和 def 不同,如果语义清晰,匿名函数的参数类型也可以省略。
val sq = (x:Int) => x * x // 类型 "Int => Int" 意味着这个函数接收一个 Int 并返回一个 Int。
val sq: Int => Int = x => x * x
/* 上面的例子说明 // 匿名函数的调用也是类似的:
sq(10) // => 100
sq: Int => Int = <function1> // 如果您的匿名函数中每个参数仅使用一次,
// Scala 提供一个更简洁的方式来定义他们。这样的匿名函数极为常见,
// 在数据结构部分会明显可见。
val addOne: Int => Int = _ + 1
val weirdSum: (Int, Int) => Int = (_ * 2 + _ * 3)
意味着这次我们给予了 sq 这样一个显式的名字给一个接受一个 Int 类型值并返回 一个 Int 类型值的函数 addOne(5) // => 6
weirdSum(2, 4) // => 16
sq 可以像下面那样被执行:
*/
sq(10) // 返回给你res33: Int = 100.
// Scala 允许方法和函数返回或者接受其它的函数或者方法作为参数。
val add10: Int => Int = _ + 10 // 一个接受一个 Int 类型参数并返回一个 Int 类型值的函数
List(1, 2, 3) map add10 // List(11, 12, 13) - add10 被应用到每一个元素
// 匿名函数可以被使用来代替有命名的函数:
List(1, 2, 3) map (x => x + 10)
// 下划线标志,如果匿名函数只有一个参数可以被使用来表示该参数变量
List(1, 2, 3) map (_ + 10)
// 如果你所应用的匿名块和匿名函数都接受一个参数,那么你甚至可以省略下划线
List("Dom", "Bob", "Natalia") foreach println
// return 关键字是存在的,但它只从最里面包裹了 return 的 def 函数中返回。
// 警告: 在 Scala 中使用 return 容易出错,应该避免使用。
// 在匿名函数中没有效果,例如:
def foo(x: Int): Int = {
val anonFunc: Int => Int = { z =>
if (z > 5)
return z // 这一行令 z 成为 foo 函数的返回值!
else
z + 2 // 这一行是 anonFunc 函数的返回值
}
anonFunc(x) // 这一行是 foo 函数的返回值
}
// 数据结构 /*
* 译者注:此处是指匿名函数中的 return z 成为最后执行的语句,
val a = Array(1, 2, 3, 5, 8, 13) * 在 anonFunc(x) 下面的表达式(假设存在)不再执行。如果 anonFunc
a(0) * 是用 def 定义的函数, return z 仅返回到 anonFunc(x)
a(3) * 在 anonFunc(x) 下面的表达式(假设存在)会继续执行。
a(21) // 这会抛出一个异常
val m = Map("fork" -> "tenedor", "spoon" -> "cuchara", "knife" -> "cuchillo")
m("fork")
m("spoon")
m("bottle") // 这会抛出一个异常
val safeM = m.withDefaultValue("no lo se")
safeM("bottle")
val s = Set(1, 3, 7)
s(0)
s(1)
/* 查看 map 的文档
* 点击[这里](http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Map)
* 确保你可以读它
*/ */
// 元组 /////////////////////////////////////////////////
// 3. 控制语句
(1, 2) /////////////////////////////////////////////////
(4, 3, 2)
(1, 2, "three")
(a, 2, "three")
// 为什么有这个?
val divideInts = (x:Int, y:Int) => (x / y, x % y)
divideInts(10,3) // 函数 divideInts 返回你结果和余数
// 要读取元组的元素,使用 _._nn是从1开始的元素索引
val d = divideInts(10,3)
d._1
d._2
// 选择器
s.map(sq)
val sSquared = s. map(sq)
sSquared.filter(_ < 10)
sSquared.reduce (_+_)
// filter 函数接受一个预测(一个函数,形式为 A -> Boolean) 并选择出所有的元素满足这个预测
List(1, 2, 3) filter (_ > 2) // List(3)
List(
Person(name = "Dom", age = 23),
Person(name = "Bob", age = 30)
).filter(_.age > 25) // List(Person("Bob", 30))
// Scala 的 foreach 方法定义在特定的接受一个类型的集合上
// 返回 Unit(一个 void 方法)
aListOfNumbers foreach (x => println(x))
aListOfNumbers foreach println
// For 包含
for { n <- s } yield sq(n)
val nSquared2 = 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
/* 注意:这些不是 for 循环. 一个 for 循环的语义是 '重复'('repeat')
然而,一个 for-包含 定义了一个两个数据结合间的关系 */
// 循环和迭代
1 to 5 1 to 5
val r = 1 to 5 val r = 1 to 5
r.foreach( println ) r.foreach( println )
r foreach println r foreach println
// 注意Scala 是相当宽容的当它遇到点和括号 - 分别地学习这些规则 // 附注: Scala 对点和括号的要求想当宽松,注意其规则是不同的。
// 这帮助你编写读起来像英语的 DSLs 和 APIs // 这有助于写出读起来像英语的 DSL(领域特定语言) 和 API(应用编程接口)。
(5 to 1 by -1) foreach ( println ) (5 to 1 by -1) foreach ( println )
@ -227,27 +231,27 @@ r foreach println
var i = 0 var i = 0
while (i < 10) { println("i " + i); i+=1 } while (i < 10) { println("i " + i); i+=1 }
while (i < 10) { println("i " + i); i+=1 } // 发生了什么为什么 while (i < 10) { println("i " + i); i+=1 } // 没错再执行一次发生了什么为什么
i // 展示 i 的值。注意到 while 是一个传统意义上的循环 i // 显示 i 的值。注意 while 是经典的循环方式,它连续执行并改变循环中的变量。
// 它顺序地执行并且改变循环变量的值。while 非常快,比 Java // 循环快, // while 执行很快,比 Java 的循环快,但像上面所看到的那样用组合子和推导式
// 但是在其上使用选择器和包含易理解和并行。 // 更易理解和并行
// do while 循环 // do while 循环
do { do {
println("x is still less then 10"); println("x is still less than 10");
x += 1 x += 1
} while (x < 10) } while (x < 10)
// 在 Scala中尾递归是一种惯用的执行循环的方式。 // Scala 中尾递归是一种符合语言习惯的递归方式。
// 递归函数需要显示的返回类型,编译器不能推断出类型 // 递归函数需要清晰的返回类型,编译器不能推断得知
// 这里它是 Unit。 // 这是一个 Unit。
def showNumbersInRange(a:Int, b:Int):Unit = { def showNumbersInRange(a:Int, b:Int):Unit = {
print(a) print(a)
if (a < b) if (a < b)
showNumbersInRange(a + 1, b) showNumbersInRange(a + 1, b)
} }
showNumbersInRange(1,14)
// 条件语句 // 条件语句
@ -262,140 +266,340 @@ if (x == 11) println ("yeah") else println("nay")
println(if (x == 10) "yeah" else "nope") println(if (x == 10) "yeah" else "nope")
val text = if (x == 10) "yeah" else "nope" val text = if (x == 10) "yeah" else "nope"
var i = 0
while (i < 10) { println("i " + i); i+=1 } /////////////////////////////////////////////////
// 4. 数据结构
/////////////////////////////////////////////////
val a = Array(1, 2, 3, 5, 8, 13)
a(0)
a(3)
a(21) // 抛出异常
val m = Map("fork" -> "tenedor", "spoon" -> "cuchara", "knife" -> "cuchillo")
m("fork")
m("spoon")
m("bottle") // 抛出异常
val safeM = m.withDefaultValue("no lo se")
safeM("bottle")
val s = Set(1, 3, 7)
s(0)
s(1)
/* 这里查看 map 的文档 -
* http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Map
* 并确保你会阅读
*/
// 元组
// 面向对象特性 (1, 2)
// 类名是 Dog (4, 3, 2)
class Dog {
//bark 方法,返回字符串 (1, 2, "three")
def bark: String = {
// the body of the method (a, 2, "three")
"Woof, woof!"
} // 为什么有这个?
val divideInts = (x:Int, y:Int) => (x / y, x % y)
divideInts(10,3) // 函数 divideInts 同时返回结果和余数
// 要读取元组的元素,使用 _._nn是从1开始的元素索引
val d = divideInts(10,3)
d._1
d._2
/////////////////////////////////////////////////
// 5. 面向对象编程
/////////////////////////////////////////////////
/*
旁白: 教程中到现在为止我们所做的一切只是简单的表达式(值,函数等)。
这些表达式可以输入到命令行解释器中作为快速测试,但它们不能独立存在于 Scala
文件。举个例子,您不能在 Scala 文件上简单的写上 "val x = 5"。相反 Scala 文件
允许的顶级结构是:
- objects
- classes
- case classes
- traits
现在来解释这些是什么。
*/
// 类和其他语言的类相似,构造器参数在类名后声明,初始化在类结构体中完成。
class Dog(br: String) {
// 构造器代码在此
var breed: String = br
// 定义名为 bark 的方法,返回字符串
def bark = "Woof, woof!"
// 值和方法作用域假定为 public。"protected" 和 "private" 关键字也是可用的。
private def sleep(hours: Int) =
println(s"I'm sleeping for $hours hours")
// 抽象方法是没有方法体的方法。如果取消下面那行注释Dog 类必须被声明为 abstract
// abstract class Dog(...) { ... }
// def chaseAfter(what: String): String
} }
// 类可以包含几乎其它的构造,包括其它的类, val mydog = new Dog("greyhound")
// 函数方法对象case 类,特性等等。 println(mydog.breed) // => "greyhound"
println(mydog.bark) // => "Woof, woof!"
// "object" 关键字创造一种类型和该类型的单例。
// Case 类 // Scala 的 class 常常也含有一个 “伴生对象”class 中包含每个实例的行为,所有实例
// 共用的行为则放入 object 中。两者的区别和其他语言中类方法和静态方法类似。
case class Person(name:String, phoneNumber:String) // 请注意 object 和 class 可以同名。
object Dog {
Person("George", "1234") == Person("Kate", "1236") def allKnownBreeds = List("pitbull", "shepherd", "retriever")
def createDog(breed: String) = new Dog(breed)
// 模式匹配
val me = Person("George", "1234")
me match { case Person(name, number) => {
"We matched someone : " + name + ", phone : " + number }}
me match { case Person(name, number) => "Match : " + name; case _ => "Hm..." }
me match { case Person("George", number) => "Match"; case _ => "Hm..." }
me match { case Person("Kate", number) => "Match"; case _ => "Hm..." }
me match { case Person("Kate", _) => "Girl"; case Person("George", _) => "Boy" }
val kate = Person("Kate", "1234")
kate match { case Person("Kate", _) => "Girl"; case Person("George", _) => "Boy" }
// 正则表达式
val email = "(.*)@(.*)".r // 在字符串上调用 r 会使它变成一个正则表达式
val email(user, domain) = "henry@zkpr.com"
"mrbean@pyahoo.com" match {
case email(name, domain) => "I know your name, " + name
} }
// Case 类是有额外内建功能的类。Scala 初学者常遇到的问题之一便是何时用类
// 和何时用 case 类。界线比较模糊,但通常类倾向于封装,多态和行为。类中的值
// 的作用域一般为 private 只有方向是暴露的。case 类的主要目的是放置不可变
// 数据。它们通常只有几个方法,且方法几乎没有副作用。
case class Person(name: String, phoneNumber: String)
// 字符串 // 创造新实例,注意 case 类不需要使用 "new" 关键字
val george = Person("George", "1234")
val kate = Person("Kate", "4567")
"Scala 字符串被双引号包围" // // 使用 case 类,您可以轻松得到一些功能,像 getters:
'a' // Scala 字符 george.phoneNumber // => "1234"
'单引号的字符串不存在' // 错误
"字符串拥有通常的 Java 方法定义在其上".length
"字符串也有额外的 Scala 方法".reverse
// 参见: scala.collection.immutable.StringOps // 每个字段的相等性比较(无需覆盖 .equals
Person("George", "1234") == Person("Kate", "1236") // => false
println("ABCDEF".length) // 简单的拷贝方式
println("ABCDEF".substring(2, 6)) // otherGeorge == Person("george", "9876")
println("ABCDEF".replace("C", "3")) val otherGeorge = george.copy(phoneNumber = "9876")
val n = 45 // 还有很多。case 类同时可以用于模式匹配,接下来会看到。
println(s"We have $n apples")
val a = Array(11, 9, 6)
println(s"My second daughter is ${a(2-1)} years old")
// 一些字符需要被转义,举例来说,字符串中的双引号:
val a = "They stood outside the \"Rose and Crown\""
// 三个双引号使得字符串可以跨行并且可以包含引号(无需转义)
val html = """<form id="daform">
<p>Press belo', Joe</p>
| <input type="submit">
</form>"""
// 敬请期待 Traits
// 应用结果和组织
// import /////////////////////////////////////////////////
// 6. 模式匹配
/////////////////////////////////////////////////
// 模式匹配是一个强大和常用的 Scala 特性。这是用模式匹配一个 case 类的例子。
// 附注:不像其他语言, Scala 的 case 不需要 break 其他语言中 switch 语句的
// fall-through 现象不会发生。
def matchPerson(person: Person): String = person match {
// Then you specify the patterns:
case Person("George", number) => "We found George! His number is " + number
case Person("Kate", number) => "We found Kate! Her number is " + number
case Person(name, number) => "We matched someone : " + name + ", phone : " + number
}
val email = "(.*)@(.*)".r // 定义下一个例子会用到的正则
// 模式匹配看起来和 C语言家族的 switch 语句相似,但更为强大。
// Scala 中您可以匹配很多东西:
def matchEverything(obj: Any): String = obj match {
// 匹配值:
case "Hello world" => "Got the string Hello world"
// 匹配类型:
case x: Double => "Got a Double: " + x
// 匹配时指定条件
case x: Int if x > 10000 => "Got a pretty big number!"
// 像之前一样匹配 case 类:
case Person(name, number) => s"Got contact info for $name!"
// 匹配正则表达式:
case email(name, domain) => s"Got email address $name@$domain"
// 匹配元组:
case (a: Int, b: Double, c: String) => s"Got a tuple: $a, $b, $c"
// 匹配数据结构:
case List(1, b, c) => s"Got a list with three elements and starts with 1: 1, $b, $c"
// 模式可以嵌套
case List(List((1, 2,"YAY"))) => "Got a list of list of tuple"
}
// 事实上,你可以对任何有 "unapply" 方法的对象进行模式匹配。
// 这个特性如此强大以致于 Scala 允许定义一个函数作为模式匹配:
val patternFunc: Person => String = {
case Person("George", number) => s"George's number: $number"
case Person(name, number) => s"Random person's number: $number"
}
/////////////////////////////////////////////////
// 7. 函数式编程
/////////////////////////////////////////////////
// Scala 允许方法和函数作为其他方法和函数的参数和返回值。
val add10: Int => Int = _ + 10 // 一个接受一个 Int 类型参数并返回一个 Int 类型值的函数
List(1, 2, 3) map add10 // List(11, 12, 13) - add10 被应用到每一个元素
// 匿名函数可以被使用来代替有命名的函数:
List(1, 2, 3) map (x => x + 10)
// 如果匿名函数只有一个参数可以用下划线作为变量
List(1, 2, 3) map (_ + 10)
// 如果您所应用的匿名块和匿名函数都接受一个参数,那么你甚至可以省略下划线
List("Dom", "Bob", "Natalia") foreach println
// 组合子
// 译注: val sq: Int => Int = x => x * x
s.map(sq)
val sSquared = s. map(sq)
sSquared.filter(_ < 10)
sSquared.reduce (_+_)
// filter 函数接受一个 predicate (函数根据条件 A 返回 Boolean并选择
// 所有满足 predicate 的元素
List(1, 2, 3) filter (_ > 2) // List(3)
case class Person(name:String, age:Int)
List(
Person(name = "Dom", age = 23),
Person(name = "Bob", age = 30)
).filter(_.age > 25) // List(Person("Bob", 30))
// Scala 的 foreach 方法定义在某些集合中,接受一个函数并返回 Unit void 方法)
// 另请参见:
// http://www.scala-lang.org/api/current/index.html#scala.collection.IterableLike@foreach(f:A=>Unit):Unit
val aListOfNumbers = List(1, 2, 3, 4, 10, 20, 100)
aListOfNumbers foreach (x => println(x))
aListOfNumbers foreach println
// For 推导式
for { n <- s } yield sq(n)
val nSquared2 = 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
/* 注意,这些不是 for 循环for 循环的语义是‘重复’,然而 for 推导式定义
两个数据集合的关系。 */
/////////////////////////////////////////////////
// 8. 隐式转换
/////////////////////////////////////////////////
/* 警告 警告: 隐式转换是 Scala 中一套强大的特性,因此容易被滥用。
* Scala 初学者在理解它们的工作原理和最佳实践之前,应抵制使用它的诱惑。
* 我们加入这一章节仅因为它们在 Scala 的库中太过常见,导致没有用隐式转换的库
* 就不可能做有意义的事情。这章节主要让你理解和使用隐式转换,而不是自己声明。
*/
// 可以通过 "implicit" 声明任何值val, 函数,对象等)为隐式值,
// 请注意这些例子中我们用到第5部分的 Dog 类。
implicit val myImplicitInt = 100
implicit def myImplicitFunction(breed: String) = new Dog("Golden " + breed)
// implicit 关键字本身不改变值的行为,所以上面的值可以照常使用。
myImplicitInt + 2 // => 102
myImplicitFunction("Pitbull").breed // => "Golden Pitbull"
// 区别在于,当另一段代码“需要”隐式值时,这些值现在有资格作为隐式值。
// 一种情况是隐式函数参数。
def sendGreetings(toWhom: String)(implicit howMany: Int) =
s"Hello $toWhom, $howMany blessings to you and yours!"
// 如果提供值给 “howMany”函数正常运行
sendGreetings("John")(1000) // => "Hello John, 1000 blessings to you and yours!"
// 如果省略隐式参数,会传一个和参数类型相同的隐式值,
// 在这个例子中, 是 “myImplicitInt":
sendGreetings("Jane") // => "Hello Jane, 100 blessings to you and yours!"
// 隐式的函数参数使我们可以模拟其他函数式语言的 type 类type classes
// 它经常被用到所以有特定的简写。这两行代码是一样的:
def foo[T](implicit c: C[T]) = ...
def foo[T : C] = ...
// 编译器寻找隐式值另一种情况是你调用方法时
// obj.method(...)
// 但 "obj" 没有一个名为 "method" 的方法。这样的话,如果有一个参数类型为 A
// 返回值类型为 B 的隐式转换obj 的类型是 AB 有一个方法叫 "method" ,这样
// 转换就会被应用。所以作用域里有上面的 myImplicitFunction, 我们可以这样做:
"Retriever".breed // => "Golden Retriever"
"Sheperd".bark // => "Woof, woof!"
// 这里字符串先被上面的函数转换为 Dog 对象,然后调用相应的方法。
// 这是相当强大的特性,但再次提醒,请勿轻率使用。
// 事实上,当你定义上面的隐式函数时,编译器会作出警告,除非你真的了解
// 你正在做什么否则不要使用。
/////////////////////////////////////////////////
// 9. 杂项
/////////////////////////////////////////////////
// 导入类
import scala.collection.immutable.List import scala.collection.immutable.List
// Import 所有的子包 // 导入所有子包
import scala.collection.immutable._ import scala.collection.immutable._
// 在一条语句中 Import 多个类 // 一条语句导入多个类
import scala.collection.immutable.{List, Map} import scala.collection.immutable.{List, Map}
// 使用 '=>' 来重命名一个 import // 使用 => 对导入进行重命名
import scala.collection.immutable.{ List => ImmutableList } import scala.collection.immutable.{ List => ImmutableList }
// import 除了一些类的其它所有的类。下面的例子除去了 Map 类和 Set 类: // 导入所有类,排除其中一些。下面的语句排除了 Map 和 Set
import scala.collection.immutable.{Map => _, Set => _, _} import scala.collection.immutable.{Map => _, Set => _, _}
// 在 scala 源文件中,你的程序入口点使用一个拥有单一方法 main 的对象来定义: // 在 Scala 文件用 object 和单一的 main 方法定义程序入口:
object Application { object Application {
def main(args: Array[String]): Unit = { def main(args: Array[String]): Unit = {
// stuff goes here. // stuff goes here.
} }
} }
// 文件可以包含多个类和对象。由 scalac 来编译 // 文件可以包含多个 class 和 object用 scalac 编译源文件
// 输入和输出 // 输入和输出
// 一行一行读取文件 // 按行读文件
import scala.io.Source import scala.io.Source
for(line <- Source.fromPath("myfile.txt").getLines()) for(line <- Source.fromFile("myfile.txt").getLines())
println(line) println(line)
// 使用 Java 的 PrintWriter 来写文件 // 用 Java 的 PrintWriter 写文件
val writer = new PrintWriter("myfile.txt")
writer.write("Writing line for line" + util.Properties.lineSeparator)
writer.write("Another line here" + util.Properties.lineSeparator)
writer.close()
``` ```