mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2025-08-19 13:02:14 +02:00
Merge branch 'master' of https://github.com/adambard/learnxinyminutes-docs
This commit is contained in:
677
c.html.markdown
677
c.html.markdown
@@ -1,23 +1,25 @@
|
||||
---
|
||||
name: c
|
||||
category: language
|
||||
language: c
|
||||
filename: learnc.c
|
||||
contributors:
|
||||
- ["Adam Bard", "http://adambard.com/"]
|
||||
- name: c
|
||||
- category: language
|
||||
- language: c
|
||||
- filename: learnc.c
|
||||
- contributors:
|
||||
- [Adam Bard](http://adambard.com/)
|
||||
- [Árpád Goretity](http://twitter.com/H2CO3_iOS)
|
||||
|
||||
---
|
||||
|
||||
Ah, C. Still the language of modern high-performance computing.
|
||||
Ah, C. Still **the** language of modern high-performance computing.
|
||||
|
||||
C is the lowest-level language most programmers will ever use, but
|
||||
it more than makes up for it with raw speed. Just be aware of its manual
|
||||
memory management and C will take you as far as you need to go.
|
||||
|
||||
```c
|
||||
// Single-line comments start with //
|
||||
// Single-line comments start with // - only available in C99 and later.
|
||||
|
||||
/*
|
||||
Multi-line comments look like this.
|
||||
Multi-line comments look like this. They work in C89 as well.
|
||||
*/
|
||||
|
||||
// Import headers with #include
|
||||
@@ -25,6 +27,17 @@ Multi-line comments look like this.
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// file names between <angle brackets> are headers from the C standard library.
|
||||
// They are searched for by the preprocessor in the system include paths
|
||||
// (usually /usr/lib on Unices, can be controlled with the -I<dir> option if you are using GCC or clang.)
|
||||
// For your own headers, use double quotes instead of angle brackets:
|
||||
#include "my_header.h"
|
||||
|
||||
// The C preprocessor introduces an almost fully-featured macro language. It's useful, but
|
||||
// it can be confusing (and what's even worse, it can be misused). Read the
|
||||
// Wikipedia article on the C preprocessor for further information:
|
||||
// http://en.wikipedia.org/wiki/C_preprocessor
|
||||
|
||||
// Declare function signatures in advance in a .h file, or at the top of
|
||||
// your .c file.
|
||||
void function_1();
|
||||
@@ -33,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.
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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
407
fr-fr/ruby-fr.html.markdown
Normal 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
|
||||
|
||||
```
|
@@ -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/)
|
||||
|
@@ -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
406
ko-kr/java-kr.html.markdown
Normal 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)
|
@@ -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
384
pt-br/ruby-pt.html.markdown
Normal 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
|
||||
|
||||
```
|
426
ru-ru/clojure-ru.html.markdown
Normal file
426
ru-ru/clojure-ru.html.markdown
Normal 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
658
ru-ru/php-ru.html.markdown
Normal 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).
|
486
ru-ru/python-ru.html.markdown
Normal file
486
ru-ru/python-ru.html.markdown
Normal 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)
|
||||
|
@@ -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.
|
||||
|
@@ -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
279
zh-cn/go-zh.html.markdown
Normal 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赋值0,p不再是空的了。
|
||||
s := make([]int, 20) // 给20个int变量分配一块内存
|
||||
s[3] = 7 // 赋值
|
||||
r := -2 // 声明另一个局部变量
|
||||
return &s[3], &r // & 取址
|
||||
}
|
||||
|
||||
func expensiveComputation() int {
|
||||
return 1e6
|
||||
}
|
||||
|
||||
func learnFlowControl() {
|
||||
// If需要花括号,括号就免了
|
||||
if true {
|
||||
fmt.Println("told ya")
|
||||
}
|
||||
// 用go fmt 命令可以帮你格式化代码,所以不用怕被人吐槽代码风格了,也不用容忍被人的代码风格。
|
||||
if false {
|
||||
// pout
|
||||
} else {
|
||||
// gloat
|
||||
}
|
||||
// 如果太多嵌套的if语句,推荐使用switch
|
||||
x := 1
|
||||
switch x {
|
||||
case 0:
|
||||
case 1:
|
||||
// 隐式调用break语句,匹配上一个即停止
|
||||
case 2:
|
||||
// 不会运行
|
||||
}
|
||||
// 和if一样,for也不用括号
|
||||
for x := 0; x < 3; x++ { // ++ 自增
|
||||
fmt.Println("iteration", x)
|
||||
}
|
||||
// x在这里还是1。为什么?
|
||||
|
||||
// for 是go里唯一的循环关键字,不过它有很多变种
|
||||
for { // 无限循环
|
||||
break // 骗你的
|
||||
continue // 不会运行的
|
||||
}
|
||||
// 和for一样,if中的:=先给y赋值,然后再和x作比较。
|
||||
if y := expensiveComputation(); y > x {
|
||||
x = y
|
||||
}
|
||||
// 闭包函数
|
||||
xBig := func() bool {
|
||||
return x > 100 // x是上面声明的变量引用
|
||||
}
|
||||
fmt.Println("xBig:", xBig()) // true (上面把y赋给x了)
|
||||
x /= 1e5 // x变成10
|
||||
fmt.Println("xBig:", xBig()) // 现在是false
|
||||
|
||||
// 当你需要goto的时候,你会爱死它的!
|
||||
goto love
|
||||
love:
|
||||
|
||||
learnInterfaces() // 好东西来了!
|
||||
}
|
||||
|
||||
// 定义Stringer为一个接口类型,有一个方法String
|
||||
type Stringer interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
// 定义pair为一个结构体,有x和y两个int型变量。
|
||||
type pair struct {
|
||||
x, y int
|
||||
}
|
||||
|
||||
// 定义pair类型的方法,实现Stringer接口。
|
||||
func (p pair) String() string { // p被叫做“接收器”
|
||||
// Sprintf是fmt包中的另一个公有函数。
|
||||
// 用 . 调用p中的元素。
|
||||
return fmt.Sprintf("(%d, %d)", p.x, p.y)
|
||||
}
|
||||
|
||||
func learnInterfaces() {
|
||||
// 花括号用来定义结构体变量,:=在这里将一个结构体变量赋值给p。
|
||||
p := pair{3, 4}
|
||||
fmt.Println(p.String()) // 调用pair类型p的String方法
|
||||
var i Stringer // 声明i为Stringer接口类型
|
||||
i = p // 有效!因为p实现了Stringer接口(类似java中的塑型)
|
||||
// 调用i的String方法,输出和上面一样
|
||||
fmt.Println(i.String())
|
||||
|
||||
// fmt包中的Println函数向对象要它们的string输出,实现了String方法就可以这样使用了。(类似java中的序列化)
|
||||
fmt.Println(p) // 输出和上面一样,自动调用String函数。
|
||||
fmt.Println(i) // 输出和上面一样。
|
||||
|
||||
learnErrorHandling()
|
||||
}
|
||||
|
||||
func learnErrorHandling() {
|
||||
// ", ok"用来判断有没有正常工作
|
||||
m := map[int]string{3: "three", 4: "four"}
|
||||
if x, ok := m[1]; !ok { // ok 为false,因为m中没有1
|
||||
fmt.Println("no one there")
|
||||
} else {
|
||||
fmt.Print(x) // 如果x在map中的话,x就是那个值喽。
|
||||
}
|
||||
// 错误可不只是ok,它还可以给出关于问题的更多细节。
|
||||
if _, err := strconv.Atoi("non-int"); err != nil { // _ discards value
|
||||
// 输出"strconv.ParseInt: parsing "non-int": invalid syntax"
|
||||
fmt.Println(err)
|
||||
}
|
||||
// 待会再说接口吧。同时,
|
||||
learnConcurrency()
|
||||
}
|
||||
|
||||
// c是channel类型,一个并发安全的通信对象。
|
||||
func inc(i int, c chan int) {
|
||||
c <- i + 1 // <-把右边的发送到左边的channel。
|
||||
}
|
||||
|
||||
// 我们将用inc函数来并发地增加一些数字。
|
||||
func learnConcurrency() {
|
||||
// 用make来声明一个slice,make会分配和初始化slice,map和channel。
|
||||
c := make(chan int)
|
||||
// 用go关键字开始三个并发的goroutine,如果机器支持的话,还可能是并行执行。三个都被发送到同一个channel。
|
||||
go inc(0, c) // go is a statement that starts a new goroutine.
|
||||
go inc(10, c)
|
||||
go inc(-805, c)
|
||||
// 从channel中独处结果并打印。
|
||||
// 打印出什么东西是不可预知的。
|
||||
fmt.Println(<-c, <-c, <-c) // channel在右边的时候,<-是接收操作。
|
||||
|
||||
cs := make(chan string) // 操作string的channel
|
||||
cc := make(chan chan string) // 操作channel的channel
|
||||
go func() { c <- 84 }() // 开始一个goroutine来发送一个新的数字
|
||||
go func() { cs <- "wordy" }() // 发送给cs
|
||||
// Select类似于switch,但是每个case包括一个channel操作。它随机选择一个准备好通讯的case。
|
||||
select {
|
||||
case i := <-c: // 从channel接收的值可以赋给其他变量
|
||||
fmt.Println("it's a", i)
|
||||
case <-cs: // 或者直接丢弃
|
||||
fmt.Println("it's a string")
|
||||
case <-cc: // 空的,还没作好通讯的准备
|
||||
fmt.Println("didn't happen.")
|
||||
}
|
||||
// 上面c或者cs的值被取到,其中一个goroutine结束,另外一个保持阻塞。
|
||||
|
||||
learnWebProgramming() // Go很适合web编程,我知道你也想学!
|
||||
}
|
||||
|
||||
// http包中的一个简单的函数就可以开启web服务器。
|
||||
func learnWebProgramming() {
|
||||
// ListenAndServe第一个参数指定了监听端口,第二个参数是一个接口,特定是http.Handler。
|
||||
err := http.ListenAndServe(":8080", pair{})
|
||||
fmt.Println(err) // 不要无视错误。
|
||||
}
|
||||
|
||||
// 使pair实现http.Handler接口的ServeHTTP方法。
|
||||
func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// 使用http.ResponseWriter返回数据
|
||||
w.Write([]byte("You learned Go in Y minutes!"))
|
||||
}
|
||||
```
|
||||
|
||||
## 更进一步
|
||||
|
||||
Go的根源在[Go官方网站](http://golang.org/)。
|
||||
在那里你可以学习入门教程,通过浏览器交互式地学习,而且可以读到很多东西。
|
||||
|
||||
强烈推荐阅读语言定义部分,很简单而且很简洁!(as language definitions go these days.)
|
||||
|
||||
学习Go还要阅读Go标准库的源代码,全部文档化了,可读性非常好,可以学到go,go style和go idioms。在文档中点击函数名,源代码就出来了!
|
Reference in New Issue
Block a user