1
0
mirror of https://github.com/adambard/learnxinyminutes-docs.git synced 2025-08-19 13:02:14 +02:00
This commit is contained in:
Adam
2013-08-16 08:51:16 -07:00
15 changed files with 3578 additions and 412 deletions

View File

@@ -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,261 +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 (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"
// 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;
// Pointer types end with * in their declaration
int* px; // 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
// 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();
// 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
///////////////////////////////////////
@@ -297,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
}
@@ -309,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;
@@ -333,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 .
@@ -349,37 +456,45 @@ 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
///////////////////////////////////////
/*
At runtime, functions are located at known memory addresses. Function pointers are
much likely any other pointer (they just store a memory address), but can be used
much like any other pointer (they just store a memory address), but can be used
to invoke functions directly, and to pass handlers (or callback functions) around.
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.
}
@@ -391,7 +506,7 @@ Function pointers are usually typedef'd for simplicity and readability, as follo
typedef void (*my_fnp_type)(char *);
// The used when declaring the actual pointer variable:
// Then used when declaring the actual pointer variable:
// ...
// my_fnp_type f;
@@ -400,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/)
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).
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.

View File

@@ -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);

View File

@@ -14,7 +14,8 @@ filename: coffeescript-es.coffee
# Los comentarios son como en Ruby y Python, usan almohadillas.
###
Los comentarios en bloque son como estos, y se traducen directamente a '/*' y '*/' para el código JavaScript resultante.
Los comentarios en bloque son como estos, y se traducen directamente a '/*' y '*/'
para el código JavaScript resultante.
Deberías entender la mayor parte de la semántica de JavaScript antes de continuar.
###

407
fr-fr/ruby-fr.html.markdown Normal file
View File

@@ -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
```

View File

@@ -405,3 +405,7 @@ Other Topics To Research:
* [Generics](http://docs.oracle.com/javase/tutorial/java/generics/index.html)
* [Java Code Conventions](http://www.oracle.com/technetwork/java/codeconv-138413.html)
Books:
* [Head First Java] (http://www.headfirstlabs.com/books/hfjava/)

View File

@@ -30,83 +30,84 @@ doStuff();
// wherever there's a newline, except in certain cases.
doStuff()
// We'll leave semicolons off here; whether you do or not will depend on your
// personal preference or your project's style guide.
// So that we don't have to worry about those certain cases (for now), we'll
// leave them on.
///////////////////////////////////
// 1. Numbers, Strings and Operators
// Javascript has one number type (which is a 64-bit IEEE 754 double).
3 // = 3
1.5 // = 1.5
3; // = 3
1.5; // = 1.5
// All the basic arithmetic works as you'd expect.
1 + 1 // = 2
8 - 1 // = 7
10 * 2 // = 20
35 / 5 // = 7
1 + 1; // = 2
8 - 1; // = 7
10 * 2; // = 20
35 / 5; // = 7
// Including uneven division.
5 / 2 // = 2.5
5 / 2; // = 2.5
// Bitwise operations also work; when you perform a bitwise operation your float
// is converted to a signed int *up to* 32 bits.
1 << 2 // = 4
1 << 2; // = 4
// Precedence is enforced with parentheses.
(1 + 3) * 2 // = 8
(1 + 3) * 2; // = 8
// There are three special not-a-real-number values:
Infinity // result of e.g. 1/0
-Infinity // result of e.g. -1/0
NaN // result of e.g. 0/0
Infinity; // result of e.g. 1/0
-Infinity; // result of e.g. -1/0
NaN; // result of e.g. 0/0
// There's also a boolean type.
true
false
true;
false;
// Strings are created with ' or ".
'abc'
"Hello, world"
'abc';
"Hello, world";
// Negation uses the ! symbol
!true // = false
!false // = true
!true; // = false
!false; // = true
// Equality is ==
1 == 1 // = true
2 == 1 // = false
1 == 1; // = true
2 == 1; // = false
// Inequality is !=
1 != 1 // = false
2 != 1 // = true
1 != 1; // = false
2 != 1; // = true
// More comparisons
1 < 10 // = true
1 > 10 // = false
2 <= 2 // = true
2 >= 2 // = true
1 < 10; // = true
1 > 10; // = false
2 <= 2; // = true
2 >= 2; // = true
// Strings are concatenated with +
"Hello " + "world!" // = "Hello world!"
"Hello " + "world!"; // = "Hello world!"
// and are compared with < and >
"a" < "b" // = true
"a" < "b"; // = true
// Type coercion is performed for comparisons...
"5" == 5 // = true
"5" == 5; // = true
// ...unless you use ===
"5" === 5 // = false
"5" === 5; // = false
// You can access characters in a string with charAt
"This is a string".charAt(0)
"This is a string".charAt(0);
// There's also null and undefined
null // used to indicate a deliberate non-value
undefined // used to indicate a value that hasn't been set yet
null; // used to indicate a deliberate non-value
undefined; // used to indicate a value is not currently present (although undefined
// is actually a value itself)
// null, undefined, NaN, 0 and "" are falsy, and everything else is truthy.
// false, null, undefined, NaN, 0 and "" are falsy, and everything else is truthy.
// Note that 0 is falsy and "0" is truthy, even though 0 == "0".
///////////////////////////////////
@@ -114,57 +115,57 @@ undefined // used to indicate a value that hasn't been set yet
// Variables are declared with the var keyword. Javascript is dynamically typed,
// so you don't need to specify type. Assignment uses a single = character.
var someVar = 5
var someVar = 5;
// if you leave the var keyword off, you won't get an error...
someOtherVar = 10
someOtherVar = 10;
// ...but your variable will be created in the global scope, not in the scope
// you defined it in.
// Variables declared without being assigned to are set to undefined.
var someThirdVar // = undefined
var someThirdVar; // = undefined
// There's shorthand for performing math operations on variables:
someVar += 5 // equivalent to someVar = someVar + 5; someVar is 10 now
someVar *= 10 // now someVar is 100
someVar += 5; // equivalent to someVar = someVar + 5; someVar is 10 now
someVar *= 10; // now someVar is 100
// and an even-shorter-hand for adding or subtracting 1
someVar++ // now someVar is 101
someVar-- // back to 100
someVar++; // now someVar is 101
someVar--; // back to 100
// Arrays are ordered lists of values, of any type.
var myArray = ["Hello", 45, true]
var myArray = ["Hello", 45, true];
// Their members can be accessed using the square-brackets subscript syntax.
// Array indices start at zero.
myArray[1] // = 45
myArray[1]; // = 45
// JavaScript's objects are equivalent to 'dictionaries' or 'maps' in other
// languages: an unordered collection of key-value pairs.
{key1: "Hello", key2: "World"}
var myObj = {key1: "Hello", key2: "World"};
// Keys are strings, but quotes aren't required if they're a valid
// JavaScript identifier. Values can be any type.
var myObj = {myKey: "myValue", "my other key": 4}
var myObj = {myKey: "myValue", "my other key": 4};
// Object attributes can also be accessed using the subscript syntax,
myObj["my other key"] // = 4
myObj["my other key"]; // = 4
// ... or using the dot syntax, provided the key is a valid identifier.
myObj.myKey // = "myValue"
myObj.myKey; // = "myValue"
// Objects are mutable; values can be changed and new keys added.
myObj.myThirdKey = true
myObj.myThirdKey = true;
// If you try to access a value that's not yet set, you'll get undefined.
myObj.myFourthKey // = undefined
myObj.myFourthKey; // = undefined
///////////////////////////////////
// 3. Logic and Control Structures
// The if structure works as you'd expect.
var count = 1
var count = 1;
if (count == 3){
// evaluated if count is 3
} else if (count == 4) {
@@ -181,10 +182,10 @@ while (true) {
// Do-while loops are like while loops, except they always run at least once.
var input
do {
input = getInput()
input = getInput();
} while (!isValid(input))
// the for loop is the same as C and Java:
// the for loop is the same as C and Java:
// initialisation; continue condition; iteration.
for (var i = 0; i < 5; i++){
// will run 5 times
@@ -192,29 +193,23 @@ for (var i = 0; i < 5; i++){
// && is logical and, || is logical or
if (house.size == "big" && house.colour == "blue"){
house.contains = "bear"
house.contains = "bear";
}
if (colour == "red" || colour == "blue"){
// colour is either red or blue
}
// && and || "short circuit", which is useful for setting default values.
var name = otherName || "default"
var name = otherName || "default";
///////////////////////////////////
// 4. Functions, Scope and Closures
// JavaScript functions are declared with the function keyword.
function myFunction(thing){
return thing.toUpperCase()
return thing.toUpperCase();
}
myFunction("foo") // = "FOO"
// Functions can also be defined "anonymously" - without a name:
function(thing){
return thing.toLowerCase()
}
// (we can't call our function, since we don't have a name to refer to it with)
myFunction("foo"); // = "FOO"
// JavaScript functions are first class objects, so they can be reassigned to
// different variable names and passed to other functions as arguments - for
@@ -222,52 +217,49 @@ function(thing){
function myFunction(){
// this code will be called in 5 seconds' time
}
setTimeout(myFunction, 5000)
setTimeout(myFunction, 5000);
// You can even write the function statement directly in the call to the other
// function.
setTimeout(function myFunction(){
// Function objects don't even have to be declared with a name - you can write
// an anonymous function definition directly into the arguments of another.
setTimeout(function(){
// this code will be called in 5 seconds' time
}, 5000)
}, 5000);
// JavaScript has function scope; functions get their own scope but other blocks
// do not.
if (true){
var i = 5
var i = 5;
}
i // = 5 - not undefined as you'd expect in a block-scoped language
i; // = 5 - not undefined as you'd expect in a block-scoped language
// This has led to a common pattern of "immediately-executing anonymous
// functions", which prevent temporary variables from leaking into the global
// scope.
(function(){
var temporary = 5
var temporary = 5;
// We can access the global scope by assiging to the 'global object', which
// in a web browser is always 'window'. The global object may have a
// different name in non-browser environments such as Node.js.
window.permanent = 10
// Or, as previously mentioned, we can just leave the var keyword off.
permanent2 = 15
})()
temporary // raises ReferenceError
permanent // = 10
permanent2 // = 15
window.permanent = 10;
})();
temporary; // raises ReferenceError
permanent; // = 10
// One of JavaScript's most powerful features is closures. If a function is
// defined inside another function, the inner function has access to all the
// outer function's variables.
// outer function's variables, even after the outer function exits.
function sayHelloInFiveSeconds(name){
var prompt = "Hello, " + name + "!"
var prompt = "Hello, " + name + "!";
function inner(){
alert(prompt)
alert(prompt);
}
setTimeout(inner, 5000)
// setTimeout is asynchronous, so this function will finish without waiting
// 5 seconds. However, once the 5 seconds is up, inner will still have
// access to the value of prompt.
setTimeout(inner, 5000);
// setTimeout is asynchronous, so the sayHelloInFiveSeconds function will
// exit immediately, and setTimeout will call inner afterwards. However,
// because inner is "closed over" sayHelloInFiveSeconds, inner still has
// access to the 'prompt' variable when it is finally called.
}
sayHelloInFiveSeconds("Adam") // will open a popup with "Hello, Adam!" in 5s
sayHelloInFiveSeconds("Adam"); // will open a popup with "Hello, Adam!" in 5s
///////////////////////////////////
// 5. More about Objects; Constructors and Prototypes
@@ -275,44 +267,44 @@ sayHelloInFiveSeconds("Adam") // will open a popup with "Hello, Adam!" in 5s
// Objects can contain functions.
var myObj = {
myFunc: function(){
return "Hello world!"
return "Hello world!";
}
}
myObj.myFunc() // = "Hello world!"
};
myObj.myFunc(); // = "Hello world!"
// When functions attached to an object are called, they can access the object
// they're attached to using the this keyword.
myObj = {
myString: "Hello world!",
myFunc: function(){
return this.myString
return this.myString;
}
}
myObj.myFunc() // = "Hello world!"
};
myObj.myFunc(); // = "Hello world!"
// What this is set to has to do with how the function is called, not where
// it's defined. So, our function doesn't work if it isn't called in the
// context of the object.
var myFunc = myObj.myFunc
myFunc() // = undefined
var myFunc = myObj.myFunc;
myFunc(); // = undefined
// Inversely, a function can be assigned to the object and gain access to it
// through this, even if it wasn't attached when it was defined.
var myOtherFunc = function(){
return this.myString.toUpperCase()
return this.myString.toUpperCase();
}
myObj.myOtherFunc = myOtherFunc
myObj.myOtherFunc() // = "HELLO WORLD!"
myObj.myOtherFunc = myOtherFunc;
myObj.myOtherFunc(); // = "HELLO WORLD!"
// When you call a function with the new keyword, a new object is created, and
// made available to the function via this. Functions designed to be called
// like this are called constructors.
var MyConstructor = function(){
this.myNumber = 5
this.myNumber = 5;
}
myNewObj = new MyConstructor() // = {myNumber: 5}
myNewObj.myNumber // = 5
myNewObj = new MyConstructor(); // = {myNumber: 5}
myNewObj.myNumber; // = 5
// Every JavaScript object has a 'prototype'. When you go to access a property
// on an object that doesn't exist on the actual object, the interpreter will
@@ -323,31 +315,31 @@ myNewObj.myNumber // = 5
// part of the standard; we'll get to standard ways of using prototypes later.
var myObj = {
myString: "Hello world!",
}
};
var myPrototype = {
meaningOfLife: 42,
myFunc: function(){
return this.myString.toLowerCase()
}
}
myObj.__proto__ = myPrototype
myObj.meaningOfLife // = 42
};
myObj.__proto__ = myPrototype;
myObj.meaningOfLife; // = 42
// This works for functions, too.
myObj.myFunc() // = "hello world!"
myObj.myFunc(); // = "hello world!"
// Of course, if your property isn't on your prototype, the prototype's
// prototype is searched, and so on.
myPrototype.__proto__ = {
myBoolean: true
}
myObj.myBoolean // = true
};
myObj.myBoolean; // = true
// There's no copying involved here; each object stores a reference to its
// prototype. This means we can alter the prototype and our changes will be
// reflected everywhere.
myPrototype.meaningOfLife = 43
myObj.meaningOfLife // = 43
myPrototype.meaningOfLife = 43;
myObj.meaningOfLife; // = 43
// We mentioned that __proto__ was non-standard, and there's no standard way to
// change the prototype of an existing object. However, there's two ways to
@@ -355,8 +347,8 @@ myObj.meaningOfLife // = 43
// The first is Object.create, which is a recent addition to JS, and therefore
// not available in all implementations yet.
var myObj = Object.create(myPrototype)
myObj.meaningOfLife // = 43
var myObj = Object.create(myPrototype);
myObj.meaningOfLife; // = 43
// The second way, which works anywhere, has to do with constructors.
// Constructors have a property called prototype. This is *not* the prototype of
@@ -366,20 +358,20 @@ myConstructor.prototype = {
getMyNumber: function(){
return this.myNumber
}
}
var myNewObj2 = new myConstructor()
myNewObj2.getMyNumber() // = 5
};
var myNewObj2 = new myConstructor();
myNewObj2.getMyNumber(); // = 5
// Built-in types like strings and numbers also have constructors that create
// equivalent wrapper objects.
var myNumber = 12
var myNumberObj = new Number(12)
myNumber == myNumberObj // = true
var myNumber = 12;
var myNumberObj = new Number(12);
myNumber == myNumberObj; // = true
// Except, they aren't exactly equivalent.
typeof(myNumber) // = 'number'
typeof(myNumberObj) // = 'object'
myNumber === myNumberObj // = false
typeof(myNumber); // = 'number'
typeof(myNumberObj); // = 'object'
myNumber === myNumberObj; // = false
if (0){
// This code won't execute, because 0 is falsy.
}
@@ -390,9 +382,9 @@ if (Number(0)){
// However, the wrapper objects and the regular builtins share a prototype, so
// you can actually add functionality to a string, for instance.
String.prototype.firstCharacter = function(){
return this.charAt(0)
return this.charAt(0);
}
"abc".firstCharacter() // = "a"
"abc".firstCharacter(); // = "a"
// This fact is often used in "polyfilling", which is implementing newer
// features of JavaScript in an older subset of JavaScript, so that they can be
@@ -403,10 +395,10 @@ String.prototype.firstCharacter = function(){
if (Object.create === undefined){ // don't overwrite it if it exists
Object.create = function(proto){
// make a temporary constructor with the right prototype
var Constructor = function(){}
Constructor.prototype = proto
var Constructor = function(){};
Constructor.prototype = proto;
// then use it to create a new, appropriately-prototyped object
return new Constructor()
return new Constructor();
}
}
```

406
ko-kr/java-kr.html.markdown Normal file
View File

@@ -0,0 +1,406 @@
---
language: java
category: language
contributors:
- ["Jake Prather", "http://github.com/JakeHP"]
translators:
- ["wikibook", "http://wikibook.co.kr"]
lang: ko-kr
---
자바는 일반 목적으로 사용할 수 있고 동시성을 지원하며, 클래스 기반의 객체지향 컴퓨터 프로그래밍 언어입니다.
[더 자세한 사항](http://docs.oracle.com/javase/tutorial/java/index.html)
```java
// 한 줄짜리 주석은 //로 시작합니다.
/*
여러 줄 주석은 다음과 같은 형태입니다.
*/
/**
자바독(JavaDoc) 주석은 이렇게 생겼습니다. 자바독 주석은 클래스나 클래스의
다양한 속성을 기술하는 데 사용됩니다.
*/
// java.util 패키지 안에 있는 ArrayList 클래스를 임포트합니다.
import java.util.ArrayList;
// java.security 패키지 안에 있는 모든 클래스를 임포트합니다.
import java.security.*;
// 각 .java 파일에는 공용(public) 클래스가 들어 있으며, 클래스의 이름은 파일명과 동일합니다.
public class LearnJava {
// 프로그램에는 반드시 진입점 역할을 하는 main 메서드가 하나 있어야 합니다.
public static void main (String[] args) {
// System.out.println을 이용해 한 줄을 출력합니다.
System.out.println("Hello World!");
System.out.println(
"Integer: " + 10 +
" Double: " + 3.14 +
" Boolean: " + true);
// 줄바꿈 없이 뭔가를 출력하려면 System.out.print를 사용합니다.
System.out.print("Hello ");
System.out.print("World");
///////////////////////////////////////
// 타입 & 변수
///////////////////////////////////////
// <타입> <이름>과 같은 형태로 변수를 선언합니다.
// Byte - 부호가 있는 8비트 2의 보수 정수
// (-128 <= byte <= 127)
byte fooByte = 100;
// Short - 부호가 있는 16비트 2의 보수 정수
// (-32,768 <= short <= 32,767)
short fooShort = 10000;
// Integer - 부호가 있는 32비트 2의 보수 정수
// (-2,147,483,648 <= int <= 2,147,483,647)
int fooInt = 1;
// Long - 부호가 있는 64비트 2의 보수 정수
// (-9,223,372,036,854,775,808 <= long <= 9,223,372,036,854,775,807)
long fooLong = 100000L;
// L은 이 변수의 값이 Long 타입임을 나타내는 데 사용됩니다.
// L이 없는 것들은 기본적으로 정수로 간주됩니다.
// 참고: 자바에는 부호 없는(unsigned) 타입이 없습니다.
// Float - 단정도 32비트 IEEE 754 부동 소수점 수
float fooFloat = 234.5f;
// f는 이 변수의 값이 float 타입임을 나타내는 데 사용됩니다.
// f를 지정하지 않으면 double로 간주됩니다.
// Double - 배정도 64비트 IEEE 754 부동 소수점 수
double fooDouble = 123.4;
// Boolean - 참(true) & 거짓(false)
boolean fooBoolean = true;
boolean barBoolean = false;
// Char - 단일 16비트 유니코드 문자
char fooChar = 'A';
// 변수를 변경할 수 없게 만들려면 final을 지정합니다.
final int HOURS_I_WORK_PER_WEEK = 9001;
// 문자열
String fooString = "My String Is Here!";
// \n은 새로운 줄을 시작하는 이스케이프 문자입니다.
String barString = "Printing on a new line?\nNo Problem!";
// \t는 탭 문자를 추가하는 이스케이프 문자입니다.
String bazString = "Do you want to add a tab?\tNo Problem!";
System.out.println(fooString);
System.out.println(barString);
System.out.println(bazString);
// 배열
// 배열의 크기는 반드시 선언할 때 결정해야 합니다.
// 배열을 선언하는 형식은 다음과 같습니다.
//<자료형> [] <변수명> = new <자료형>[<배열 크기>];
int [] intArray = new int[10];
String [] stringArray = new String[1];
boolean [] booleanArray = new boolean[100];
// 배열을 선언하고 초기화하는 또 다른 방법
int [] y = {9000, 1000, 1337};
// 배열 인덱스 - 요소에 접근
System.out.println("intArray @ 0: " + intArray[0]);
// 배열의 인덱스는 0에서부터 시작하며 변경 가능합니다.
intArray[1] = 1;
System.out.println("intArray @ 1: " + intArray[1]); // => 1
// 기타 참고할 만한 자료구조
// ArrayLists - 좀 더 많은 기능을 제공하고 크기를 변경 가능하다는 점을
// 제외하면 배열과 비슷합니다.
// LinkedLists
// Maps
// HashMaps
///////////////////////////////////////
// 연산자
///////////////////////////////////////
System.out.println("\n->Operators");
int i1 = 1, i2 = 2; // 다중 선언의 축약형
// 산술 연산은 이해하기 어렵지 않습니다.
System.out.println("1+2 = " + (i1 + i2)); // => 3
System.out.println("2-1 = " + (i2 - i1)); // => 1
System.out.println("2*1 = " + (i2 * i1)); // => 2
System.out.println("1/2 = " + (i1 / i2)); // => 0 (0.5를 잘라 버립니다)
// 나눗셈
System.out.println("11%3 = "+(11 % 3)); // => 2
// 비교 연산자
System.out.println("3 == 2? " + (3 == 2)); // => false
System.out.println("3 != 2? " + (3 != 2)); // => true
System.out.println("3 > 2? " + (3 > 2)); // => true
System.out.println("3 < 2? " + (3 < 2)); // => false
System.out.println("2 <= 2? " + (2 <= 2)); // => true
System.out.println("2 >= 2? " + (2 >= 2)); // => true
// 비트 연산자!
/*
~ 단항 보수 연산
<< 산술적 왼쪽 시프트
>> 산술적 오른쪽 시프트
>>> 논리적 오른쪽 시프트
& 비트 단위 논리곱(AND)
^ 비트 단위 배타적 논리합(OR)
| 비트 단위 논리합(OR)
*/
// 증감 연산자
int i = 0;
System.out.println("\n->Inc/Dec-rementation");
System.out.println(i++); //i = 1. 후치 증가 연산
System.out.println(++i); //i = 2. 전치 증가 연산
System.out.println(i--); //i = 1. 후치 감소 연산
System.out.println(--i); //i = 0. 전치 감소 연산
///////////////////////////////////////
// 에저 구조
///////////////////////////////////////
System.out.println("\n->Control Structures");
// if 문은 C 언어와 비슷합니다.
int j = 10;
if (j == 10){
System.out.println("I get printed");
} else if (j > 10) {
System.out.println("I don't");
} else {
System.out.println("I also don't");
}
// while 루프
int fooWhile = 0;
while(fooWhile < 100)
{
// System.out.println(fooWhile);
// 카운터를 증가
// 99번 반복, fooWhile 0->99
fooWhile++;
}
System.out.println("fooWhile Value: " + fooWhile);
// do-while 루프
int fooDoWhile = 0;
do
{
// System.out.println(fooDoWhile);
// 카운터를 증가
// 99번 반복, fooDoWhile 0->99
fooDoWhile++;
}while(fooDoWhile < 100);
System.out.println("fooDoWhile Value: " + fooDoWhile);
// for 루프
int fooFor;
// for 루프 구조 => for(<초기식>; <조건식>; <증감식>)
for(fooFor=0; fooFor<10; fooFor++){
// System.out.println(fooFor);
// 10번 반복, fooFor 0->9
}
System.out.println("fooFor Value: " + fooFor);
// switch-case 문
// switch는 byte, short, char, int 자료형을 대상으로 동작합니다.
// 아울러 열거형을 비롯해 String 클래스 및 원시 타입을 감싼 Character,
// Byte, Short, Integer와 같은 몇 가지 특별한 클래스에 대해서도 동작합니다.
int month = 3;
String monthString;
switch (month){
case 1:
monthString = "January";
break;
case 2:
monthString = "February";
break;
case 3:
monthString = "March";
break;
default:
monthString = "Some other month";
break;
}
System.out.println("Switch Case Result: " + monthString);
///////////////////////////////////////
// 자료형 변환과 형변환
///////////////////////////////////////
// 데이터 변환
// 문자열에서 정수로 변환
Integer.parseInt("123");// 정수 버전의 "123"을 반환
// 정수를 문자열로 변환
Integer.toString(123);// 문자열 버전의 123을 반환
// 다른 변환에 대해서는 아래 클래스를 확인해 보세요.
// Double
// Long
// String
// 형변환
// 자바 객채 또한 형변환할 수 있으며, 이와 관련해서 알아야 할 세부사항이 많을뿐더러
// 다소 중급 수준에 해당하는 개념들도 다뤄야 합니다.
// 이와 관련된 사항은 아래 링크를 참고하세요.
// http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
///////////////////////////////////////
// 클래스와 함수
///////////////////////////////////////
System.out.println("\n->Classes & Functions");
// (Bicycle 클래스의 정의)
// 클래스를 인스턴스화하려면 new를 사용합니다.
Bicycle trek = new Bicycle();
// 객체의 메서드를 호출합니다.
trek.speedUp(3); // 항상 설정자 메서드와 접근자 메서드를 사용해야 합니다.
trek.setCadence(100);
// 현재 객체의 값을 표시할 때는 관례적으로 toString을 사용합니다.
System.out.println("trek info: " + trek.toString());
} // main 메서드 끝
} // LearnJava 클래스 끝
// .java 파일 안에 다른 비공개 클래스를 포함할 수 있습니다.
// 클래스 선언 문법:
// <public/private/protected> class <클래스명>{
// // 데이터 필드, 생성자, 함수가 모두 이곳에 들어갑니다.
// // 자바에서는 함수를 메서드라고 부릅니다.
// }
class Bicycle {
// Bicycle의 필드와 변수
public int cadence; // Public: 어느 곳에서도 접근할 수 있습니다.
private int speed; // Private: 클래스 안에서만 접근할 수 있습니다.
protected int gear; // Protected: 현재 클래스와 하위 클래스에서 접근할 수 있습니다.
String name; // default: 현재 패키지 안에서만 접근할 수 있습니다.
// 생성자는 클래스를 생성하는 방법 중 하나입니다.
// 다음은 기본 생성자입니다.
public Bicycle() {
gear = 1;
cadence = 50;
speed = 5;
name = "Bontrager";
}
// 다음은 구체화된 생성자입니다(인자를 담고 있습니다)
public Bicycle(int startCadence, int startSpeed, int startGear, String name) {
this.gear = startGear;
this.cadence = startCadence;
this.speed = startSpeed;
this.name = name;
}
// 함수 문법:
// <public/private/protected> <반환형> <함수명>(<인자>)
// 자바 클래스는 필드에 대해 접근자 메서드와 설정자 메서드를 구현할 때가 많습니다.
// 메서드 선언 문법:
// <유효범위> <반환형> <메서드명>(<인자>)
public int getCadence() {
return cadence;
}
// void 메서드는 반환형이 필요하지 않습니다.
public void setCadence(int newValue) {
cadence = newValue;
}
public void setGear(int newValue) {
gear = newValue;
}
public void speedUp(int increment) {
speed += increment;
}
public void slowDown(int decrement) {
speed -= decrement;
}
public void setName(String newName) {
name = newName;
}
public String getName() {
return name;
}
// 현재 객체의 속성값을 표시하는 메서드
@Override
public String toString() {
return "gear: " + gear +
" cadence: " + cadence +
" speed: " + speed +
" name: " + name;
}
} // Bicycle 클래스의 끝
// PennyFarthing은 Bicycle의 하위 클래스입니다.
class PennyFarthing extends Bicycle {
// (페니 파딩은 앞바퀴가 굉장히 큰 자전거입니다. 기어가 없죠.)
public PennyFarthing(int startCadence, int startSpeed){
// super를 이용해 부모 생성자를 호출합니다.
super(startCadence, startSpeed, 0, "PennyFarthing");
}
// @annotation을 이용해 재정의하는 메서드를 표시해야 합니다.
// 애노테이션과 애노테이션의 용도에 관한 자세한 내용은 아래 링크를 참고하세요.
// 애노테이션: http://docs.oracle.com/javase/tutorial/java/annotations/
@Override
public void setGear(int gear) {
gear = 0;
}
}
```
## 기타 참고자료
다음 링크를 통해 다양한 주제를 이해하고 구글을 통해 구체적인 예제들을 찾아보세요.
공부할 만한 기타 주제:
* [썬/오라클의 자바 자습서](http://docs.oracle.com/javase/tutorial/index.html)
* [자바 접근 제한자](http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html)
* [객체 지향 프로그래밍 개념](http://docs.oracle.com/javase/tutorial/java/concepts/index.html):
* [상속(Inheritance)](http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html)
* [다형성(Polymorphism)](http://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html)
* [추상화(Abstraction)](http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html)
* [예외(Exceptions)](http://docs.oracle.com/javase/tutorial/essential/exceptions/index.html)
* [인터페이스(Interfaces)](http://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html)
* [제네릭(Generics)](http://docs.oracle.com/javase/tutorial/java/generics/index.html)
* [자바 코딩 관례(Java Code Conventions)](http://www.oracle.com/technetwork/java/codeconv-138413.html)

View File

@@ -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]))

384
pt-br/ruby-pt.html.markdown Normal file
View File

@@ -0,0 +1,384 @@
---
language: ruby
filename: learnruby.rb
contributors:
- ["Bruno Henrique - Garu", "http://garulab.com"]
- ["Katyanna Moura", "https://twitter.com/amelie_kn"]
---
```ruby
# Isso é um comentário
=begin
Isso é um comentário multilinha
Ninguém os usa
Você não deve usar também
=end
# Primeiro e principal: Tudo é um objeto.
# Números são objetos
3.class #=> Fixnum
3.to_s #=> "3"
# Um pouco de aritmética básica
1 + 1 #=> 2
8 - 1 #=> 7
10 * 2 #=> 20
35 / 5 #=> 7
# Aritimética é apenas açúcar sintático
# para chamar um método de um objeto
1.+(3) #=> 4
10.* 5 #=> 50
# Valores especiais são objetos
nil # Nada para ver aqui
true # verdadeiro
false # falso
nil.class #=> NilClass
true.class #=> TrueClass
false.class #=> FalseClass
# Igualdade
1 == 1 #=> true
2 == 1 #=> false
# Desigualdade
1 != 1 #=> false
2 != 1 #=> true
!true #=> false
!false #=> true
# além de 'false', 'nil' é o único outro valor falso
!nil #=> true
!false #=> true
!0 #=> false
# Mais comparações
1 < 10 #=> true
1 > 10 #=> false
2 <= 2 #=> true
2 >= 2 #=> true
# Strings são objects
'Eu sou uma string'.class #=> String
"Eu também sou uma string".class #=> String
placeholder = "usar interpolação de string"
"Eu posso #{placeholder} quando estiver usando aspas duplas"
#=> "Eu posso usar insterpolação de string quando estiver usando aspas duplas"
# imprime para output (saída)
puts "Estou imprimindo"
# Variáveis
x = 25 #=> 25
x #=> 25
# Note que uma atribuição retorna o valor atribuido
# Isso significa que você pode fazer múltiplas atribuições:
x = y = 10 #=> 10
x #=> 10
y #=> 10
# Por convenção, use snake_case para nomes de variáveis
snake_case = true
# Use nomes de variáveis descritivos
caminho_para_a_raiz_do_projeto = '/bom/nome/'
caminho = '/nome/ruim/'
# Símbolos (são objetos)
# Símbolos são imutáveis, são constantes reutilizáveis representadadas internamente por um
# valor inteiro. Eles são frequentemente usados no lugar de strings para transmitir com eficiência os valores
# específicos e significativos
:pendente.class #=> Symbol
status = :pendente
status == :pendente #=> true
status == 'pendente' #=> false
status == :aprovado #=> false
# Arrays
# Isso é um array
[1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]
# Arrays podem conter diferentes tipos de itens
array = [1, "Oi", false] #=> => [1, "Oi", false]
# Arrays podem ser indexados
# a partir do começo
array[0] #=> 1
array[12] #=> nil
# Como aritimética, o acesso via [var]
# é apenas açúcar sintático
# para chamar o método [] de um objeto
array.[] 0 #=> 1
array.[] 12 #=> nil
# a partir do final
array[-1] #=> 5
# Com um índice de começo e fim
array[2, 4] #=> [3, 4, 5]
# Ou com um intervalo de valores
array[1..3] #=> [2, 3, 4]
# Adicionar a um array como este
array << 6 #=> [1, 2, 3, 4, 5, 6]
# Hashes são o principal dicionário de Ruby com pares de chaves(keys)/valor(value).
# Hashes são simbolizados com chaves "{}"
hash = {'cor' => 'verde', 'numero' => 5}
hash.keys #=> ['cor', 'numero']
# Hashes podem ser rapidamente pesquisados pela chave (key)
hash['cor'] #=> 'verde'
hash['numero'] #=> 5
# Procurar em um hash por uma chave que não existe retorna nil:
hash['nada aqui'] #=> nil
# Interar sobre hashes com o método #each:
hash.each do |k, v|
puts "#{k} is #{v}"
end
hash.each do |k, v|
puts "#{k} é #{v}"
end
# Desde o Ruby 1.9, temos uma sintaxe especial quando usamos símbolos como chaves (keys)
novo_hash = { defcon: 3, acao: true}
novo_hash.keys #=> [:defcon, :acao]
# Dica: Tanto Arrays quanto Hashes são Enumerable.
# Eles compartilham um monte de métodos úteis como each, map, count e mais
# Estruturas de controle
if true
"Se verdadeiro"
elsif false
"else if, opicional"
else
"else, também é opicional"
end
for contador in 1..5
puts "interação #{contador}"
end
#=> contador 1
#=> contador 2
#=> contador 3
#=> contador 4
#=> contador 5
# PORÉM
# Ninguém usa para loops
# Use "each" em vez, dessa forma:
(1..5).each do |contador|
puts "interação #{contador}"
end
#=> contador 1
#=> contador 2
#=> contador 3
#=> contador 4
#=> contador 5
contador = 1
while contador <= 5 do
puts "interação #{contador}"
contador += 1
end
#=> contador 1
#=> contador 2
#=> contador 3
#=> contador 4
#=> contador 5
grau = 'B'
case grau
when 'A'
puts "Um longo caminho a percorrer, pequeno gafanhoto"
when 'B'
puts "Melhor sorte da próxima vez"
when 'C'
puts "Você pode fazer melhor"
when 'D'
puts "Scraping through"
when 'F'
puts "Você falhou"
else
puts "Alternative grading system, eh?"
end
# Funções
def dobrar(x)
x * 2
end
# Funções (e todos os blocos) retornam implicitamente o valor da última linha
dobrar(2) #=> 4
# Parênteses são opicionais onde o resultado é claro
dobrar 3 #=> 6
dobrar dobrar 3 #=> 12
def somar(x,y)
x + y
end
# Argumentos de métodos são separados por uma vírgula
somar 3, 4 #=> 7
somar somar(3,4), 5 #=> 12
# yield
# Todos os métodos possuem implicitamente um paramêntro opcional que é um bloco
# ele pode ser chamado com a palavra chave 'yield'
def ao_redor
puts "{"
yield
puts "}"
end
ao_redor { puts 'Olá mundo' }
# {
# Olá mundo
# }
# Define uma classe com a palavra chave 'class'
class Humano
# Uma variável de classe. Ela é compartilhada por todas as instâncias dessa classe
@@especies = "H. sapiens"
# Inicialização básica (contructor)
def initialize(nome, idade=0)
# Atribui o argumento para a variável de instancia "nome" do objeto
@nome = nome
# Se a idade não for passada, nós definimos um valor padrão na lista de argumentos
@idade = idade
end
# Método básico para atribuir valor
def nome=(nome)
@nome = nome
end
# Método básico de resgatar valor
def nome
@nome
end
# Um método de classe usa a palavra chave self para se defenciar dos métodos de instância.
# Ele só pode ser chamado na classe, não na instancia
def self.diz(msg)
puts "#{msg}"
end
def especies
@@especies
end
end
# Instanciando uma classe
jim = Humano.new("Jim Halpert")
dwight = Humano.new("Dwight K. Schrute")
# Vamos chamar um par de métodos
jim.especies #=> "H. sapiens"
jim.nome #=> "Jim Halpert"
jim.nome = "Jim Halpert II" #=> "Jim Halpert II"
jim.nome #=> "Jim Halpert II"
dwight.especies #=> "H. sapiens"
dwight.nome #=> "Dwight K. Schrute"
# Chamar o método de classe
Humano.diz("Oi") #=> "Oi"
# Uma classe também é objeto em Ruby. Então uma classe pode possuir variável de instância
# Variáveis de classe são compartilhadas entre a classe e todos os seus descendentes.
# Classe base
class Humano
@@foo = 0
def self.foo
@@foo
end
def self.foo=(value)
@@foo = value
end
end
# classe filha
class Trabalhador < Humano
end
Humano.foo # 0
Trabalhador.foo # 0
Humano.foo = 2 # 2
Trabalhador.foo # 2
# Uma variável de instância não é compartilhada por suas classes decendentes.
class Humano
@bar = 0
def self.bar
@bar
end
def self.bar=(value)
@bar = value
end
end
class Doutor < Humano
end
Humano.bar # 0
Doutor.bar # nil
```

View File

@@ -0,0 +1,426 @@
---
language: clojure
filename: learnclojure-ru.clj
contributors:
- ["Adam Bard", "http://adambard.com/"]
- ["Alexey Pirogov", "http://twitter.com/alex_pir"]
---
Clojure, это представитель семейства Lisp-подобных языков, разработанный
для Java Virtual Machine. Язык идейно гораздо ближе к чистому
[функциональному программированию](https://ru.wikipedia.org/wiki/%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5) чем его прародитель Common Lisp, но в то же время обладает набором инструментов для работы с состоянием,
таких как [STM](https://ru.wikipedia.org/wiki/Software_transactional_memory).
Благодаря такому сочетанию технологий в одном языке, разработка программ,
предполагающих конкурентное выполнение, значительно упрощается
и даже может быть автоматизирована.
(Последующие примеры кода предполагают выполнение в Clojure версии 1.2 и выше)
```clojure
; Комментарии начинаются символом ";".
; Код на языке Clojure записывается в виде "форм",
; которые представляют собой обычные списки элементов, разделенных пробелами,
; заключённые в круглые скобки
;
; Clojure Reader (инструмент языка, отвечающий за чтение исходного кода),
; анализируя форму, предполагает, что первым элементом формы (т.е. списка)
; является функция или макрос, который следует вызвать, передав ему
; в качестве аргументов остальные элементы списка-формы.
; Первым вызовом в файле должен быть вызов функции ns,
; которая отвечает за выбор текущего пространства имен (namespace)
(ns learnclojure-ru)
; Несколько простых примеров:
; str объединяет в единую строку все свои аргументы
(str "Hello" " " "World") ; => "Hello World"
; Арифметика тоже выглядит несложно
(+ 1 1) ; => 2
(- 2 1) ; => 1
(* 1 2) ; => 2
(/ 2 1) ; => 2
; Проверка на равенство (Equality)
(= 1 1) ; => true
(= 2 1) ; => false
; Для булевой логики вам может понадобиться not
(not true) ; => false
; Вложенные формы, конечно же, допустимы и работают вполне предсказуемо
(+ 1 (- 3 2)) ; = 1 + (3 - 2) => 2
; Типы
;;;;;;;;;;;;;
; Clojure использует типы Java для представления булевых значений,
; строк и чисел
; Узнать тип мы можем, использую функцию `class
(class 1) ; Целочисленные литералы типа по-умолчанию являются java.lang.Long
(class 1.) ; Числа с плавающей точкой, это java.lang.Double
(class "") ; Строки всегда заключаются в двойные кавычки
; и представляют собой java.lang.String
(class false) ; Булевы значения, это экземпляры java.lang.Boolean
(class nil) ; "Пустое" значение называется "nil"
; Если Вы захотите создать список из чисел, вы можете просто
; предварить форму списка символом "'", который подскажет Reader`у,
; что эта форма не требует вычисления
'(+ 1 2) ; => (+ 1 2)
; ("'", это краткая запись формы (quote (+ 1 2))
; "Квотированный" список можно вычислить, передав его функции eval
(eval '(+ 1 2)) ; => 3
; Коллекции и Последовательности
;;;;;;;;;;;;;;;;;;;
; Списки (Lists) в clojure структурно представляют собой "связанные списки",
; тогда как Векторы (Vectors), устроены как массивы.
; Векторы и Списки тоже являются классами Java!
(class [1 2 3]); => clojure.lang.PersistentVector
(class '(1 2 3)); => clojure.lang.PersistentList
; Список может быть записан, как (1 2 3), но в этом случае
; он будет воспринят reader`ом, как вызов функции.
; Есть два способа этого избежать:
; '(1 2 3) - квотирование,
; (list 1 2 3) - явное конструирование списка с помощью функции list.
; "Коллекции", это некие наборы данных
; И списки, и векторы являются коллекциями:
(coll? '(1 2 3)) ; => true
(coll? [1 2 3]) ; => true
; "Последовательности" (seqs), это абстракция над наборами данных,
; элементы которых "упакованы" последовательно.
; Списки - последовательности, а вектора - нет.
(seq? '(1 2 3)) ; => true
(seq? [1 2 3]) ; => false
; Любая seq предоставляет доступ только к началу последовательности данных,
; не предоставляя информацию о её длине.
; При этом последовательности могут быть и бесконечными,
; т.к. являются ленивыми и предоставляют данные только по требованию!
(range 4) ; => (0 1 2 3)
(range) ; => (0 1 2 3 4 ...) (бесконечная последовательность!)
(take 4 (range)) ; (0 1 2 3)
; Добавить элемент в начало списка или вектора можно с помощью функции cons
(cons 4 [1 2 3]) ; => (4 1 2 3)
(cons 4 '(1 2 3)) ; => (4 1 2 3)
; Функция conj добавляет элемент в коллекцию
; максимально эффективным для неё способом.
; Для списков эффективно добавление в начло, а для векторов - в конец.
(conj [1 2 3] 4) ; => [1 2 3 4]
(conj '(1 2 3) 4) ; => (4 1 2 3)
; Функция concat объединяет несколько списков и векторов в единый список
(concat [1 2] '(3 4)) ; => (1 2 3 4)
; Работать с коллекциями удобно с помощью функций filter и map
(map inc [1 2 3]) ; => (2 3 4)
(filter even? [1 2 3]) ; => (2)
; reduce поможет "свернуть" коллекцию
(reduce + [1 2 3 4])
; = (+ (+ (+ 1 2) 3) 4)
; => 10
; Вызывая reduce, мы можем указать начальное значение
(reduce conj [] '(3 2 1))
; = (conj (conj (conj [] 3) 2) 1)
; => [3 2 1]
; Функции
;;;;;;;;;;;;;;;;;;;;;
; Функция создается специальной формой fn.
; "Тело"" функции может состоять из нескольких форм,
; но результатом вызова функции всегда будет результат вычисления
; последней из них.
(fn [] "Hello World") ; => fn
; (Вызов функции требует "оборачивания" fn-формы в форму вызова)
((fn [] "Hello World")) ; => "Hello World"
; Назначить значению имя можно специальной формой def
(def x 1)
x ; => 1
; Назначить имя можно любому значению, в т.ч. и функции:
(def hello-world (fn [] "Hello World"))
(hello-world) ; => "Hello World"
; Поскольку именование функций - очень частая операция,
; clojure позволяет, сделать это проще:
(defn hello-world [] "Hello World")
; Вектор [] в форме описания функции, следующий сразу за именем,
; описывает параметры функции:
(defn hello [name]
(str "Hello " name))
(hello "Steve") ; => "Hello Steve"
; Одна функция может иметь сразу несколько наборов аргументов:
(defn hello3
([] "Hello World")
([name] (str "Hello " name)))
(hello3 "Jake") ; => "Hello Jake"
(hello3) ; => "Hello World"
; Также функция может иметь набор аргументов переменной длины
(defn count-args [& args] ; args будет содержать seq аргументов
(str "You passed " (count args) " args: " args))
(count-args 1 2 3) ; => "You passed 3 args: (1 2 3)"
; Можно комбинировать оба подхода задания аргументов
(defn hello-count [name & args]
(str "Hello " name ", you passed " (count args) " extra args"))
(hello-count "Finn" 1 2 3)
; => "Hello Finn, you passed 3 extra args"
; Для создания анонимных функций есть специальный синтаксис:
; функциональные литералы
(def hello2 #(str "Hello " %1))
(hello2 "Fanny") ; => "Hello Fanny"
; такие функциональные литералы удобно использовать с map, filter и reduce
(map #(* 10 %1) [1 2 3 5]) ; => (10 20 30 50)
(filter #(> %1 3) [1 2 3 4 5 6 7]) ; => (4 5 6 7)
(reduce #(str %1 "," %2) [1 2 3 4]) ; => "1,2,3,4"
; Отображения (Maps)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Hash maps и array maps имеют одинаковый интерфейс.
; Hash maps производят поиск по ключу быстрее, но не сохраняют порядок ключей
(class {:a 1 :b 2 :c 3}) ; => clojure.lang.PersistentArrayMap
(class (hash-map :a 1 :b 2 :c 3)) ; => clojure.lang.PersistentHashMap
; Array maps автоматически преобразуются в hash maps,
; как только разрастутся до определенного размера
; Отображения могут использовать в качестве ключей любые хэшируемые значения,
; однако предпочтительными являются ключи,
; являющиеся "ключевыми словами" (keywords)
(class :a) ; => clojure.lang.Keyword
(def stringmap {"a" 1, "b" 2, "c" 3})
stringmap ; => {"a" 1, "b" 2, "c" 3}
(def keymap {:a 1, :b 2, :c 3})
keymap ; => {:a 1, :c 3, :b 2}
; Предыдущий пример содержит запятые в коде, однако reader не использует их,
; при обработке литералов - запятые просто воспринимаются,
; как "пробельные символы" (whitespaces)
; Отображение может выступать в роли функции, возвращающей значение по ключу
(stringmap "a") ; => 1
(keymap :a) ; => 1
; При попытке получить отсутствующее значение, будет возвращён nil
(stringmap "d") ; => nil
; Иногда бывает удобно указать конкретное значение по-умолчанию:
({:a 1 :b 2} :c "Oops!") ; => "Oops!"
; Keywords тоже могут использоваться в роли функций!
(:b keymap) ; => 2
; Однако этот фокус не пройдёт со строками.
;("a" stringmap)
; => Exception: java.lang.String cannot be cast to clojure.lang.IFn
; Добавить пару ключ-значение в отображение можно функцией assoc
(def newkeymap (assoc keymap :d 4))
newkeymap ; => {:a 1, :b 2, :c 3, :d 4}
; Но всегда следует помнить, что значения в Clojure - неизменяемые!
keymap ; => {:a 1, :b 2, :c 3} - оригинал не был затронут
; dissoc позволяет исключить значение по ключу
(dissoc keymap :a :b) ; => {:c 3}
; Множества (Sets)
;;;;;;;;;;;;;;;;;;
(class #{1 2 3}) ; => clojure.lang.PersistentHashSet
(set [1 2 3 1 2 3 3 2 1 3 2 1]) ; => #{1 2 3}
; Добавляются элементы посредством conj
(conj #{1 2 3} 4) ; => #{1 2 3 4}
; Исключаются - посредством disj
(disj #{1 2 3} 1) ; => #{2 3}
; Вызов множества, как функции, позволяет проверить
; принадлежность элемента этому множеству:
(#{1 2 3} 1) ; => 1
(#{1 2 3} 4) ; => nil
; В пространстве имен clojure.sets
; содержится множество функций для работы с множествами
; Полезные формы
;;;;;;;;;;;;;;;;;
; Конструкции ветвления в clojure, это обычные макросы
; и подобны их собратьям в других языках:
(if false "a" "b") ; => "b"
(if false "a") ; => nil
; Специальная форма let позволяет присвоить имена значениям локально.
; При этом все изменения будут видны только вложенным формам:
(def a 10)
(let [a 1 b 2]
(> a b)) ; => false
; Несколько форм можно объединить в одну форму посредством do
; Значением do-формы будет значение последней формы из списка вложенных в неё:
(do
(print "Hello")
"World") ; => "World" (prints "Hello")
; Множество макросов содержит внутри себя неявную do-форму.
; Пример - макрос определения функции:
(defn print-and-say-hello [name]
(print "Saying hello to " name)
(str "Hello " name))
(print-and-say-hello "Jeff") ;=> "Hello Jeff" (prints "Saying hello to Jeff")
; Ещё один пример - let:
(let [name "Urkel"]
(print "Saying hello to " name)
(str "Hello " name)) ; => "Hello Urkel" (prints "Saying hello to Urkel")
; Модули
;;;;;;;;;
; Форма "use" позволяет добавить в текущее пространство имен
; все имена (вместе со значениями) из указанного модуля:
(use 'clojure.set)
; Теперь нам доступны операции над множествами:
(intersection #{1 2 3} #{2 3 4}) ; => #{2 3}
(difference #{1 2 3} #{2 3 4}) ; => #{1}
; use позволяет указать, какие конкретно имена
; должны быть импортированы из модуля:
(use '[clojure.set :only [intersection]])
; Также модуль может быть импортирован формой require
(require 'clojure.string)
; После этого модуль становится доступе в текущем пространстве имен,
; а вызов его функций может быть осуществлен указанием полного имени функции:
(clojure.string/blank? "") ; => true
; Импортируемому модулю можно назначить короткое имя:
(require '[clojure.string :as str])
(str/replace "This is a test." #"[a-o]" str/upper-case) ; => "THIs Is A tEst."
; (Литерал вида #"" обозначает регулярное выражение)
; Вместо отдельной формы require (и use, хотя это и не приветствуется) можно
; указать необходимые модули прямо в форме ns:
(ns test
(:require
[clojure.string :as str] ; Внимание: при указании внутри формы ns
[clojure.set :as set])) ; имена пакетов не квотируются!
; Java
;;;;;;;
; Стандартная библиотека Java очень богата,
; и всё это богатство доступно и для Clojure!
; import позволяет импортировать модули Java
(import java.util.Date)
; В том числе и из ns
(ns test
(:import java.util.Date
java.util.Calendar))
; Имя класса, сопровождаемое символом "." позволяет
; инстанцировать объекты Java-классов:
(Date.) ; <a date object>
; форма . позволяет вызывать методы:
(. (Date.) getTime) ; <a timestamp>
(.getTime (Date.)) ; а можно и так
; Статические методы вызываются как функции модуля:
(System/currentTimeMillis) ; <a timestamp> (Модуль system всегда доступен!)
; doto позволяет удобно работать с объектами, изменяющими свое состояние
(import java.util.Calendar)
(doto (Calendar/getInstance)
(.set 2000 1 1 0 0 0)
.getTime) ; => A Date. set to 2000-01-01 00:00:00
; Работа с изменяемым сотоянием
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Clojure предоставляет набор инструментов
; для работы с изменяемым состоянием: Software Transactional Memory.
; Структуры STM представлены тремя типами:
; - атомы (atoms)
; - агенты (agents)
; - ссылки (references)
; Самые простые хранители состояния - атомы:
(def my-atom (atom {})) ; {} - начальное состояние атома
; Обновляется атом посредством swap!.
; swap! применяет функцию аргумент к текущему значению
; атома и помещает в атом результат
(swap! my-atom assoc :a 1) ; Обновляет my-atom, помещая в него (assoc {} :a 1)
(swap! my-atom assoc :b 2) ; Обновляет my-atom, помещая в него (assoc {:a 1} :b 2)
; Получить значение атома можно посредством '@'
; (провести так называемую операцию dereference)
my-atom ;=> Atom<#...> (Возвращает объект типа Atom)
@my-atom ; => {:a 1 :b 2}
; Пример реализации счётчика на атоме
(def counter (atom 0))
(defn inc-counter []
(swap! counter inc))
(inc-counter)
(inc-counter)
(inc-counter)
(inc-counter)
(inc-counter)
@counter ; => 5
; С другими STM-конструкциями - refs и agents - можно ознакомиться тут:
; Refs: http://clojure.org/refs
; Agents: http://clojure.org/agents
```
### Для будущего чтения
Это руководство не претендует на полноту, но мы смеем надеяться, способно вызвать интерес к дальнейшему изучению языка.
Clojure.org - сайт содержит большое количество статей по языку:
[http://clojure.org/](http://clojure.org/)
Clojuredocs.org - сайт документации языка с примерами использования функций:
[http://clojuredocs.org/quickref/Clojure%20Core](http://clojuredocs.org/quickref/Clojure%20Core)
4Clojure - отличный способ закрепить навыки программирования на clojure, решая задачи вместе с коллегами со всего мира:
[http://www.4clojure.com/](http://www.4clojure.com/)
Clojure-doc.org (да, именно) неплохой перечень статей для начинающих:
[http://clojure-doc.org/](http://clojure-doc.org/)

658
ru-ru/php-ru.html.markdown Normal file
View File

@@ -0,0 +1,658 @@
---
language: php
contributors:
- ["Malcolm Fell", "http://emarref.net/"]
- ["Trismegiste", "https://github.com/Trismegiste"]
- ["SlaF", "https://github.com/SlaF"]
lang: ru-ru
filename: learnphp-ru.php
---
Этот документ описывает версию PHP 5 и выше.
```php
<?php // PHP код должен быть заключен в теги <?php
// Если ваш файл содержит только PHP код, то можно
// пропустить закрывающийся ?>
// А так начинаются комментарии
# Это тоже комментарий но // предпочтительнее
/*
Окруженный /* и */ текст превращается
в многострочный комментарий
*/
// Используйте "echo" или "print" для вывода.
print('Hello '); // Напечатать "Hello " без перевода строки
// () необязательно применять для print и echo
echo "World\n"; // Печатать "World" и перейти на новую строку.
// (все утверждения должны заканчиваться ;)
// Любые символы за пределами закрывающегося тега выводятся автоматически:
?>
Hello World Again!
<?php
/************************************
* Типы и Переменные
*/
// Переменные начинаются с символа $.
// Правильное имя переменной начинается с буквы или знака подчеркивания,
// и может содержать любые цифры, буквы, или знаки подчеркивания.
// Не рекомендуется использовать кирилические символы в именах (прим. пер.)
// Логические значения нечувствительны к регистру
$boolean = true; // или TRUE или True
$boolean = false; // или FALSE или False
// Целые числа
$int1 = 12; // => 12
$int2 = -12; // => -12-
$int3 = 012; // => 10 (ведущий 0 обозначает восьмеричное число)
$int4 = 0x0F; // => 15 (ведущие символы 0x означает шестнадцатеричное число)
// Дробные числа
$float = 1.234;
$float = 1.2e3;
$float = 7E-10;
// Арифметика
$sum = 1 + 1; // 2
$difference = 2 - 1; // 1
$product = 2 * 2; // 4
$quotient = 2 / 1; // 2
// Арифметические сокращения
$number = 0;
$number += 1; // Увеличивает $number на 1
echo $number++; // Печатает 1 (инкрементируется после вывода)
echo ++$number; // Печатает 3 (инкрементируется до вывода)
$number /= $float; // Делится и результат присваивается $number
// Строки должны быть заключены в одинарные кавычки;
$sgl_quotes = '$String'; // => '$String'
// Избегайте двойных кавычек за исключением случаев интерполирования переменной
$dbl_quotes = "This is a $sgl_quotes."; // => 'This is a $String.'
// Специальные (escape) символы работают только в двойных кавычках
$escaped = "This contains a \t tab character.";
$unescaped = 'This just contains a slash and a t: \t';
// Заключайте переменные в фигурные скобки если это необходимо
$money = "I have $${number} in the bank.";
// Начиная с PHP 5.3, синтаксис nowdocs может использоваться для неинтерполированного многострочного текста
$nowdoc = <<<'END'
Multi line
string
END;
// Heredocs поддерживает интерполяцию переменных
$heredoc = <<<END
Multi line
$sgl_quotes
END;
// Строки соединяются при помощи .
echo 'This string ' . 'is concatenated';
/********************************
* Константы
*/
// Константа определяется при помощи define()
// и никогда не может быть изменена во время выполнения программы!
// Правильное имя константы начинается с буквы или символа подчеркивания,
// и содержит любое колличество букв, цифр и знаков подчеркивания.
define("FOO", "something");
// Доступ к константе возможен через прямое указание её имени
echo 'This outputs '.FOO;
/********************************
* Массивы
*/
// Все массивы в PHP - это ассоциативные массивы или хеши,
// Ассоциативные массивы, известные в других языках как хеш-карты.
// Работает во всех версиях РHP
$associative = array('One' => 1, 'Two' => 2, 'Three' => 3);
// В PHP 5.4 появился новый синтаксис
$associative = ['One' => 1, 'Two' => 2, 'Three' => 3];
echo $associative['One']; // печатает 1
// Список тоже содержит целочисленные ключи
$array = ['One', 'Two', 'Three'];
echo $array[0]; // => "One"
/********************************
* Вывод
*/
echo('Hello World!');
// Печатает Hello World! на stdout.
// Stdout это веб-страница запущенная в браузере.
print('Hello World!'); // Аналогично echo
// echo - это конструкция языка, вы можете опустить скобки.
echo 'Hello World!';
print 'Hello World!'; // Выводит Hello World!
$paragraph = 'paragraph';
echo 100; // Печать скалярной переменной напрямую
echo $paragraph; // или печать переменной
// Если короткие теги разрешены, или ваша версия PHP >= 5.4
// вы можете использовать сокращенный синтаксис echo
?>
<p><?= $paragraph ?></p>
<?php
$x = 1;
$y = 2;
$x = $y; // $x теперь содержит значение переменной $y
$z = &$y;
// $z содержит ссылку на $y. Изменение значения $z затронет значение $y и наоборот.
// Значение $x остается неизменным.
echo $x; // => 2
echo $z; // => 2
$y = 0;
echo $x; // => 2
echo $z; // => 0
/********************************
* Логические выражения
*/
$a = 0;
$b = '0';
$c = '1';
$d = '1';
// Утверждение (assert) выдает предупреждение если аргумент не true
// Эти сравнения всегда будут истинными, даже если типы будут различаться
assert($a == $b); // "равно"
assert($c != $a); // "не равно"
assert($c <> $a); // другое обозначение "не равно"
assert($a < $c); // меньше
assert($c > $b); // больше
assert($a <= $b); // меньше или равно
assert($c >= $d); // больше или равно
// Следующие утверждения истинны если переменные имеют одинаковый тип.
assert($c === $d);
assert($a !== $d);
assert(1 == '1');
assert(1 !== '1');
// Переменные могут изменять тип, в зависимости от их использования.
$integer = 1;
echo $integer + $integer; // => 2
$string = '1';
echo $string + $string; // => 2 (строка превращается в число)
// Выводится 0 по той причине, что оператор + не может привести строку 'one' к числовому типу
$string = 'one';
echo $string + $string; // => 0
// Приведение типов (type casting) может быть использовано для преобразование переменной в другой тип
$boolean = (boolean) 1; // => true
$zero = 0;
$boolean = (boolean) $zero; // => false
// Также существуют функции выполняющие приведение типов
$integer = 5;
$string = strval($integer);
$float = floatval($integer);
$var = null; // Null
// И похожая по действию функция
$integer = 10;
$boolen = settype($integer, "string") // теперь $integer имеет строковый тип
// settype возвращает true - если преобразование удалось и false в противном случае
/********************************
* Управляющие структуры
*/
if (true) {
print 'I get printed';
}
if (false) {
print 'I don\'t';
} else {
print 'I get printed';
}
if (false) {
print 'Does not get printed';
} elseif(true) {
print 'Does';
}
// Тернарный оператор
print (false ? 'Does not get printed' : 'Does');
$x = 0;
if ($x === '0') {
print 'Does not print';
} elseif($x == '1') {
print 'Does not print';
} else {
print 'Does print';
}
// Альтернативный синтаксис полезный для шаблонов
?>
<?php if ($x): ?>
This is displayed if the test is truthy.
<?php else: ?>
This is displayed otherwise.
<?php endif; ?>
<?php
// Использование switch.
switch ($x) {
case '0':
print 'Switch does type coercion';
break; // You must include a break, or you will fall through
// to cases 'two' and 'three'
case 'two':
case 'three':
// Do something if $variable is either 'two' or 'three'
break;
default:
// Do something by default
}
// Циклы: while, do...while и for
$i = 0;
while ($i < 5) {
echo $i++;
}; // Prints "01234"
echo "\n";
$i = 0;
do {
echo $i++;
} while ($i < 5); // Prints "01234"
echo "\n";
for ($x = 0; $x < 10; $x++) {
echo $x;
} // Prints "0123456789"
echo "\n";
$wheels = ['bicycle' => 2, 'car' => 4];
// Циклы foreach могут обходить массивы
foreach ($wheels as $wheel_count) {
echo $wheel_count;
} // Prints "24"
echo "\n";
// Вы можете обходить как ключи, так и их значения
foreach ($wheels as $vehicle => $wheel_count) {
echo "A $vehicle has $wheel_count wheels";
}
echo "\n";
$i = 0;
while ($i < 5) {
if ($i === 3) {
break; // Exit out of the while loop
}
echo $i++;
} // Prints "012"
for ($i = 0; $i < 5; $i++) {
if ($i === 3) {
continue; // Skip this iteration of the loop
}
echo $i;
} // Prints "0124"
/********************************
* Функции
*/
// Определение функции:
function my_function () {
return 'Hello';
}
echo my_function(); // => "Hello"
// Правильное имя функции начинается с буквы или символа подчеркивания
// и состоит из букв, цифр или знаков подчеркивания.
function add ($x, $y = 1) { // $y по умолчанию равно 1
$result = $x + $y;
return $result;
}
echo add(4); // => 5
echo add(4, 2); // => 6
// $result недоступна за пределами функции
// print $result; // Выдает предупреждение
// Начиная с PHP 5.3 вы можете объявлять анонимные функции:
$inc = function ($x) {
return $x + 1;
};
echo $inc(2); // => 3
function foo ($x, $y, $z) {
echo "$x - $y - $z";
}
// Функции могут возвращать функции
function bar ($x, $y) {
// Используйте 'use' для передачи внешних переменных
return function ($z) use ($x, $y) {
foo($x, $y, $z);
};
}
$bar = bar('A', 'B');
$bar('C'); // Prints "A - B - C"
// Вы можете вызывать именованные функции используя строки
$function_name = 'add';
echo $function_name(1, 2); // => 3
// Полезно для программного определения запущенной функции.
// Или используйте call_user_func(callable $callback [, $parameter [, ... ]]);
/********************************
* Includes
*/
<?php
// PHP код внутри включаемого файла должен начинаться с тега PHP.
include 'my-file.php';
// Код в файле my-file.php теперь доступен в текущем в текущем пространстве имен.
// Если файл не удалось включить, будет выдано предупреждение.
include_once 'my-file.php';
// Если код в файле my-file.php уже был включен, он не будет включен повторно.
// Это предотвращает ошибку повторного включения файла.
require 'my-file.php';
require_once 'my-file.php';
// Same as include(), except require() will cause a fatal error if the
// file cannot be included.
// Действует также как и include(), но если файл не удалось подключить,
// функция выдает неисправимую ошибку
// Содержимое файла my-include.php:
<?php
return 'Anything you like.';
// Конец файла
// Эти функции могут также возвращать значения.
$value = include 'my-include.php';
// Имена файлов содержат их путь в файловой системе, или если передано просто имя файла,
// PHP обращается к директиве include_path. Если файл не найден в include_path, предпринимается
// попытка поиска в папке, где выполняется скрипт или в текущей рабочей директории.
// Если не в одном из этих мест файл не найден - выдается ошибка
/* */
/********************************
* Классы
*/
// Классы определяются при помощи ключевого слова "class"
class MyClass
{
const MY_CONST = 'value'; // A constant
static $staticVar = 'static';
// Properties must declare their visibility
public $property = 'public';
public $instanceProp;
protected $prot = 'protected'; // Accessible from the class and subclasses
private $priv = 'private'; // Accessible within the class only
// Create a constructor with __construct
public function __construct($instanceProp) {
// Access instance variables with $this
$this->instanceProp = $instanceProp;
}
// Methods are declared as functions inside a class
public function myMethod()
{
print 'MyClass';
}
final function youCannotOverrideMe()
{
}
public static function myStaticMethod()
{
print 'I am static';
}
}
echo MyClass::MY_CONST; // Выведет 'value';
echo MyClass::$staticVar; // Выведет 'static';
MyClass::myStaticMethod(); // Выведет 'I am static';
// Новый экземпляр класса используя new
$my_class = new MyClass('An instance property');
// Если аргументы отсутствуют, можно не ставить круглые скобки
// Доступ к членам класса используя ->
echo $my_class->property; // => "public"
echo $my_class->instanceProp; // => "An instance property"
$my_class->myMethod(); // => "MyClass"
// Наследование классов используя "extends"
class MyOtherClass extends MyClass
{
function printProtectedProperty()
{
echo $this->prot;
}
// Override a method
function myMethod()
{
parent::myMethod();
print ' > MyOtherClass';
}
}
$my_other_class = new MyOtherClass('Instance prop');
$my_other_class->printProtectedProperty(); // => Выведет "protected"
$my_other_class->myMethod(); // Выведет "MyClass > MyOtherClass"
final class YouCannotExtendMe
{
}
// Вы можете использовать "магические методы" для создания геттеров и сеттеров
class MyMapClass
{
private $property;
public function __get($key)
{
return $this->$key;
}
public function __set($key, $value)
{
$this->$key = $value;
}
}
$x = new MyMapClass();
echo $x->property; // Будет использован метод __get()
$x->property = 'Something'; // Будет использован метод __set()
// Классы могут быть абстрактными (используя ключевое слово abstract)
// или реализовывать интерфейсы (используя ключевое слово implements).
// Интерфейсы определяются при помощи ключевого слова interface
interface InterfaceOne
{
public function doSomething();
}
interface InterfaceTwo
{
public function doSomethingElse();
}
// Интерфейсы могут быть расширены
interface InterfaceThree extends InterfaceTwo
{
public function doAnotherContract();
}
abstract class MyAbstractClass implements InterfaceOne
{
public $x = 'doSomething';
}
class MyConcreteClass extends MyAbstractClass implements InterfaceTwo
{
public function doSomething()
{
echo $x;
}
public function doSomethingElse()
{
echo 'doSomethingElse';
}
}
// Классы могут реализовывать более одного интерфейса
class SomeOtherClass implements InterfaceOne, InterfaceTwo
{
public function doSomething()
{
echo 'doSomething';
}
public function doSomethingElse()
{
echo 'doSomethingElse';
}
}
/********************************
* Трейты
*/
// Трейты появились в PHP 5.4.0 и объявляются при помощи ключевого слова trait
trait MyTrait
{
public function myTraitMethod()
{
print 'I have MyTrait';
}
}
class MyTraitfulClass
{
use MyTrait;
}
$cls = new MyTraitfulClass();
$cls->myTraitMethod(); // Prints "I have MyTrait"
/********************************
* Пространства имен
*/
// Это секция особая, ведь объявление пространства имен
// должно быть самым первым в файле. Позвольте сделать вид, что это не так
<?php
// По умолчанию, классы существуют в глобальном пространстве имен и могут быть
// вызваны с обратным слешем.
$cls = new \MyClass();
// Задание пространства имен файла
namespace My\Namespace;
class MyClass
{
}
// (из другого файла)
$cls = new My\Namespace\MyClass;
// Или внутри другого пространства имен.
namespace My\Other\Namespace;
use My\Namespace\MyClass;
$cls = new MyClass();
// Или вы можете создать псевдоним для пространства имен:
namespace My\Other\Namespace;
use My\Namespace as SomeOtherNamespace;
$cls = new SomeOtherNamespace\MyClass();
*/
```
## Смотрите также:
Посетите страницу [официальной документации PHP](http://www.php.net/manual/) для справки.
Если вас интересуют полезные приемы использования PHP посетите [PHP The Right Way](http://www.phptherightway.com/).
Если вы раньше пользовались языком с хорошей организацией пакетов, посмотрите [Composer](http://getcomposer.org/).
Для изучения стандартов использования языка посетите PHP Framework Interoperability Group's [PSR standards](https://github.com/php-fig/fig-standards).

View File

@@ -0,0 +1,486 @@
---
language: python
contributors:
- ["Yury Timofeev", "http://twitter.com/gagar1n"]
filename: learnpython-ru.py
---
Язык Python был создан Гвидо ван Россумом в ранние 90-е. Сегодня это один из самых популярных
языков. Я влюбился в него благодаря его понятному и доходчивому синтаксису - это почти что исполняемый псевдокод.
Обратная связь будет высоко оценена! Вы можете связаться со мной: [@louiedinh](http://twitter.com/louiedinh) или louiedinh [at] [google's email service]
Замечание: Эта статья относится к Python 2.7, но должна быть применима к Python 2.x. Скоро ожидается версия и для Python 3!
```python
# Однострочные комментарии начинаются с hash-символа.
""" Многострочный текст может быть
записан, используя 3 знака " и обычно используется
в качестве комментария
"""
####################################################
## 1. Примитивные типы данных и операторв
####################################################
# У вас есть числа
3 #=> 3
# Математика работает так, как вы и думаете
1 + 1 #=> 2
8 - 1 #=> 7
10 * 2 #=> 20
35 / 5 #=> 7
# Деление немного сложнее. Это деление целых чисел и результат
# автоматически округляется в меньшую сторону.
5 / 2 #=> 2
# Чтобы научиться делить, сначала нужно немного узнать о дробных числах.
2.0 # Это дробное число.
11.0 / 4.0 #=> 2.75 вооот... гораздо лучше
# Приоритет операций указывается скобками
(1 + 3) * 2 #=> 8
# Логические значения являются примитивами
True
False
# Для отрицания используется ключевое слово not
not True #=> False
not False #=> True
# Равенство это ==
1 == 1 #=> True
2 == 1 #=> False
# Неравенство это !=
1 != 1 #=> False
2 != 1 #=> True
# Больше сравнений
1 < 10 #=> True
1 > 10 #=> False
2 <= 2 #=> True
2 >= 2 #=> True
# Сравнения могут быть соединены в цепь!
1 < 2 < 3 #=> True
2 < 3 < 2 #=> False
# Строки создаются при символом " или '
"Это строка."
'Это тоже строка.'
# Строки тоже могут складываться!
"Привет " + "мир!" #=> "Привет мир!"
# Со строкой можно работать как со списком символов
"Это строка"[0] #=> 'Э'
# % используется для форматирования строк, например:
"%s могут быть %s" % ("строки", "интерполированы")
# Новый метод форматирования строк - использование метода format.
# Это предпочитаемый способ.
"{0} могут быть {1}".format("строки", "форматированы")
# Вы можете использовать ключевые слова, если не хотите считать.
"{name} хочет есть {food}".format(name="Боб", food="лазанью")
# None является объектом
None #=> None
# Не используйте оператор равенства `==` для сравнения
# объектов с None. Используйте для этого `is`
"etc" is None #=> False
None is None #=> True
# Оператор 'is' проверяет идентичность объектов. Он не
# очень полезен при работе с примитивными типами, но
# очень полезен при работе с объектами.
# None, 0, и пустые строки/списки равны False.
# Все остальные значения равны True
0 == False #=> True
"" == False #=> True
####################################################
## 2. Переменные и коллекции
####################################################
# Печать довольно проста
print "Я Python. Приятно познакомиться!"
# Необязательно объявлять переменные перед присваиванием им значения.
some_var = 5 # По соглашению используется нижний_регистр_с_подчеркиваниями
some_var #=> 5
# При попытке доступа к переменной, которой не было ранее присвоено значение,
# выбрасывается исключение.
# См. раздел "Поток управления" для информации об исключениях.
some_other_var # Выбрасывает ошибку именования
# if может быть использован как выражение
"yahoo!" if 3 > 2 else 2 #=> "yahoo!"
# Списки хранят последовательности
li = []
# Можно сразу начать с заполненным списком
other_li = [4, 5, 6]
# Объекты добавляются в конец списка методом append
li.append(1) #li содержит [1]
li.append(2) #li содержит [1, 2]
li.append(4) #li содержит [1, 2, 4]
li.append(3) #li содержит [1, 2, 4, 3]
# Удаляются с конца методом pop
li.pop() #=> 3 и li содержит [1, 2, 4]
# Положим его обратно
li.append(3) # li содержит [1, 2, 4, 3] опять.
# Обращайтесь со списком, как с обычным массивом
li[0] #=> 1
# Посмотрим на последний элемент
li[-1] #=> 3
# Попытка выйти за границы массива приводит к IndexError
li[4] # Выдает IndexError
# Можно обращаться к диапазону, используя "кусочный синтаксис" (slice syntax)
# (Для тех из вас, кто любит математику, это замкнуто/открытый интервал.)
li[1:3] #=> [2, 4]
# Опускаем начало
li[2:] #=> [4, 3]
# Опускаем конец
li[:3] #=> [1, 2, 4]
# Удаляем произвольные элементы из списка оператором del
del li[2] # li содержит [1, 2, 3]
# Вы можете складывать списки
li + other_li #=> [1, 2, 3, 4, 5, 6] - ЗАмечание: li и other_li остаются нетронутыми
# Конкатенировать списки можно методом extend
li.extend(other_li) # Теперь li содержит [1, 2, 3, 4, 5, 6]
# Проверять элемент на вхождение на список оператором in
1 in li #=> True
# Длина списка вычисляется при помощи len
len(li) #=> 6
# Кортежи - это как списки, только неизменяемые
tup = (1, 2, 3)
tup[0] #=> 1
tup[0] = 3 # Выдает TypeError
# Все те же штуки можно делать и с кортежами
len(tup) #=> 3
tup + (4, 5, 6) #=> (1, 2, 3, 4, 5, 6)
tup[:2] #=> (1, 2)
2 in tup #=> True
# Вы можете распаковывать кортежи (или списки) в переменные
a, b, c = (1, 2, 3) # a теперь равно 1, b равно 2 и c равно 3
# Кортежи создаются по умолчанию, если опущены скобки
d, e, f = 4, 5, 6
# Обратите внимание, как легко поменять местами значения двух переменных
e, d = d, e # d теперь равно 5 and e равно 4
# Словари содержат ассоциативные массивы
empty_dict = {}
# Вот так описывается предзаполненный словарь
filled_dict = {"one": 1, "two": 2, "three": 3}
# Значения ищутся по ключу с помощью оператора []
filled_dict["one"] #=> 1
# Можно получить все ключи в виде списка
filled_dict.keys() #=> ["three", "two", "one"]
# Замечание - сохранение порядка ключей в словаре не гарантируется
# Ваши результаты могут не совпадать с этими.
# Можно получить и все значения в виде списка
filled_dict.values() #=> [3, 2, 1]
# Замечание - то же самое, что и выше, насчет порядка ключей
# При помощи оператора in можно проверять ключи на вхождение в словарь
"one" in filled_dict #=> True
1 in filled_dict #=> False
# Попытка получить значение по несуществующему ключу выбросит KeyError
filled_dict["four"] # KeyError
# Чтобы избежать этого, используйте метод get
filled_dict.get("one") #=> 1
filled_dict.get("four") #=> None
# Метод get также принимает аргумент default, значение которого будет возвращено при отсутствии указанного ключа
filled_dict.get("one", 4) #=> 1
filled_dict.get("four", 4) #=> 4
# Метод setdefault - это безопасный способ добавить новую пару ключ-значение в словарь
filled_dict.setdefault("five", 5) #filled_dict["five"] возвращает 5
filled_dict.setdefault("five", 6) #filled_dict["five"] по прежнему возвращает 5
# Множества содержат... ну, в общем, множества
empty_set = set()
# Инициализация множества набором значений
some_set = set([1,2,2,3,4]) # some_set теперь равно set([1, 2, 3, 4])
# Начиная с Python 2.7, вы можете использовать {} чтобы обьявить множество
filled_set = {1, 2, 2, 3, 4} # => {1 2 3 4}
# Добавление новых элементов в множество
filled_set.add(5) # filled_set равно {1, 2, 3, 4, 5}
# Пересечение множеств: &
other_set = {3, 4, 5, 6}
filled_set & other_set #=> {3, 4, 5}
# Объединение множеств: |
filled_set | other_set #=> {1, 2, 3, 4, 5, 6}
# Разность множеств: -
{1,2,3,4} - {2,3,5} #=> {1, 4}
# Проверка на вхождение во множество: in
2 in filled_set #=> True
10 in filled_set #=> False
####################################################
## 3. Поток управления
####################################################
# Давайте заведем переменную
some_var = 5
# Так выглядит выражение if. Отступы в python очень важны!
# результат: "some_var меньше, чем 10"
if some_var > 10:
print "some_var намного больше, чем 10."
elif some_var < 10: # Выражение elif необязательно.
print "some_var меньше, чем 10."
else: # Это тоже необязательно.
print "some_var равно 10."
"""
Циклы For проходят по циклам
результат:
собака это млекопитающее
кошка это млекопитающее
мышь это млекопитающее
"""
for animal in ["собака", "кошка", "мышь"]:
# Можете использовать оператор % для интерполяции форматированных строк
print "%s это млекопитающее" % animal
"""
`range(number)` возвращает список чисел
от нуля до заданного числа
результат:
0
1
2
3
"""
for i in range(4):
print i
"""
Циклы while продолжаются до тех пор, пока указанное условие не станет ложным.
результат:
0
1
2
3
"""
x = 0
while x < 4:
print x
x += 1 # То же самое, что x = x + 1
# Обрабывайте исключения блоками try/except
# Работает в Python 2.6 и выше:
try:
# Для выбора ошибки используется raise
raise IndexError("Это IndexError")
except IndexError as e:
pass # pass это просто отсутствие оператора. Обычно здесь происходит восстановление от ошибки.
####################################################
## 4. Функции
####################################################
# Используйте def для создания новых функций
def add(x, y):
print "x равен %s, а y равен %s" % (x, y)
return x + y # Возвращайте результат выражением return
# Вызов функции с аргументами
add(5, 6) #=> prints out "x равен 5, а y равен 6" и возвращает 11
# Другой способ вызова функции с аргументами
add(y=6, x=5) # Именованные аргументы можно указывать в любом порядке.
# Вы можете определить функцию, принимающую неизвестное количество аргументов
def varargs(*args):
return args
varargs(1, 2, 3) #=> (1,2,3)
# А также можете определить функцию, принимающую изменяющееся количество
# именованных аргументов
def keyword_args(**kwargs):
return kwargs
# Вызовем эту функцию и посмотрим, что из этого получится
keyword_args(big="foot", loch="ness") #=> {"big": "foot", "loch": "ness"}
# Если хотите, можете использовать оба способа одновременно
def all_the_args(*args, **kwargs):
print args
print kwargs
"""
all_the_args(1, 2, a=3, b=4) выводит:
(1, 2)
{"a": 3, "b": 4}
"""
# Вызывая функции, можете сделать наоборот!
# Используйте символ * для передачи кортежей и ** для передачи словарей
args = (1, 2, 3, 4)
kwargs = {"a": 3, "b": 4}
all_the_args(*args) # эквивалент foo(1, 2, 3, 4)
all_the_args(**kwargs) # эквивалент foo(a=3, b=4)
all_the_args(*args, **kwargs) # эквивалент foo(1, 2, 3, 4, a=3, b=4)
# Python имеет функции первого класса
def create_adder(x):
def adder(y):
return x + y
return adder
add_10 = create_adder(10)
add_10(3) #=> 13
# Также есть и анонимные функции
(lambda x: x > 2)(3) #=> True
# Есть встроенные функции высшего порядка
map(add_10, [1,2,3]) #=> [11, 12, 13]
filter(lambda x: x > 5, [3, 4, 5, 6, 7]) #=> [6, 7]
# Мы можем использовать списки для удобного отображения и фильтрации
[add_10(i) for i in [1, 2, 3]] #=> [11, 12, 13]
[x for x in [3, 4, 5, 6, 7] if x > 5] #=> [6, 7]
####################################################
## 5. Классы
####################################################
# Чтобы получить класс, мы наследуемся от object.
class Human(object):
# Атрибут класса. Он разделяется всеми экземплярами этого класса
species = "H. sapiens"
# Обычный конструктор
def __init__(self, name):
# Присваивание значения аргумента атрибуту класса name
self.name = name
# Метод экземпляра. Все методы принимают self в качестве первого аргумента
def say(self, msg):
return "%s: %s" % (self.name, msg)
# Метод класса разделяется между всеми экземплярами
# Они вызываются с указыванием вызывающего класса в качестве первого аргумента
@classmethod
def get_species(cls):
return cls.species
# Статический метод вызывается без ссылки на класс или экземпляр
@staticmethod
def grunt():
return "*grunt*"
# Инстанцирование класса
i = Human(name="Иван")
print i.say("привет") # выводит "Иван: привет"
j = Human("Петр")
print j.say("Привет") #выводит "Петр: привет"
# Вызов метода класса
i.get_species() #=> "H. sapiens"
# Присвоение разделяемому атрибуту
Human.species = "H. neanderthalensis"
i.get_species() #=> "H. neanderthalensis"
j.get_species() #=> "H. neanderthalensis"
# Вызов статического метода
Human.grunt() #=> "*grunt*"
####################################################
## 6. Модули
####################################################
# Вы можете импортировать модули
import math
print math.sqrt(16) #=> 4
# Вы можете импортировать отдельные функции модуля
from math import ceil, floor
print ceil(3.7) #=> 4.0
print floor(3.7) #=> 3.0
# Можете импортировать все функции модуля.
# Предупреждение: не рекомендуется
from math import *
# Можете сокращать имена модулей
import math as m
math.sqrt(16) == m.sqrt(16) #=> True
# Модули в Python это обычные файлы с кодом python. Вы
# можете писать свои модули и импортировать их. Название
# модуля совпадает с названием файла.
# Вы можете узнать, какие функции и атрибуты определены
# в модуле
import math
dir(math)
```
## Хочется большего?
### Бесплатные онлайн-материалы
* [Learn Python The Hard Way](http://learnpythonthehardway.org/book/)
* [Dive Into Python](http://www.diveintopython.net/)
* [The Official Docs](http://docs.python.org/2.6/)
* [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/)
* [Python Module of the Week](http://pymotw.com/2/)
### Готовьте деньги
* [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)

View File

@@ -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.

View File

@@ -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

279
zh-cn/go-zh.html.markdown Normal file
View File

@@ -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赋值0p不再是空的了。
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来声明一个slicemake会分配和初始化slicemap和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标准库的源代码全部文档化了可读性非常好可以学到gogo style和go idioms。在文档中点击函数名源代码就出来了