summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--c.html.markdown678
-rw-r--r--es-es/c-es.html.markdown2
-rw-r--r--fr-fr/ruby-fr.html.markdown407
-rw-r--r--objective-c.html.markdown4
-rw-r--r--ruby-ecosystem.html.markdown2
-rw-r--r--ruby.html.markdown6
-rw-r--r--zh-cn/go-zh.html.markdown279
7 files changed, 1092 insertions, 286 deletions
diff --git a/c.html.markdown b/c.html.markdown
index 2b50efa0..8e16837c 100644
--- a/c.html.markdown
+++ b/c.html.markdown
@@ -1,23 +1,25 @@
---
-name: c
-category: language
-language: c
-filename: learnc.c
-contributors:
- - ["Adam Bard", "http://adambard.com/"]
+- name: c
+- category: language
+- language: c
+- filename: learnc.c
+- contributors:
+ - [Adam Bard](http://adambard.com/)
+ - [Árpád Goretity](http://twitter.com/H2CO3_iOS)
+
---
-Ah, C. Still the language of modern high-performance computing.
+Ah, C. Still **the** language of modern high-performance computing.
C is the lowest-level language most programmers will ever use, but
it more than makes up for it with raw speed. Just be aware of its manual
memory management and C will take you as far as you need to go.
```c
-// Single-line comments start with //
+// Single-line comments start with // - only available in C99 and later.
/*
-Multi-line comments look like this.
+Multi-line comments look like this. They work in C89 as well.
*/
// Import headers with #include
@@ -25,6 +27,17 @@ Multi-line comments look like this.
#include <stdio.h>
#include <string.h>
+// file names between <angle brackets> are headers from the C standard library.
+// They are searched for by the preprocessor in the system include paths
+// (usually /usr/lib on Unices, can be controlled with the -I<dir> option if you are using GCC or clang.)
+// For your own headers, use double quotes instead of angle brackets:
+#include "my_header.h"
+
+// The C preprocessor introduces an almost fully-featured macro language. It's useful, but
+// it can be confusing (and what's even worse, it can be misused). Read the
+// Wikipedia article on the C preprocessor for further information:
+// http://en.wikipedia.org/wiki/C_preprocessor
+
// Declare function signatures in advance in a .h file, or at the top of
// your .c file.
void function_1();
@@ -33,264 +46,347 @@ void function_2();
// Your program's entry point is a function called
// main with an integer return type.
int main() {
-
-// print output using printf, for "print formatted"
-// %d is an integer, \n is a newline
-printf("%d\n", 0); // => Prints 0
-// All statements must end with a semicolon
-
-///////////////////////////////////////
-// Types
-///////////////////////////////////////
-
-// You have to declare variables before using them. A variable declaration
-// requires you to specify its type; a variable's type determines its size
-// in bytes.
-
-// ints are usually 4 bytes
-int x_int = 0;
-
-// shorts are usually 2 bytes
-short x_short = 0;
-
-// chars are guaranteed to be 1 byte
-char x_char = 0;
-char y_char = 'y'; // Char literals are quoted with ''
-
-// longs are often 4 to 8 bytes; long longs are guaranteed to be at least
-// 64 bits
-long x_long = 0;
-long long x_long_long = 0;
-
-// floats are usually 32-bit floating point numbers
-float x_float = 0.0;
-
-// doubles are usually 64-bit floating-point numbers
-double x_double = 0.0;
-
-// Integral types may be unsigned. This means they can't be negative, but
-// the maximum value of an unsigned variable is greater than the maximum
-// signed value of the same size.
-unsigned char ux_char;
-unsigned short ux_short;
-unsigned int ux_int;
-unsigned long long ux_long_long;
-
-// Other than char, which is always 1 byte, these types vary in size depending
-// on your machine. sizeof(T) gives you the size of a variable with type T in
-// bytes so you can express the size of these types in a portable way.
-// For example,
-printf("%lu\n", sizeof(int)); // => 4 (on machines with 4-byte words)
-
-// Arrays must be initialized with a concrete size.
-char my_char_array[20]; // This array occupies 1 * 20 = 20 bytes
-int my_int_array[20]; // This array occupies 4 * 20 = 80 bytes
- // (assuming 4-byte words)
-
-
-// You can initialize an array to 0 thusly:
-char my_array[20] = {0};
-
-// Indexing an array is like other languages -- or,
-// rather, other languages are like C
-my_array[0]; // => 0
-
-// Arrays are mutable; it's just memory!
-my_array[1] = 2;
-printf("%d\n", my_array[1]); // => 2
-
-// Strings are just arrays of chars terminated by a NUL (0x00) byte,
-// represented in strings as the special character '\0'.
-// (We don't have to include the NUL byte in string literals; the compiler
-// inserts it at the end of the array for us.)
-char a_string[20] = "This is a string";
-printf("%s\n", a_string); // %s formats a string
-
-/*
-You may have noticed that a_string is only 16 chars long.
-Char #17 is the NUL byte.
-Chars #18, 19 and 20 have undefined values.
-*/
-
-printf("%d\n", a_string[16]); // => 0
-
-///////////////////////////////////////
-// Operators
-///////////////////////////////////////
-
-int i1 = 1, i2 = 2; // Shorthand for multiple declaration
-float f1 = 1.0, f2 = 2.0;
-
-// Arithmetic is straightforward
-i1 + i2; // => 3
-i2 - i1; // => 1
-i2 * i1; // => 2
-i1 / i2; // => 0 (0.5, but truncated towards 0)
-
-f1 / f2; // => 0.5, plus or minus epsilon
-
-// Modulo is there as well
-11 % 3; // => 2
-
-// Comparison operators are probably familiar, but
-// there is no boolean type in c. We use ints instead.
-// 0 is false, anything else is true. (The comparison
-// operators always return 0 or 1.)
-3 == 2; // => 0 (false)
-3 != 2; // => 1 (true)
-3 > 2; // => 1
-3 < 2; // => 0
-2 <= 2; // => 1
-2 >= 2; // => 1
-
-// Logic works on ints
-!3; // => 0 (Logical not)
-!0; // => 1
-1 && 1; // => 1 (Logical and)
-0 && 1; // => 0
-0 || 1; // => 1 (Logical or)
-0 || 0; // => 0
-
-// Bitwise operators!
-~0x0F; // => 0xF0 (bitwise negation)
-0x0F & 0xF0; // => 0x00 (bitwise AND)
-0x0F | 0xF0; // => 0xFF (bitwise OR)
-0x04 ^ 0x0F; // => 0x0B (bitwise XOR)
-0x01 << 1; // => 0x02 (bitwise left shift (by 1))
-0x02 >> 1; // => 0x01 (bitwise right shift (by 1))
-
-///////////////////////////////////////
-// Control Structures
-///////////////////////////////////////
-
-if (0) {
- printf("I am never run\n");
-} else if (0) {
- printf("I am also never run\n");
-} else {
- printf("I print\n");
-}
-
-// While loops exist
-int ii = 0;
-while (ii < 10) {
- printf("%d, ", ii++); // ii++ increments ii in-place, after using its value.
-} // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
-
-printf("\n");
-
-int kk = 0;
-do {
- printf("%d, ", kk);
-} while (++kk < 10); // ++kk increments kk in-place, before using its value
-// => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
-
-printf("\n");
-
-// For loops too
-int jj;
-for (jj=0; jj < 10; jj++) {
- printf("%d, ", jj);
-} // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
-
-printf("\n");
-
-///////////////////////////////////////
-// Typecasting
-///////////////////////////////////////
-
-// Every value in C has a type, but you can cast one value into another type
-// if you want.
-
-int x_hex = 0x01; // You can assign vars with hex literals
-
-// Casting between types will attempt to preserve their numeric values
-printf("%d\n", x_hex); // => Prints 1
-printf("%d\n", (short) x_hex); // => Prints 1
-printf("%d\n", (char) x_hex); // => Prints 1
-
-// Types will overflow without warning
-printf("%d\n", (char) 257); // => 1 (Max char = 255)
-
-// Integral types can be cast to floating-point types, and vice-versa.
-printf("%f\n", (float)100); // %f formats a float
-printf("%lf\n", (double)100); // %lf formats a double
-printf("%d\n", (char)100.0);
-
-///////////////////////////////////////
-// Pointers
-///////////////////////////////////////
-
-// A pointer is a variable declared to store a memory address. Its declaration will
-// also tell you the type of data it points to. You can retrieve the memory address
-// of your variables, then mess with them.
-
-int x = 0;
-printf("%p\n", &x); // Use & to retrieve the address of a variable
-// (%p formats a pointer)
-// => Prints some address in memory;
-
-
-// Pointers start with * in their declaration
-int *px, not_a_pointer; // px is a pointer to an int
-px = &x; // Stores the address of x in px
-printf("%p\n", px); // => Prints some address in memory
-printf("%d, %d\n", (int)sizeof(px), (int)sizeof(not_a_pointer));
-// => Prints "8, 4" on 64-bit system
-
-// To retreive the value at the address a pointer is pointing to,
-// put * in front to de-reference it.
-printf("%d\n", *px); // => Prints 0, the value of x, which is what px is pointing to the address of
-
-// You can also change the value the pointer is pointing to.
-// We'll have to wrap the de-reference in parenthesis because
-// ++ has a higher precedence than *.
-(*px)++; // Increment the value px is pointing to by 1
-printf("%d\n", *px); // => Prints 1
-printf("%d\n", x); // => Prints 1
-
-int x_array[20]; // Arrays are a good way to allocate a contiguous block of memory
-int xx;
-for (xx=0; xx<20; xx++) {
- x_array[xx] = 20 - xx;
-} // Initialize x_array to 20, 19, 18,... 2, 1
-
-// Declare a pointer of type int and initialize it to point to x_array
-int* x_ptr = x_array;
-// x_ptr now points to the first element in the array (the integer 20).
-// This works because arrays are actually just pointers to their first element.
-
-// Arrays are pointers to their first element
-printf("%d\n", *(x_ptr)); // => Prints 20
-printf("%d\n", x_array[0]); // => Prints 20
-
-// Pointers are incremented and decremented based on their type
-printf("%d\n", *(x_ptr + 1)); // => Prints 19
-printf("%d\n", x_array[1]); // => Prints 19
-
-// You can also dynamically allocate contiguous blocks of memory with the
-// standard library function malloc, which takes one integer argument
-// representing the number of bytes to allocate from the heap.
-int* my_ptr = (int*) malloc(sizeof(int) * 20);
-for (xx=0; xx<20; xx++) {
- *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx would also work here
-} // Initialize memory to 20, 19, 18, 17... 2, 1 (as ints)
-
-// Dereferencing memory that you haven't allocated gives
-// unpredictable results
-printf("%d\n", *(my_ptr + 21)); // => Prints who-knows-what?
-
-// When you're done with a malloc'd block of memory, you need to free it,
-// or else no one else can use it until your program terminates
-free(my_ptr);
-
-// Strings can be char arrays, but are usually represented as char
-// pointers:
-char* my_str = "This is my very own string";
-
-printf("%c\n", *my_str); // => 'T'
-
-function_1();
+ // print output using printf, for "print formatted"
+ // %d is an integer, \n is a newline
+ printf("%d\n", 0); // => Prints 0
+ // All statements must end with a semicolon
+
+ ///////////////////////////////////////
+ // Types
+ ///////////////////////////////////////
+
+ // You have to declare variables before using them. A variable declaration
+ // requires you to specify its type; a variable's type determines its size
+ // in bytes.
+
+ // ints are usually 4 bytes
+ int x_int = 0;
+
+ // shorts are usually 2 bytes
+ short x_short = 0;
+
+ // chars are guaranteed to be 1 byte
+ char x_char = 0;
+ char y_char = 'y'; // Char literals are quoted with ''
+
+ // longs are often 4 to 8 bytes; long longs are guaranteed to be at least
+ // 64 bits
+ long x_long = 0;
+ long long x_long_long = 0;
+
+ // floats are usually 32-bit floating point numbers
+ float x_float = 0.0;
+
+ // doubles are usually 64-bit floating-point numbers
+ double x_double = 0.0;
+
+ // Integral types may be unsigned. This means they can't be negative, but
+ // the maximum value of an unsigned variable is greater than the maximum
+ // signed value of the same size.
+ unsigned char ux_char;
+ unsigned short ux_short;
+ unsigned int ux_int;
+ unsigned long long ux_long_long;
+
+ // Other than char, which is always 1 byte (but not necessarily 8 bits!),
+ // these types vary in size depending on your machine and compiler.
+ // sizeof(T) gives you the size of a variable with type T in
+ // bytes so you can express the size of these types in a portable way.
+ // sizeof(obj) yields the size of an actual expression (variable, literal, etc.).
+ // For example,
+ printf("%zu\n", sizeof(int)); // => 4 (on most machines with 4-byte words)
+
+
+ // It's worth noting that if the argument of the `sizeof` operator is not a type but an expression,
+ // then its argument is not evaluated except VLAs (see below). Also, `sizeof()` is an operator, not a function,
+ // furthermore, the value it yields is a compile-time constant (except when used on VLAs, again.)
+ int a = 1;
+ size_t size = sizeof(a++); // a++ is not evaluated
+ printf("sizeof(a++) = %zu where a = %d\n", size, a);
+ // the above code prints "sizeof(a++) = 4 where a = 1" (on a usual 32-bit architecture)
+
+ // Arrays must be initialized with a concrete size.
+ char my_char_array[20]; // This array occupies 1 * 20 = 20 bytes
+ int my_int_array[20]; // This array occupies 4 * 20 = 80 bytes
+ // (assuming 4-byte words)
+
+
+ // You can initialize an array to 0 thusly:
+ char my_array[20] = {0};
+
+ // Indexing an array is like other languages -- or,
+ // rather, other languages are like C
+ my_array[0]; // => 0
+
+ // Arrays are mutable; it's just memory!
+ my_array[1] = 2;
+ printf("%d\n", my_array[1]); // => 2
+
+ // In C99 (and as an optional feature in C11), variable-length arrays (VLAs) can be declared as well.
+ // The size of such an array need not be a compile time constant:
+ printf("Enter the array size: "); // ask the user for an array size
+ char buf[0x100];
+ fgets(buf, sizeof buf, stdin);
+ size_t size = strtoul(buf, NULL, 10); // strtoul parses a string to an unsigned integer
+ int var_length_array[size]; // declare the VLA
+ printf("sizeof array = %zu\n", sizeof var_length_array);
+
+ // A possible outcome of this program may be:
+ Enter the array size: 10
+ sizeof array = 40
+
+ // Strings are just arrays of chars terminated by a NUL (0x00) byte,
+ // represented in strings as the special character '\0'.
+ // (We don't have to include the NUL byte in string literals; the compiler
+ // inserts it at the end of the array for us.)
+ char a_string[20] = "This is a string";
+ printf("%s\n", a_string); // %s formats a string
+
+ /*
+ You may have noticed that a_string is only 16 chars long.
+ Char #17 is the NUL byte.
+ Chars #18, 19 and 20 are 0 as well - if an initializer list (in this case, the string literal)
+ has less elements than the array it is initializing, then excess array elements are implicitly
+ initialized to zero. This is why int ar[10] = { 0 } works as expected intuitively.
+ */
+
+ printf("%d\n", a_string[16]); // => 0
+
+ // So string literals are strings enclosed within double quotes, but if we have characters
+ // between single quotes, that's a character literal.
+ // It's of type `int`, and *not* `char` (for historical reasons).
+ int cha = 'a'; // fine
+ char chb = 'a'; // fine too (implicit conversion from int to char - truncation)
+
+ ///////////////////////////////////////
+ // Operators
+ ///////////////////////////////////////
+
+ int i1 = 1, i2 = 2; // Shorthand for multiple declaration
+ float f1 = 1.0, f2 = 2.0;
+
+ // Arithmetic is straightforward
+ i1 + i2; // => 3
+ i2 - i1; // => 1
+ i2 * i1; // => 2
+ i1 / i2; // => 0 (0.5, but truncated towards 0)
+
+ f1 / f2; // => 0.5, plus or minus epsilon - floating-point numbers and calculations are not exact
+
+ // Modulo is there as well
+ 11 % 3; // => 2
+
+ // Comparison operators are probably familiar, but
+ // there is no boolean type in c. We use ints instead.
+ // (Or _Bool or bool in C99.)
+ // 0 is false, anything else is true. (The comparison
+ // operators always yield 0 or 1.)
+ 3 == 2; // => 0 (false)
+ 3 != 2; // => 1 (true)
+ 3 > 2; // => 1
+ 3 < 2; // => 0
+ 2 <= 2; // => 1
+ 2 >= 2; // => 1
+
+ // C is not Python - comparisons don't chain.
+ int a = 1;
+ // WRONG:
+ int between_0_and_2 = 0 < a < 2;
+ // Correct:
+ int between_0_and_2 = 0 < a && a < 2;
+
+ // Logic works on ints
+ !3; // => 0 (Logical not)
+ !0; // => 1
+ 1 && 1; // => 1 (Logical and)
+ 0 && 1; // => 0
+ 0 || 1; // => 1 (Logical or)
+ 0 || 0; // => 0
+
+ // Bitwise operators!
+ ~0x0F; // => 0xF0 (bitwise negation, "1's complement")
+ 0x0F & 0xF0; // => 0x00 (bitwise AND)
+ 0x0F | 0xF0; // => 0xFF (bitwise OR)
+ 0x04 ^ 0x0F; // => 0x0B (bitwise XOR)
+ 0x01 << 1; // => 0x02 (bitwise left shift (by 1))
+ 0x02 >> 1; // => 0x01 (bitwise right shift (by 1))
+
+ // Be careful when shifting signed integers - the following are all undefined behavior:
+ // - shifting into the sign bit of a signed integer (int a = 1 << 32)
+ // - left-shifting a negative number (int a = -1 << 2)
+ // - shifting by an offset which is more than or equal to the width of the type of the LHS:
+ // int a = 1 << 32; // UB if int is 32 bits wide
+
+ ///////////////////////////////////////
+ // Control Structures
+ ///////////////////////////////////////
+
+ if (0) {
+ printf("I am never run\n");
+ } else if (0) {
+ printf("I am also never run\n");
+ } else {
+ printf("I print\n");
+ }
+
+ // While loops exist
+ int ii = 0;
+ while (ii < 10) {
+ printf("%d, ", ii++); // ii++ increments ii in-place, after yielding its value ("postincrement").
+ } // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
+
+ printf("\n");
+
+ int kk = 0;
+ do {
+ printf("%d, ", kk);
+ } while (++kk < 10); // ++kk increments kk in-place, and yields the already incremented value ("preincrement")
+ // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
+
+ printf("\n");
+
+ // For loops too
+ int jj;
+ for (jj=0; jj < 10; jj++) {
+ printf("%d, ", jj);
+ } // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
+
+ printf("\n");
+
+ // branching with multiple choices: switch()
+ switch (some_integral_expression) {
+ case 0: // labels need to be integral *constant* epxressions
+ do_stuff();
+ break; // if you don't break, control flow falls over labels - you usually don't want that.
+ case 1:
+ do_something_else();
+ break;
+ default:
+ // if `some_integral_expression` didn't match any of the labels
+ fputs("error!\n", stderr);
+ exit(-1);
+ break;
+ }
+
+
+ ///////////////////////////////////////
+ // Typecasting
+ ///////////////////////////////////////
+
+ // Every value in C has a type, but you can cast one value into another type
+ // if you want (with some constraints).
+
+ int x_hex = 0x01; // You can assign vars with hex literals
+
+ // Casting between types will attempt to preserve their numeric values
+ printf("%d\n", x_hex); // => Prints 1
+ printf("%d\n", (short) x_hex); // => Prints 1
+ printf("%d\n", (char) x_hex); // => Prints 1
+
+ // Types will overflow without warning
+ printf("%d\n", (unsigned char) 257); // => 1 (Max char = 255 if char is 8 bits long)
+ // printf("%d\n", (unsigned char) 257); would be undefined behavior - `char' is usually signed
+ // on most modern systems, and signed integer overflow invokes UB.
+ // Also, for determining the maximal value of a `char`, a `signed char` and an `unisigned char`,
+ // respectively, use the CHAR_MAX, SCHAR_MAX and UCHAR_MAX macros from <limits.h>
+
+ // Integral types can be cast to floating-point types, and vice-versa.
+ printf("%f\n", (float)100); // %f formats a float
+ printf("%lf\n", (double)100); // %lf formats a double
+ printf("%d\n", (char)100.0);
+
+ ///////////////////////////////////////
+ // Pointers
+ ///////////////////////////////////////
+
+ // A pointer is a variable declared to store a memory address. Its declaration will
+ // also tell you the type of data it points to. You can retrieve the memory address
+ // of your variables, then mess with them.
+
+ int x = 0;
+ printf("%p\n", (void *)&x); // Use & to retrieve the address of a variable
+ // (%p formats an object pointer of type void *)
+ // => Prints some address in memory;
+
+
+ // Pointers start with * in their declaration
+ int *px, not_a_pointer; // px is a pointer to an int
+ px = &x; // Stores the address of x in px
+ printf("%p\n", (void *)px); // => Prints some address in memory
+ printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer));
+ // => Prints "8, 4" on a typical 64-bit system
+
+ // To retreive the value at the address a pointer is pointing to,
+ // put * in front to de-reference it.
+ // Note: yes, it may be confusing that '*' is used for _both_ declaring a pointer and dereferencing it.
+ printf("%d\n", *px); // => Prints 0, the value of x, which is what px is pointing to the address of
+
+ // You can also change the value the pointer is pointing to.
+ // We'll have to wrap the de-reference in parenthesis because
+ // ++ has a higher precedence than *.
+ (*px)++; // Increment the value px is pointing to by 1
+ printf("%d\n", *px); // => Prints 1
+ printf("%d\n", x); // => Prints 1
+
+ int x_array[20]; // Arrays are a good way to allocate a contiguous block of memory
+ int xx;
+ for (xx = 0; xx < 20; xx++) {
+ x_array[xx] = 20 - xx;
+ } // Initialize x_array to 20, 19, 18,... 2, 1
+
+ // Declare a pointer of type int and initialize it to point to x_array
+ int* x_ptr = x_array;
+ // x_ptr now points to the first element in the array (the integer 20).
+ // This works because arrays often decay into pointers to their first element.
+ // For example, when an array is passed to a function or is assigned to a pointer,
+ // it decays into (implicitly converted to) a pointer.
+ // Exceptions: when the array is the argument of the `&` (address-od) operator:
+ int arr[10];
+ int (*ptr_to_arr)[10] = &arr; // &arr is NOT of type `int *`! It's of type "pointer to array" (of ten `int`s).
+ // or when the array is a string literal used for initializing a char array:
+ char arr[] = "foobarbazquirk";
+ // or when it's the argument of the `sizeof` or `alignof` operator:
+ int arr[10];
+ int *ptr = arr; // equivalent with int *ptr = &arr[0];
+ printf("%zu %zu\n", sizeof arr, sizeof ptr); // probably prints "40, 4" or "40, 8"
+
+
+ // Pointers are incremented and decremented based on their type
+ // (this is called pointer arithmetic)
+ printf("%d\n", *(x_ptr + 1)); // => Prints 19
+ printf("%d\n", x_array[1]); // => Prints 19
+
+ // You can also dynamically allocate contiguous blocks of memory with the
+ // standard library function malloc, which takes one argument of type size_t
+ // representing the number of bytes to allocate (usually from the heap, although this
+ // may not be true on e. g. embedded systems - the C standard says nothing about it).
+ int *my_ptr = malloc(sizeof(*my_ptr) * 20);
+ for (xx = 0; xx < 20; xx++) {
+ *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx would also work here, and it's also more readable
+ } // Initialize memory to 20, 19, 18, 17... 2, 1 (as ints)
+
+ // Dereferencing memory that you haven't allocated gives
+ // "unpredictable results" - the program is said to invoke "undefined behavior"
+ printf("%d\n", *(my_ptr + 21)); // => Prints who-knows-what? It may even crash.
+
+ // When you're done with a malloc'd block of memory, you need to free it,
+ // or else no one else can use it until your program terminates
+ // (this is called a "memory leak"):
+ free(my_ptr);
+
+ // Strings are arrays of char, but they are usually represented as a
+ // pointer-to-char (which is a pointer to the first element of the array).
+ // It's good practice to use `const char *' when referring to a string literal,
+ // since string literals shall not be modified (i. e. "foo"[0] = 'a' is ILLEGAL.)
+ const char *my_str = "This is my very own string literal";
+ printf("%c\n", *my_str); // => 'T'
+
+ // This is not the case if the string is an array (potentially initialized with a string literal)
+ // that resides in writable memory, as in:
+ char foo[] = "foo";
+ foo[0] = 'a'; // this is legal, foo now contains "aoo"
+
+ function_1();
} // end main function
///////////////////////////////////////
@@ -300,7 +396,8 @@ function_1();
// Function declaration syntax:
// <return type> <function name>(<args>)
-int add_two_ints(int x1, int x2){
+int add_two_ints(int x1, int x2)
+{
return x1 + x2; // Use return to return a value
}
@@ -312,10 +409,12 @@ Example: in-place string reversal
*/
// A void function returns no value
-void str_reverse(char* str_in){
+void str_reverse(char *str_in)
+{
char tmp;
- int ii=0, len = strlen(str_in); // Strlen is part of the c standard library
- for(ii=0; ii<len/2; ii++){
+ int ii = 0;
+ size_t len = strlen(str_in); // `strlen()` is part of the c standard library
+ for (ii = 0; ii < len / 2; ii++) {
tmp = str_in[ii];
str_in[ii] = str_in[len - ii - 1]; // ii-th char from end
str_in[len - ii - 1] = tmp;
@@ -336,15 +435,20 @@ printf("%s\n", c); // => ".tset a si sihT"
typedef int my_type;
my_type my_type_var = 0;
-// Structs are just collections of data
+// Structs are just collections of data, the members are allocated sequentially, in the order they are written:
struct rectangle {
int width;
int height;
};
+// it's generally not true that sizeof(struct rectangle) == sizeof(int) + sizeof(int) due to
+// potential padding between the structure members (this is for alignment reasons. Probably won't
+// happen if all members are of the same type, but watch out!
+// See http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member
+// for further information.
-void function_1(){
-
+void function_1()
+{
struct rectangle my_rec;
// Access struct members with .
@@ -352,22 +456,29 @@ void function_1(){
my_rec.height = 20;
// You can declare pointers to structs
- struct rectangle* my_rec_ptr = &my_rec;
+ struct rectangle *my_rec_ptr = &my_rec;
// Use dereferencing to set struct pointer members...
(*my_rec_ptr).width = 30;
- // ... or use the -> shorthand
+ // ... or even better: prefer the -> shorthand for the sake of readability
my_rec_ptr->height = 10; // Same as (*my_rec_ptr).height = 10;
}
// You can apply a typedef to a struct for convenience
typedef struct rectangle rect;
-int area(rect r){
+int area(rect r)
+{
return r.width * r.height;
}
+// if you have large structs, you can pass them "by pointer" to avoid copying the whole struct:
+int area(const rect *r)
+{
+ return r->width * r->height;
+}
+
///////////////////////////////////////
// Function pointers
///////////////////////////////////////
@@ -379,10 +490,11 @@ However, definition syntax may be initially confusing.
Example: use str_reverse from a pointer
*/
-void str_reverse_through_pointer(char * str_in) {
+void str_reverse_through_pointer(char *str_in) {
// Define a function pointer variable, named f.
void (*f)(char *); // Signature should exactly match the target function.
f = &str_reverse; // Assign the address for the actual function (determined at runtime)
+ // f = str_reverse; would work as well - functions decay into pointers, similar to arrays
(*f)(str_in); // Just calling the function through the pointer
// f(str_in); // That's an alternative but equally valid syntax for calling it.
}
@@ -403,7 +515,15 @@ typedef void (*my_fnp_type)(char *);
## Further Reading
Best to find yourself a copy of [K&R, aka "The C Programming Language"](https://en.wikipedia.org/wiki/The_C_Programming_Language)
+It is *the* book about C, written by the creators of C. Be careful, though - it's ancient and it contains some
+inaccuracies (well, ideas that are not considered good anymore) or now-changed practices.
+
+Another good resource is [Learn C the hard way](http://c.learncodethehardway.org/book/).
+
+If you have a question, read the [compl.lang.c Frequently Asked Questions](http://c-faq.com).
-Another good resource is [Learn C the hard way](http://c.learncodethehardway.org/book/)
+It's very important to use proper spacing, indentation and to be consistent with your coding style in general.
+Readable code is better than clever code and fast code. For a good, sane coding style to adopt, see the
+[Linux kernel coding stlye](https://www.kernel.org/doc/Documentation/CodingStyle).
Other than that, Google is your friend.
diff --git a/es-es/c-es.html.markdown b/es-es/c-es.html.markdown
index b109f761..5d3aae0c 100644
--- a/es-es/c-es.html.markdown
+++ b/es-es/c-es.html.markdown
@@ -284,7 +284,7 @@ for (xx=0; xx<20; xx++) {
// impredecibles
printf("%d\n", *(my_ptr + 21)); // => Prints who-knows-what?
-// Cuando hallas acabado con el bloque de memoría malloc, necesitas
+// Cuando hayas acabado con el bloque de memoría malloc, necesitas
// liberarlo o sino nadie más podrá usarlo hasta que tu programa se cierre
free(my_ptr);
diff --git a/fr-fr/ruby-fr.html.markdown b/fr-fr/ruby-fr.html.markdown
new file mode 100644
index 00000000..5efb2f3c
--- /dev/null
+++ b/fr-fr/ruby-fr.html.markdown
@@ -0,0 +1,407 @@
+---
+language: ruby
+filename: learnruby-fr.rb
+contributors:
+ - ["David Underwood", "http://theflyingdeveloper.com"]
+ - ["Joel Walden", "http://joelwalden.net"]
+ - ["Luke Holder", "http://twitter.com/lukeholder"]
+ - ["Tristan Hume", "http://thume.ca/"]
+ - ["Nick LaMuro", "https://github.com/NickLaMuro"]
+translators:
+ - ["Geoffrey Roguelon", "https://github.com/GRoguelon"]
+ - ["Nami-Doc", "https://github.com/Nami-Doc"]
+lang: fr-fr
+---
+
+```ruby
+# Ceci est un commentaire
+
+=begin
+Ceci est un commentaire multiligne
+Personne ne les utilise
+Vous devriez en faire de même
+=end
+
+# Tout d'abord : Tout est un objet.
+
+# Les nombres sont des objets
+
+3.class #=> Fixnum
+
+3.to_s #=> "3"
+
+# Les opérateurs de base
+1 + 1 #=> 2
+8 - 1 #=> 7
+10 * 2 #=> 20
+35 / 5 #=> 7
+
+# Les opérateurs sont juste des raccourcis
+# pour appeler une méthode sur un objet
+1.+(3) #=> 4
+10.* 5 #=> 50
+
+# Les valeurs spéciales sont des objets
+nil # Nul
+true # Vrai
+false # Faux
+
+nil.class #=> NilClass
+true.class #=> TrueClass
+false.class #=> FalseClass
+
+# Égalité
+1 == 1 #=> true
+2 == 1 #=> false
+
+# Inégalité
+1 != 1 #=> false
+2 != 1 #=> true
+!true #=> false
+!false #=> true
+
+# à part false lui-même, nil est la seule autre valeur 'false'
+
+!nil #=> true
+!false #=> true
+!0 #=> false
+
+# Plus de comparaisons
+1 < 10 #=> true
+1 > 10 #=> false
+2 <= 2 #=> true
+2 >= 2 #=> true
+
+# Les chaînes de caractères sont des objets
+
+'Je suis une chaîne de caractères'.class #=> String
+"Je suis également une chaîne de caractères".class #=> String
+
+placeholder = "utiliser l'interpolation de chaîne de caractères"
+"Je peux #{placeholder} quand j'utilise les guillemets"
+#=> "Je peux utiliser l'interpolation de chaîne de caractères quand j'utilise les guillemets"
+
+# Affichez un message
+puts "J'affiche à l'écran!"
+
+# Variables
+x = 25 #=> 25
+x #=> 25
+
+# Notez que l'affectation retourne la valeur affectée.
+# Cela signifie que vous pouvez affecter plusieurs fois de suite :
+
+x = y = 10 #=> 10
+x #=> 10
+y #=> 10
+
+# Par convention, utilisez la notation underscore
+# pour nommer les variables
+snake_case = true
+
+# Utilisez des noms de variable explicites
+path_to_project_root = '/nom/correct/'
+path = '/mauvais/nom/'
+
+# Symboles (aussi des objets)
+# Les symboles sont immuables, constants,
+# réutilisables et représentés en interne
+# par une valeur entière. Ils sont souvent
+# utilisés à la place des chaînes de caractères
+# pour transmettre efficacement des valeurs
+# spécifiques ou significatives
+
+:pending.class #=> Symbol
+
+status = :pending
+
+status == :pending #=> true
+
+status == 'pending' #=> false
+
+status == :approved #=> false
+
+# Tableaux
+
+# Ceci est un tableau
+array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]
+
+# Les tableaux contiennent différents types d'élément.
+
+[1, "hello", false] #=> [1, "hello", false]
+
+# Les tableaux peuvent être indexés
+# Du début
+array[0] #=> 1
+array[12] #=> nil
+
+# Comme les opérateurs, la syntaxe [var] est juste un raccourci
+# pour appeler la méthode [] d'un objet
+array.[] 0 #=> 1
+array.[] 12 #=> nil
+
+# Depuis la fin
+array[-1] #=> 5
+
+# Avec un index de début et de fin
+array[2, 4] #=> [3, 4, 5]
+
+# Ou avec un intervalle
+array[1..3] #=> [2, 3, 4]
+
+# Ajoutez un élément au tableau comme ceci
+array << 6 #=> [1, 2, 3, 4, 5, 6]
+
+# Les Hash sont des dictionnaires Ruby contenant des paires de clé/valeur.
+# Les Hash sont délimitées par des accolades :
+hash = {'color' => 'green', 'number' => 5}
+
+hash.keys #=> ['color', 'number']
+
+# Les Hash retournent la valeur
+# en utilisant la clé associée à la valeur :
+hash['color'] #=> 'green'
+hash['number'] #=> 5
+
+# Recherchez une clé inexistante dans une Hash retourne nil :
+hash['nothing here'] #=> nil
+
+# Depuis Ruby 1.9, Une syntaxe spécifique est apparue en utilisant les symboles comme clés :
+
+new_hash = { defcon: 3, action: true}
+
+new_hash.keys #=> [:defcon, :action]
+
+# Astuce : Les tableaux et les Hash sont dénombrables
+# Ils partagent un certain nombre de méthodes pratiques
+# telle que each, map, count, etc...
+
+# Structures de contrôle
+
+if true
+ "si instruction"
+elsif false
+ "autrement si, facultatif"
+else
+ "autrement, également facultatif"
+end
+
+for compteur in 1..5
+ puts "itération #{compteur}"
+end
+#=> itération 1
+#=> itération 2
+#=> itération 3
+#=> itération 4
+#=> itération 5
+
+# CEPENDANT, l'usage de la boucle for est très rare.
+# À la place, utilisez la méthode "each"
+# et passez lui un bloc de code.
+# Un bloc de code est un ensemble d'instructions que vous pouvez passer à une methode comme "each".
+# Les blocs sont similaires aux lambdas, les fonctions anonymes ou les closures dans d'autres langages.
+#
+# La méthode "each" exécute le bloc de code pour chaque élément de l'intervalle d'éléments.
+# Le bloc de code passe un paramètre compteur.
+# Appelez la méthode "each" avec un bloc de code comme ceci :
+
+(1..5).each do |compteur|
+ puts "itération #{compteur}"
+end
+#=> itération 1
+#=> itération 2
+#=> itération 3
+#=> itération 4
+#=> itération 5
+
+# Vous pouvez également mettre un bloc de code entre accolades :
+(1..5).each {|compteur| puts "itération #{compteur}"}
+
+# Le contenu des structures de données peut être parcouru
+# en utilisant la méthode each.
+array.each do |element|
+ puts "#{element} est une partie du tableau"
+end
+hash.each do |cle, valeur|
+ puts "#{cle} est #{valeur}"
+end
+
+compteur = 1
+while compteur <= 5 do
+ puts "itération #{compteur}"
+ compteur += 1
+end
+#=> itération 1
+#=> itération 2
+#=> itération 3
+#=> itération 4
+#=> itération 5
+
+grade = 'B'
+
+case grade
+when 'A'
+ puts "Excellent"
+when 'B'
+ puts "Plus de chance la prochaine fois"
+when 'C'
+ puts "Vous pouvez faire mieux"
+when 'D'
+ puts "C'est pas terrible"
+when 'F'
+ puts "Vous avez échoué!"
+else
+ puts "Sytème de notation alternatif"
+end
+
+# Fonctions
+
+def double(x)
+ x * 2
+end
+
+# Les fonctions (et tous les blocs de code) retournent
+# implicitement la valeur de la dernière instruction évaluée
+double(2) #=> 4
+
+# Les paranthèses sont facultative
+# lorsqu'il n'y a pas d'ambiguïté sur le résultat
+double 3 #=> 6
+
+double double 3 #=> 12
+
+def sum(x,y)
+ x + y
+end
+
+# Les paramètres de méthode sont séparés par des virgules
+sum 3, 4 #=> 7
+
+sum sum(3,4), 5 #=> 12
+
+# yield
+# Toutes les méthodes ont un argument facultatif et implicite
+# de type bloc de code
+# il peut être appelé avec le mot clé 'yield'
+
+def surround
+ puts "{"
+ yield
+ puts "}"
+end
+
+surround { puts 'Bonjour tout le monde' }
+
+# {
+# Bonjour tout le monde
+# }
+
+
+# Définissez une classe avec le mot clé 'class'
+class Humain
+
+ # Une variable de classe
+ # est partagée par toutes les instances de cette classe.
+ @@espece = "H. sapiens"
+
+ # Constructeur de classe
+ def initialize(nom, age = 0)
+ # Affectez l'argument à la variable d'instance 'nom'
+ # pour la durée de vie de l'instance de cette classe
+ @nom = nom
+ # Si le paramètre 'age' est absent,
+ # la valeur par défaut définie dans la liste des arguments sera utilisée.
+ @age = age
+ end
+
+ # Une simple méthode setter
+ def nom=(nom)
+ @nom = nom
+ end
+
+ # Une simple méthode getter
+ def nom
+ @nom
+ end
+
+ # Une méthode de classe utilise le mot clé 'self'
+ # pour se distinguer de la méthode d'instance.
+ # La méthode sera alors accessible à partir de la classe
+ # et non pas de l'instance.
+ def self.say(msg)
+ puts "#{msg}"
+ end
+
+ def species
+ @@species
+ end
+
+end
+
+
+# Instanciez une classe
+jim = Humain.new("Jim Halpert")
+
+dwight = Humain.new("Dwight K. Schrute")
+
+# Appelez quelques méthodes
+jim.espece #=> "H. sapiens"
+jim.nom #=> "Jim Halpert"
+jim.nom = "Jim Halpert II" #=> "Jim Halpert II"
+jim.nom #=> "Jim Halpert II"
+dwight.espece #=> "H. sapiens"
+dwight.nom #=> "Dwight K. Schrute"
+
+# Appelez la méthode de classe
+Humain.say("Hi") #=> "Hi"
+
+# Les classes sont également des objets en Ruby.
+# Par conséquent, les classes peuvent avoir des variables d'instance.
+# Les variables de classe sont partagées parmi
+# la classe et ses descendants.
+
+# Classe parente
+class Humain
+ @@foo = 0
+
+ def self.foo
+ @@foo
+ end
+
+ def self.foo=(valeur)
+ @@foo = valeur
+ end
+end
+
+# Classe fille
+class Travailleur < Humain
+end
+
+Humain.foo # 0
+Travailleur.foo # 0
+
+Humain.foo = 2 # 2
+Travailleur.foo # 2
+
+# Les variables d'instance de classe ne sont pas partagées
+# avec les classes héritées.
+
+class Humain
+ @bar = 0
+
+ def self.bar
+ @bar
+ end
+
+ def self.bar=(valeur)
+ @bar = valeur
+ end
+end
+
+class Docteur < Humain
+end
+
+Humain.bar # 0
+Docteur.bar # nil
+
+```
diff --git a/objective-c.html.markdown b/objective-c.html.markdown
index 2b1b3c67..b92e3218 100644
--- a/objective-c.html.markdown
+++ b/objective-c.html.markdown
@@ -160,7 +160,7 @@ int main (int argc, const char * argv[])
int jj;
for (jj=0; jj < 4; jj++)
{
- NSLog(@"%d,", ii++);
+ NSLog(@"%d,", jj++);
} // => prints "0,"
// "1,"
// "2,"
@@ -256,7 +256,7 @@ int main (int argc, const char * argv[])
}
// Constructors are a way of creating classes
-// This is a default constructor which is call when the object is creating
+// This is a default constructor which is called when the object is creating
- (id)init
{
if ((self = [super init]))
diff --git a/ruby-ecosystem.html.markdown b/ruby-ecosystem.html.markdown
index cae55cd3..54c1d178 100644
--- a/ruby-ecosystem.html.markdown
+++ b/ruby-ecosystem.html.markdown
@@ -81,7 +81,7 @@ development.
Less mature/compatible:
* Topaz - Written in RPython (using the PyPy toolchain), Topaz is fairly young
- and not yet compatable. It shows promise to be a high-performance ruby
+ and not yet compatible. It shows promise to be a high-performance ruby
implementation.
* IronRuby - Written in C# targeting the .NET platform, work on IronRuby seems
to have stopped since Microsoft pulled their support.
diff --git a/ruby.html.markdown b/ruby.html.markdown
index 19f2ec86..3a233d98 100644
--- a/ruby.html.markdown
+++ b/ruby.html.markdown
@@ -36,7 +36,7 @@ You shouldn't either
# Arithmetic is just syntactic sugar
# for calling a method on an object
1.+(3) #=> 4
-10.* 5 #=> 50
+10.* 5 #=> 50
# Special values are objects
nil # Nothing to see here
@@ -242,7 +242,7 @@ when 'D'
puts "Scraping through"
when 'F'
puts "You failed!"
-else
+else
puts "Alternative grading system, eh?"
end
@@ -252,7 +252,7 @@ def double(x)
x * 2
end
-# Functions (and all blocks) implcitly return the value of the last statement
+# Functions (and all blocks) implicitly return the value of the last statement
double(2) #=> 4
# Parentheses are optional where the result is unambiguous
diff --git a/zh-cn/go-zh.html.markdown b/zh-cn/go-zh.html.markdown
new file mode 100644
index 00000000..25fd1f03
--- /dev/null
+++ b/zh-cn/go-zh.html.markdown
@@ -0,0 +1,279 @@
+---
+名字:Go
+分类:编程语言
+文件名:learngo.go
+贡献者:
+ - ["Sonia Keys", "https://github.com/soniakeys"]
+ - ["pantaovay", "https://github.com/pantaovay"]
+---
+
+发明Go语言是出于更好地完成工作的需要。Go不是计算机科学的最新发展潮流,但它却提供了解决现实问题的最新最快的方法。
+
+Go拥有命令式语言的静态类型,编译很快,执行也很快,同时加入了对于目前多核CPU的并发计算支持,也有相应的特性来实现大规模编程。
+
+Go语言有非常棒的标准库,还有一个充满热情的社区。
+
+```Go
+// 单行注释
+/* 多行
+ 注释 */
+
+// 导入包的子句在每个源文件的开头。
+// Main比较特殊,它用来声明可执行文件,而不是一个库。
+package main
+
+// Import语句声明了当前文件引用的包。
+import (
+ "fmt" // Go语言标准库中的包
+ "net/http" // 一个web服务器包
+ "strconv" // 字符串转换
+)
+
+//函数声明:Main是程序执行的入口。不管你喜欢还是不喜欢,反正G就用了花括号来包住函数体。
+func main() {
+ // 往标准输出打印一行。
+ // 用包名fmt限制打印函数。
+ fmt.Println("Hello world!")
+
+ // 调用当前包的另一个函数。
+ beyondHello()
+}
+
+// 函数可以在括号里加参数。
+// 如果没有参数的话,也需要一个空括号。
+func beyondHello() {
+ var x int // 变量声明,变量必须在使用之前声明。
+ x = 3 // 变量赋值。
+ // 可以用:=来偷懒,它自动把变量类型、声明和赋值都搞定了。
+ y := 4
+ sum, prod := learnMultiple(x, y) // 多个返回变量的函数
+ fmt.Println("sum:", sum, "prod:", prod) // 简单输出
+ learnTypes() // 少于y分钟,学的更多!
+}
+
+// 多变量和多返回值的函数
+func learnMultiple(x, y int) (sum, prod int) {
+ return x + y, x * y // 返回两个值
+}
+
+// 内置变量类型和关键词
+func learnTypes() {
+ // 短声明给你所想。
+ s := "Learn Go!" // String类型
+
+ s2 := `A "raw" string literal
+can include line breaks.` // 同样是String类型
+
+ // 非ascii字符。Go使用UTF-8编码。
+ g := 'Σ' // rune类型,uint32的别名,使用UTF-8编码
+
+ f := 3.14195 // float64类型,IEEE-754 64位浮点数
+ c := 3 + 4i // complex128类型,内部使用两个float64表示
+
+ // Var变量可以直接初始化。
+ var u uint = 7 // unsigned 无符号变量,但是实现依赖int型变量的长度
+ var pi float32 = 22. / 7
+
+ // 字符转换
+ n := byte('\n') // byte是uint8的别名
+
+ // 数组类型编译的时候大小固定。
+ var a4 [4] int // 有4个int变量的数组,初始为0
+ a3 := [...]int{3, 1, 5} // 有3个int变量的数组,同时进行了初始化
+
+ // Slice 有动态大小。Array和Slice各有千秋,但是使用slice的地方更多些。
+ s3 := []int{4, 5, 9} // 和a3相比,这里没有省略号
+ s4 := make([]int, 4) // 分配一个有4个int型变量的slice,全部被初始化为0
+
+ var d2 [][]float64 // 声明而已,什么都没有分配
+ bs := []byte("a slice") // 类型转换的语法
+
+ p, q := learnMemory() // 声明p,q为int型变量的指针
+ fmt.Println(*p, *q) // * 取值
+
+ // Map是动态可增长关联数组,和其他语言中的hash或者字典相似。
+ m := map[string]int{"three": 3, "four": 4}
+ m["one"] = 1
+
+ // 在Go语言中未使用的变量在编译的时候会报错,而不是warning。
+ // 下划线 _ 可以使你“使用”一个变量,但是丢弃它的值。
+ _,_,_,_,_,_,_,_,_ = s2, g, f, u, pi, n, a3, s4, bs
+ // 输出变量
+ fmt.Println(s, c, a4, s3, d2, m)
+
+ learnFlowControl() // 回到流程控制
+}
+
+// Go全面支持垃圾回收。Go有指针,但是不支持指针运算。
+// 你会因为空指针而犯错,但是不会因为增加指针而犯错。
+func learnMemory() (p, q *int) {
+ // 返回int型变量指针p和q
+ p = new(int) // 内置函数new分配内存
+ // 自动将分配的int赋值0,p不再是空的了。
+ s := make([]int, 20) // 给20个int变量分配一块内存
+ s[3] = 7 // 赋值
+ r := -2 // 声明另一个局部变量
+ return &s[3], &r // & 取址
+}
+
+func expensiveComputation() int {
+ return 1e6
+}
+
+func learnFlowControl() {
+ // If需要花括号,括号就免了
+ if true {
+ fmt.Println("told ya")
+ }
+ // 用go fmt 命令可以帮你格式化代码,所以不用怕被人吐槽代码风格了,也不用容忍被人的代码风格。
+ if false {
+ // pout
+ } else {
+ // gloat
+ }
+ // 如果太多嵌套的if语句,推荐使用switch
+ x := 1
+ switch x {
+ case 0:
+ case 1:
+ // 隐式调用break语句,匹配上一个即停止
+ case 2:
+ // 不会运行
+ }
+ // 和if一样,for也不用括号
+ for x := 0; x < 3; x++ { // ++ 自增
+ fmt.Println("iteration", x)
+ }
+ // x在这里还是1。为什么?
+
+ // for 是go里唯一的循环关键字,不过它有很多变种
+ for { // 无限循环
+ break // 骗你的
+ continue // 不会运行的
+ }
+ // 和for一样,if中的:=先给y赋值,然后再和x作比较。
+ if y := expensiveComputation(); y > x {
+ x = y
+ }
+ // 闭包函数
+ xBig := func() bool {
+ return x > 100 // x是上面声明的变量引用
+ }
+ fmt.Println("xBig:", xBig()) // true (上面把y赋给x了)
+ x /= 1e5 // x变成10
+ fmt.Println("xBig:", xBig()) // 现在是false
+
+ // 当你需要goto的时候,你会爱死它的!
+ goto love
+love:
+
+ learnInterfaces() // 好东西来了!
+}
+
+// 定义Stringer为一个接口类型,有一个方法String
+type Stringer interface {
+ String() string
+}
+
+// 定义pair为一个结构体,有x和y两个int型变量。
+type pair struct {
+ x, y int
+}
+
+// 定义pair类型的方法,实现Stringer接口。
+func (p pair) String() string { // p被叫做“接收器”
+ // Sprintf是fmt包中的另一个公有函数。
+ // 用 . 调用p中的元素。
+ return fmt.Sprintf("(%d, %d)", p.x, p.y)
+}
+
+func learnInterfaces() {
+ // 花括号用来定义结构体变量,:=在这里将一个结构体变量赋值给p。
+ p := pair{3, 4}
+ fmt.Println(p.String()) // 调用pair类型p的String方法
+ var i Stringer // 声明i为Stringer接口类型
+ i = p // 有效!因为p实现了Stringer接口(类似java中的塑型)
+ // 调用i的String方法,输出和上面一样
+ fmt.Println(i.String())
+
+ // fmt包中的Println函数向对象要它们的string输出,实现了String方法就可以这样使用了。(类似java中的序列化)
+ fmt.Println(p) // 输出和上面一样,自动调用String函数。
+ fmt.Println(i) // 输出和上面一样。
+
+ learnErrorHandling()
+}
+
+func learnErrorHandling() {
+ // ", ok"用来判断有没有正常工作
+ m := map[int]string{3: "three", 4: "four"}
+ if x, ok := m[1]; !ok { // ok 为false,因为m中没有1
+ fmt.Println("no one there")
+ } else {
+ fmt.Print(x) // 如果x在map中的话,x就是那个值喽。
+ }
+ // 错误可不只是ok,它还可以给出关于问题的更多细节。
+ if _, err := strconv.Atoi("non-int"); err != nil { // _ discards value
+ // 输出"strconv.ParseInt: parsing "non-int": invalid syntax"
+ fmt.Println(err)
+ }
+ // 待会再说接口吧。同时,
+ learnConcurrency()
+}
+
+// c是channel类型,一个并发安全的通信对象。
+func inc(i int, c chan int) {
+ c <- i + 1 // <-把右边的发送到左边的channel。
+}
+
+// 我们将用inc函数来并发地增加一些数字。
+func learnConcurrency() {
+ // 用make来声明一个slice,make会分配和初始化slice,map和channel。
+ c := make(chan int)
+ // 用go关键字开始三个并发的goroutine,如果机器支持的话,还可能是并行执行。三个都被发送到同一个channel。
+ go inc(0, c) // go is a statement that starts a new goroutine.
+ go inc(10, c)
+ go inc(-805, c)
+ // 从channel中独处结果并打印。
+ // 打印出什么东西是不可预知的。
+ fmt.Println(<-c, <-c, <-c) // channel在右边的时候,<-是接收操作。
+
+ cs := make(chan string) // 操作string的channel
+ cc := make(chan chan string) // 操作channel的channel
+ go func() { c <- 84 }() // 开始一个goroutine来发送一个新的数字
+ go func() { cs <- "wordy" }() // 发送给cs
+ // Select类似于switch,但是每个case包括一个channel操作。它随机选择一个准备好通讯的case。
+ select {
+ case i := <-c: // 从channel接收的值可以赋给其他变量
+ fmt.Println("it's a", i)
+ case <-cs: // 或者直接丢弃
+ fmt.Println("it's a string")
+ case <-cc: // 空的,还没作好通讯的准备
+ fmt.Println("didn't happen.")
+ }
+ // 上面c或者cs的值被取到,其中一个goroutine结束,另外一个保持阻塞。
+
+ learnWebProgramming() // Go很适合web编程,我知道你也想学!
+}
+
+// http包中的一个简单的函数就可以开启web服务器。
+func learnWebProgramming() {
+ // ListenAndServe第一个参数指定了监听端口,第二个参数是一个接口,特定是http.Handler。
+ err := http.ListenAndServe(":8080", pair{})
+ fmt.Println(err) // 不要无视错误。
+}
+
+// 使pair实现http.Handler接口的ServeHTTP方法。
+func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ // 使用http.ResponseWriter返回数据
+ w.Write([]byte("You learned Go in Y minutes!"))
+}
+```
+
+## 更进一步
+
+Go的根源在[Go官方网站](http://golang.org/)。
+在那里你可以学习入门教程,通过浏览器交互式地学习,而且可以读到很多东西。
+
+强烈推荐阅读语言定义部分,很简单而且很简洁!(as language definitions go these days.)
+
+学习Go还要阅读Go标准库的源代码,全部文档化了,可读性非常好,可以学到go,go style和go idioms。在文档中点击函数名,源代码就出来了!