mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2025-08-09 08:16:58 +02:00
Merge branch 'master' of github.com:greybird/learnxinyminutes-docs
This commit is contained in:
@@ -70,7 +70,7 @@ 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
|
||||
// value of the same size.
|
||||
// signed value of the same size.
|
||||
unsigned char ux_char;
|
||||
unsigned short ux_short;
|
||||
unsigned int ux_int;
|
||||
|
425
es-es/c-es.html.markdown
Normal file
425
es-es/c-es.html.markdown
Normal file
@@ -0,0 +1,425 @@
|
||||
---
|
||||
language: c
|
||||
filename: learnc.c
|
||||
contributors:
|
||||
- ["Adam Bard", "http://adambard.com/"]
|
||||
translators:
|
||||
- ["Francisco García", "http://flaskbreaker.tumblr.com/"]
|
||||
lang: es-es
|
||||
---
|
||||
|
||||
¡Ah!, C. Aun hoy en día sigue siendo el lenguaje por excelencia de la
|
||||
computación moderna de alto rendimiento.
|
||||
|
||||
C es el lenguaje de más bajo nivel que la mayoría de los programadores
|
||||
llegarán a usar, pero lo compensa de sobra con pura velocidad. Solo
|
||||
ten en cuenta el manejo manual de memoria y te llevará tan lejos como
|
||||
necesites.
|
||||
|
||||
```c
|
||||
// Los comentarios de una sola línea comienzan con //
|
||||
|
||||
/*
|
||||
Los comentarios multilínea tienen este aspecto.
|
||||
*/
|
||||
|
||||
// Importa cabeceras con #include
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// Declara por adelantado las armaduras de las funciones en un archivo .h,
|
||||
// o al principio de tu archivo .c .
|
||||
void function_1();
|
||||
void function_2();
|
||||
|
||||
// El punto de entrada de tu programa es una función llamada main con
|
||||
// retorno de tipo entero (integer).
|
||||
int main() {
|
||||
|
||||
// Muestra la salida usando printf, para el "formato print"
|
||||
// %d es un entero, \n es una nueva línea
|
||||
printf("%d\n", 0); // => Muestra 0
|
||||
// Todas las sentencias deben terminar con un punto y coma.
|
||||
|
||||
///////////////////////////////////////
|
||||
// Tipos
|
||||
///////////////////////////////////////
|
||||
|
||||
// Tienes que declarar una variable antes de usarla. La declaración de una
|
||||
// variable necesites que especifiques su tipo; el tipo de una variable
|
||||
// determina su tamaño en bytes.
|
||||
|
||||
// 'ints' (enteros) son normalmente de 4 bytes
|
||||
int x_int = 0;
|
||||
|
||||
// 'shorts' son normalmente de 2 bytes
|
||||
short x_short = 0;
|
||||
|
||||
// 'chars' son fijo de 1 byte
|
||||
char x_char = 0;
|
||||
char y_char = 'y'; // Los caracteres literales se entrecomillan con ''
|
||||
|
||||
// 'longs' son a menudo de 4 a 8 bytes; 'long longs' son fijo de por lo
|
||||
// menos 64 bits
|
||||
long x_long = 0;
|
||||
long long x_long_long = 0;
|
||||
|
||||
// 'floats' son normalmente números de coma flotante de 32 bits
|
||||
float x_float = 0.0;
|
||||
|
||||
// 'doubles' son normalmente números de coma flotante de 64 bits
|
||||
double x_double = 0.0;
|
||||
|
||||
// Todos los tipos enteros pueden ser 'unsigned'. Esto significa que no
|
||||
// pueden ser negativos, pero el valor máximo de una variable 'unsigned'
|
||||
// es mayor que el de una no 'unsigned' del mismo tamaño.
|
||||
unsigned char ux_char;
|
||||
unsigned short ux_short;
|
||||
unsigned int ux_int;
|
||||
unsigned long long ux_long_long;
|
||||
|
||||
// Todos menos 'char', que es siempre de 1 byte, varían el tamaño
|
||||
// dependiendo de tu máquina. sizeof(T) te dice el tamaño de una variable
|
||||
// de tipo T en bytes por lo que podemos expresar el tamaño de estos tipos
|
||||
// portatilmente.
|
||||
// Por ejemplo,
|
||||
printf("%lu\n", sizeof(int)); // => 4 (en máquinas con 'words' de 4 bytes)
|
||||
|
||||
// Los arrays deben ser inicializados con un tamaño concreto.
|
||||
char my_char_array[20]; // Este array ocupa 1 * 20 = 20 bytes
|
||||
int my_int_array[20]; // Este array ocupa 4 * 20 = 80 bytes
|
||||
// (suponiendo que tenemos 'words' de 4-byte)
|
||||
|
||||
|
||||
// Puedes inicializar un array a 0 así:
|
||||
char my_array[20] = {0};
|
||||
|
||||
// Indexar un array es como en otros lenguajes -o, más bien, otros
|
||||
// lenguajes son como C-
|
||||
my_array[0]; // => 0
|
||||
|
||||
// Los arrays varían; ¡son sólo memoria!
|
||||
my_array[1] = 2;
|
||||
printf("%d\n", my_array[1]); // => 2
|
||||
|
||||
// Las cadenas (strings) son sólo arrays de 'chars' (caracteres)
|
||||
// terminados en un byte NUL (0x00), representado en las cadenas como el
|
||||
// carácter especial '\0'.
|
||||
// (No tenemos porqué añadir el byte nulo en cadenas literales; el
|
||||
// compilador lo añade al final por nosotros.)
|
||||
char a_string[20] = "Esto es una cadena";
|
||||
printf("%s\n", a_string); // %s se sutituye por una cadena.
|
||||
|
||||
/*
|
||||
Te habrás dado cuenta de que a_string es solo de 18 caracteres.
|
||||
El 'char' #19 es el byte nulo.
|
||||
El 'char' #20 es de valor indefinido.
|
||||
*/
|
||||
|
||||
printf("%d\n", a_string[18]); // => 0
|
||||
|
||||
///////////////////////////////////////
|
||||
// Operadores
|
||||
///////////////////////////////////////
|
||||
|
||||
int i1 = 1, i2 = 2; // Forma corta de declaración múltiple
|
||||
float f1 = 1.0, f2 = 2.0;
|
||||
|
||||
// La aritmética es sencilla
|
||||
i1 + i2; // => 3
|
||||
i2 - i1; // => 1
|
||||
i2 * i1; // => 2
|
||||
i1 / i2; // => 0 (0.5, pero es truncado tras el 0)
|
||||
|
||||
f1 / f2; // => 0.5, más o menos épsilon
|
||||
// Módulo está también
|
||||
11 % 3; // => 2
|
||||
|
||||
// Los operadores de comparación te resultaran familiares, pero no hay
|
||||
// booleanos en C. Usamos enteros (ints) en su lugar. 0 es falso,
|
||||
// cualquier otra cosa es verdadero. (Los operadores de comparación
|
||||
// siempre devuelven 0 o 1)
|
||||
3 == 2; // => 0 (Falso)
|
||||
3 != 2; // => 1 (Verdadero)
|
||||
3 > 2; // => 1
|
||||
3 < 2; // => 0
|
||||
2 <= 2; // => 1
|
||||
2 >= 2; // => 1
|
||||
|
||||
// La lógica funiona en enteros
|
||||
!3; // => 0 (not lógico)
|
||||
!0; // => 1
|
||||
1 && 1; // => 1 (and lógico)
|
||||
0 && 1; // => 0
|
||||
0 || 1; // => 1 (or lógico)
|
||||
0 || 0; // => 0
|
||||
|
||||
// ¡Operadores de bits!
|
||||
~0x0F; // => 0xF0 (Negación)
|
||||
0x0F & 0xF0; // => 0x00 (AND)
|
||||
0x0F | 0xF0; // => 0xFF (OR)
|
||||
0x04 ^ 0x0F; // => 0x0B (XOR)
|
||||
0x01 << 1; // => 0x02 (desplazar hacia la izquierda (por 1))
|
||||
0x02 >> 1; // => 0x01 (desplazar hacia la derecha (por 1))
|
||||
|
||||
///////////////////////////////////////
|
||||
// Estructuras de Control
|
||||
///////////////////////////////////////
|
||||
|
||||
if (0) {
|
||||
printf("Yo nunca ocurro\n");
|
||||
} else if (0) {
|
||||
printf("Yo tampoco ocurro nunca\n");
|
||||
} else {
|
||||
printf("Yo me muestro\n");
|
||||
}
|
||||
|
||||
// Mientras el bucle exista
|
||||
int ii = 0;
|
||||
while (ii < 10) {
|
||||
printf("%d, ", ii++); // ii++ incrementa ii en uno, después de usar su valor.
|
||||
} // => muestra "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
|
||||
|
||||
printf("\n");
|
||||
|
||||
int kk = 0;
|
||||
do {
|
||||
printf("%d, ", kk);
|
||||
} while (++kk < 10); // ++kk incrementa kk en uno, antes de usar su valor.
|
||||
// => muestra "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
|
||||
|
||||
printf("\n");
|
||||
|
||||
// Bucles 'for' también
|
||||
int jj;
|
||||
for (jj=0; jj < 10; jj++) {
|
||||
printf("%d, ", jj);
|
||||
} // => muestra "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
|
||||
|
||||
printf("\n");
|
||||
|
||||
///////////////////////////////////////
|
||||
// Cambios de Tipo
|
||||
///////////////////////////////////////
|
||||
|
||||
// Cada valor en C tiene un tipo, pero tu puedes ingresar un valor en
|
||||
// otro tipo si quieres.
|
||||
|
||||
int x_hex = 0x01; // Puedes asignar hexadecimales a variables
|
||||
|
||||
// El cambio de tipos intentará mantener sus valores numéricos
|
||||
printf("%d\n", x_hex); // => Muestra 1
|
||||
printf("%d\n", (short) x_hex); // => Muestra 1
|
||||
printf("%d\n", (char) x_hex); // => Muestra 1
|
||||
|
||||
// Los tipos se desbordan sin aviso
|
||||
printf("%d\n", (char) 257); // => 1 (El valor máximo de un 'char' es 255)
|
||||
|
||||
// Los tipos enteros puden cambiarse a tipos de coma flotante, y viceversa
|
||||
printf("%f\n", (float)100); // %f se sustituye por un 'float'
|
||||
printf("%lf\n", (double)100); // %lf se sustituye por un 'double'
|
||||
printf("%d\n", (char)100.0);
|
||||
|
||||
///////////////////////////////////////
|
||||
// Punteros
|
||||
///////////////////////////////////////
|
||||
|
||||
// Un puntero es una variable declarada para almacenar una dirección de
|
||||
// memoria. Su declaración además nos dirá el tipo de dato al que apunta.
|
||||
// Puedes obtener la dirección de memoria de tus variables, y después
|
||||
// enlazarlas con ellos.
|
||||
|
||||
int x = 0;
|
||||
printf("%p\n", &x); // Usa & para obtener la dirección de una variable.
|
||||
// (%p se sustituye por un puntero)
|
||||
// => Muestra alguna dirección de memoria;
|
||||
|
||||
// Los tipos de puntero terminan con * en su declaración
|
||||
int* px; // px es un puntero a un 'int'
|
||||
px = &x; // Almacena la dirección de x en px
|
||||
printf("%p\n", px); // => Muestra alguna dirección de memoria
|
||||
|
||||
// Para obtener el valor de la dirección a la que apunta un puntero, pon
|
||||
// * delante para desreferenciarle.
|
||||
printf("%d\n", *px); // => Muestra 0, el valor de x y de la dirección a la
|
||||
// que apunta px
|
||||
|
||||
// También puedes cambiar el valor al que está apuntando el puntero.
|
||||
// Tenemos que meter la desreferencia entre paréntesis porque ++ tiene
|
||||
// prioridad frente a *.
|
||||
(*px)++; // Incrementa el valor al que apunta px en 1
|
||||
printf("%d\n", *px); // => Muestra 1
|
||||
printf("%d\n", x); // => Muestra 1
|
||||
|
||||
int x_array[20]; // Los arrays son una buena manera de distribuir bloques
|
||||
int xx; // continuos de memoria.
|
||||
for (xx=0; xx<20; xx++) {
|
||||
x_array[xx] = 20 - xx;
|
||||
} // Inicializa x_array a 20, 19, 18,... 2, 1
|
||||
|
||||
// Declara un puntero de tipo 'int' y lo inicializa para apuntar a x_array
|
||||
int* x_ptr = x_array;
|
||||
// x_ptr ahira apunta al primer elemento del 'array' (el entero 20).
|
||||
// Esto funciona porque las 'arrays' actualmente son solo punteros a su
|
||||
// primer elemento.
|
||||
|
||||
// Los 'arrays' son punteros a su primer elemento.
|
||||
printf("%d\n", *(x_ptr)); // => Muestra 20
|
||||
printf("%d\n", x_array[0]); // => Muestra 20
|
||||
|
||||
// Los punteros aumentan y disminuyen en función de su tipo.
|
||||
printf("%d\n", *(x_ptr + 1)); // => Muestra 19
|
||||
printf("%d\n", x_array[1]); // => Muestra 19
|
||||
|
||||
// Puedes también asigner dinamicamente bloques contiguos de memoria con
|
||||
// la función malloc de la librería estándard, que toma un entero como
|
||||
// argumento representando el número de bytes a asignar de la pila.
|
||||
int* my_ptr = (int*) malloc(sizeof(int) * 20);
|
||||
for (xx=0; xx<20; xx++) {
|
||||
*(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx funcionaría también aquí
|
||||
} // Inicializa la memoria a 20, 19, 18, 17... 2, 1 (como 'ints')
|
||||
|
||||
// Desreferenciando la memoria que no has asignado te dará resultados
|
||||
// impredecibles
|
||||
printf("%d\n", *(my_ptr + 21)); // => Prints who-knows-what?
|
||||
|
||||
// Cuando hallas 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);
|
||||
|
||||
// Las cadenas pueden ser 'arrays' de chars, pero normalmente se
|
||||
// representan con punteros 'char':
|
||||
char* my_str = "This is my very own string";
|
||||
|
||||
printf("%c\n", *my_str); // => 'T'
|
||||
|
||||
function_1();
|
||||
} // fin de la función main
|
||||
|
||||
///////////////////////////////////////
|
||||
// Funciones
|
||||
///////////////////////////////////////
|
||||
|
||||
// Sintexis de la declaración de funciones:
|
||||
// <tipo de retorno> <nombre>(<argumentos>)
|
||||
|
||||
int add_two_ints(int x1, int x2){
|
||||
return x1 + x2; // Usa 'return' para dar una salida
|
||||
}
|
||||
|
||||
/*
|
||||
Las funciones son de paso por valor, pero puedes hacer tus propias
|
||||
referencias con punteros de manera que las funciones puedan cambiar sus
|
||||
valores.
|
||||
|
||||
Ejemplo: invertidor de cadenas in-situ
|
||||
*/
|
||||
|
||||
// Una función 'void' no retorna valor
|
||||
void str_reverse(char* str_in){
|
||||
char tmp;
|
||||
int ii=0, len = strlen(str_in); // Strlen es parte de la librería
|
||||
for(ii=0; ii<len/2; ii++){ // estándard
|
||||
tmp = str_in[ii];
|
||||
str_in[ii] = str_in[len - ii - 1]; // ii-th último 'char'
|
||||
str_in[len - ii - 1] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
char c[] = "Esto es una prueba.";
|
||||
str_reverse(c);
|
||||
printf("%s\n", c); // => ".abeurp anu se otsE"
|
||||
*/
|
||||
|
||||
///////////////////////////////////////
|
||||
// Definición de tipos y estructuras
|
||||
///////////////////////////////////////
|
||||
|
||||
// Los 'Typedefs' pueden ser utilizados para crear alias de tipos.
|
||||
typedef int my_type;
|
||||
my_type my_type_var = 0;
|
||||
|
||||
// Las estructuras son sólo grupos de datos.
|
||||
struct rectangle {
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
|
||||
void function_1(){
|
||||
|
||||
struct rectangle my_rec;
|
||||
|
||||
// Utiliza los miembros de una estructura con .
|
||||
my_rec.width = 10;
|
||||
my_rec.height = 20;
|
||||
|
||||
// Puedes declarar punteros a estructuras
|
||||
struct rectangle* my_rec_ptr = &my_rec;
|
||||
|
||||
// Usa la desreferencia para modificar sus miembros...
|
||||
(*my_rec_ptr).width = 30;
|
||||
|
||||
// ... o usa la abreviatura ->
|
||||
my_rec_ptr->height = 10; // Lo mismo que (*my_rec_ptr).height = 10;
|
||||
}
|
||||
|
||||
// Puedes aplicar un 'typedef' a una estructura por conveniencía.
|
||||
typedef struct rectangle rect;
|
||||
|
||||
int area(rect r){
|
||||
return r.width * r.height;
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// Punteros a Funciones
|
||||
///////////////////////////////////////
|
||||
/*
|
||||
En tiempo de ejecución, las funciones se localizan en unas direcciones de
|
||||
memoria concretas. Los punteros a funciones son como cualquier otro
|
||||
puntero (almacenan una dirección de memoria), pero pueden ser usados para
|
||||
utilizar funciones directamente, o para pasar 'handlers' (o funciones
|
||||
'callback') por todos lados.
|
||||
Sin embargo, la sintaxis de definición parecera confusa al principio.
|
||||
|
||||
Ejemplo: usar str_reverse desde un puntero
|
||||
*/
|
||||
void str_reverse_through_pointer(char * str_in) {
|
||||
// Define un puntero a una función, llamado f.
|
||||
void (*f)(char *);
|
||||
// La armadura debe coincidir exactamente con al función objetivo.
|
||||
|
||||
// Assigna la dirección de la función (determinado en tiempo de ejecuión)
|
||||
f = &str_reverse;
|
||||
|
||||
// Llamando la función desde el puntero
|
||||
(*f)(str_in);
|
||||
|
||||
// Esta es una alternativa para llamarla pero con una sintaxis igual de válida.
|
||||
// f(str_in);
|
||||
}
|
||||
|
||||
/*
|
||||
Tanto tiempo como las armaduras de las funciones coincidan, podrás asignar
|
||||
cualquier función al mismo puntero.
|
||||
Los punteros a funciones son normalmente envueltos en 'typedef' para
|
||||
simplificar su legibilidad, como sigue:
|
||||
*/
|
||||
|
||||
typedef void (*my_fnp_type)(char *);
|
||||
|
||||
// Es usado para declarar la variable puntero actual:
|
||||
// ...
|
||||
// my_fnp_type f;
|
||||
|
||||
```
|
||||
|
||||
## Otras lecturas
|
||||
|
||||
Lo mejor que puedes en contrar es una copia de [K&R, aka "The C Programming Language"](https://en.wikipedia.org/wiki/The_C_Programming_Language)
|
||||
|
||||
Otro buen recurso es [Learn C the hard way](http://c.learncodethehardway.org/book/)
|
||||
|
||||
Aparte de eso, Google es tu amigo.
|
377
es-es/elisp-es.html.markdown
Normal file
377
es-es/elisp-es.html.markdown
Normal file
@@ -0,0 +1,377 @@
|
||||
---
|
||||
language: elisp
|
||||
contributors:
|
||||
- ["Bastien Guerry", "http://bzg.fr"]
|
||||
translators:
|
||||
- ["Guillermo Vayá", "http://willyfrog.es"]
|
||||
lang: es-es
|
||||
filename: learn-emacs-lisp.el
|
||||
---
|
||||
|
||||
```scheme
|
||||
;; Introduccion a Emacs Lisp en 15 minutos (v0.2d)
|
||||
;;
|
||||
;; Autor: Bastien / @bzg2 / http://bzg.fr
|
||||
;; Traducción: Guillermo Vayá
|
||||
;;
|
||||
;; Antes de nada, lee este texto de Peter Norvig:
|
||||
;; http://norvig.com/21-days.html
|
||||
;;
|
||||
;; Ahora instala GNU Emacs 24.3:
|
||||
;;
|
||||
;; Debian: apt-get install emacs
|
||||
;; (o sigue las instrucciones de tu distribución preferida)
|
||||
;; OSX: http://emacsformacosx.com/emacs-builds/Emacs-24.3-universal-10.6.8.dmg
|
||||
;; Windows: http://ftp.gnu.org/gnu/windows/emacs/emacs-24.3-bin-i386.zip
|
||||
;;
|
||||
;; Puedes encontrar información general sobre Emacs en:
|
||||
;; http://www.gnu.org/software/emacs/#Obtaining
|
||||
|
||||
;; Aviso importante:
|
||||
;;
|
||||
;; Seguir este tutorial no provocará daños en tu ordenador a menos que
|
||||
;; te enfades tanto que que acabes tirándolo al suelo. En tal caso
|
||||
;; declino cualquier responsabilidad. ¡A divertirse!
|
||||
|
||||
|
||||
;; "N. del. T.": Algunos términos comunes de la informática se han dejado
|
||||
;; sin traducir ya que es mucho más probable que el lector los conozca en
|
||||
;; su forma en inglés, siendo la versión en español de muy raro uso.
|
||||
;; Además "sexps" se ha decidido traducir por sexpresión.
|
||||
;; Por último, añadir que no se han traducido los ejemplos de código ya que no
|
||||
;; es necesario entender qué dice el string para comprender el funcionamiento
|
||||
;; y podría llevar a error.
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; Inicia Emacs.
|
||||
;;
|
||||
;; Pulsa la tecla `q' para pasar el mensaje de bienvenida.
|
||||
;;
|
||||
;; Mira a la línea gris en la parte inferior de la ventana:
|
||||
;;
|
||||
;; "*scratch*" es el nombre del espacio editable donde estás.
|
||||
;; A este espacio editable se le llama "buffer".
|
||||
;;
|
||||
;; Scratch es el buffer por defecto cuando abres Emacs.
|
||||
;; En Emacs nunca editas ficheros, sino que editas buffers que
|
||||
;; posteriormente pueden grabarse a un fichero.
|
||||
;; can save to a file.
|
||||
;;
|
||||
;; "Lisp interaction" indica el conjunto de ordenes disponibles.
|
||||
;;
|
||||
;; Emacs dispone de un set de comandos disponibles en cualquier buffer
|
||||
;; ("built-ins") y aparte varios conjuntos de ordenes disponibles
|
||||
;; según el modo específico que esté activo. En nuestro caso
|
||||
;; estamos usando `lisp-interaction-mode', el cual incluye las
|
||||
;; ordenes necesarias para evaluar y navegar código Elisp.
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; Un punto y coma comienza un comentario. Pueden ponerse en cualquier
|
||||
;; posicion de la linea.
|
||||
;;
|
||||
;; Los programas en Elisp se componen de expresiones simbólicas
|
||||
;; tambien llamadas "sexps":
|
||||
(+ 2 2)
|
||||
|
||||
;; Esta expresión simbólica se lee tal que "Suma 2 y 2"
|
||||
|
||||
;; Las sexpresiones se rodean por paréntesis, y pueden anidarse:
|
||||
(+ 2 (+ 1 1))
|
||||
|
||||
;; Una expresion simbólica está formada bien por átomos o bien por otras
|
||||
;; expresiones simbólicas. En el ejemplo de arriba, 1 y 2 son átomos,
|
||||
;; mientras que (+ 2 (+ 1 1)) y (+ 1 1) son expresiones simbólicas.
|
||||
|
||||
;; Gracias a `lisp-interaction-mode' puedes evaluar las sexpresiones.
|
||||
;; Coloca el cursor justo despues del paréntesis de cierre y
|
||||
;; mantén pulsada la tecla Control y la j (para abreviar usaremos "C-j").
|
||||
|
||||
(+ 3 (+ 1 2))
|
||||
;; ^ pon aquí el cursor
|
||||
;; `C-j' => 6
|
||||
|
||||
;; `C-j' añade el resultado de la evaluación al buffer.
|
||||
|
||||
;; `C-xC-e' muestra el mismo resultado pero en la linea inferior
|
||||
;; la cual se llama "minibuffer". Este será el metodo que usaremos
|
||||
;; normalmente para no llenar el buffer con texto inútil.
|
||||
|
||||
;; `setq' guarda un valor en una variable:
|
||||
(setq my-name "Bastien")
|
||||
;; `C-xC-e' => "Bastien" (aparece en el mini-buffer)
|
||||
|
||||
;; `insert' añade "Hello!" en el punto donde esté tu cursor:
|
||||
(insert "Hello!")
|
||||
;; `C-xC-e' => "Hello!"
|
||||
|
||||
;; Aunque hemos usado `insert' con solo un parámetro "Hello!", se
|
||||
;; pueden pasar más. Por ejemplo, en esta otra sexpresión usamos dos:
|
||||
|
||||
(insert "Hello" " world!")
|
||||
;; `C-xC-e' => "Hello world!"
|
||||
|
||||
;; Se pueden usar variables en lugar de strings:
|
||||
(insert "Hello, I am " my-name)
|
||||
;; `C-xC-e' => "Hello, I am Bastien"
|
||||
|
||||
;; Puedes combinar sexpresiones en funciones:
|
||||
(defun hello () (insert "Hello, I am " my-name))
|
||||
;; `C-xC-e' => hello
|
||||
|
||||
;; Evaluemos la funcion:
|
||||
(hello)
|
||||
;; `C-xC-e' => Hello, I am Bastien
|
||||
|
||||
;; Los parentesis vacios en la definicion de una funcion indican
|
||||
;; que no acepta parámetros. En cualquier caso, usar `my-name' siempre
|
||||
;; es aburrido, asi que vamos a hacer que la función accepte un parámetro
|
||||
;; (en este caso el parametro se llama "name"):
|
||||
(defun hello (name) (insert "Hello " name))
|
||||
;; `C-xC-e' => hello
|
||||
|
||||
;; Ahora vamos a llamar a la funcion con el string "you" como valor para
|
||||
;; el único parámetro que posee.
|
||||
(hello "you")
|
||||
;; `C-xC-e' => "Hello you"
|
||||
|
||||
;; ¡Genial!
|
||||
|
||||
;; Descansa un poco y respira.
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; Ahora cambiaremos al nuevo buffer, llamado "*test*", en una nueva ventana.
|
||||
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
;; `C-xC-e'
|
||||
;; => [La pantalla ahora tiene dos ventanas y el cursor está en el buffer *test*]
|
||||
|
||||
;; Mueve el ratón sobre la ventana superior y pulsa el boton izdo. para volver.
|
||||
;; Otra forma es usando `C-xo' (pulsa simultaneamente control y x y luego la o)
|
||||
;; para ir a la otra ventana.
|
||||
|
||||
;; Se pueden combinar varias sexpresiones mediante `progn':
|
||||
(progn
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(hello "you"))
|
||||
;; `C-xC-e'
|
||||
;; => [De las dos ventanas de la pantalla, el cursor está en la marcada como *test*]
|
||||
|
||||
;; A partir de ahora, si no te importa, dejaremos de decir que pulses `C-xC-e':
|
||||
;; tendrás que hacerlo para ejecutar cada sexpresión que siga.
|
||||
|
||||
;; También tendrás que volver al buffer *scratch* bien con el ratón o con `C-xo'.
|
||||
|
||||
;; En ocasiones será util limpiar el buffer:
|
||||
(progn
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
(hello "there"))
|
||||
|
||||
;; O volver a la ventana anterior:
|
||||
(progn
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
(hello "you")
|
||||
(other-window 1))
|
||||
|
||||
;; Puedes enlazar un valor a una variable local con `let':
|
||||
(let ((local-name "you"))
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
(hello local-name)
|
||||
(other-window 1))
|
||||
|
||||
;; En este caso, no hace falta añadir `progn' ya que `let' permite combinar
|
||||
;; varias sexpresiones.
|
||||
|
||||
;; Vamos a darle formato a un string:
|
||||
(format "Hello %s!\n" "visitor")
|
||||
|
||||
;; Cada %s indica la posicion donde irá un string, el cual será reemplazado
|
||||
;; por "visitor". "\n" es el caracter de nueva línea.
|
||||
|
||||
;; Mejoremos nuestra funcion usando `format':
|
||||
(defun hello (name)
|
||||
(insert (format "Hello %s!\n" name)))
|
||||
|
||||
(hello "you")
|
||||
|
||||
;; Creemos una nueva funcion que utililce `let':
|
||||
(defun greeting (name)
|
||||
(let ((your-name "Bastien"))
|
||||
(insert (format "Hello %s!\n\nI am %s."
|
||||
name ; the argument of the function
|
||||
your-name ; the let-bound variable "Bastien"
|
||||
))))
|
||||
|
||||
;; Y ahora la evaluamos:
|
||||
(greeting "you")
|
||||
|
||||
;; Algunas funciones son interactivas:
|
||||
(read-from-minibuffer "Enter your name: ")
|
||||
|
||||
;; Al evaluar esta función, ésta devuelve lo que hayas introducido.
|
||||
|
||||
;; Ahora hagamos nuestra función `greeting' preguntar por tu nombre:
|
||||
(defun greeting (from-name)
|
||||
(let ((your-name (read-from-minibuffer "Enter your name: ")))
|
||||
(insert (format "Hello!\n\nI am %s and you are %s."
|
||||
from-name ; the argument of the function
|
||||
your-name ; the let-bound var, entered at prompt
|
||||
))))
|
||||
|
||||
(greeting "Bastien")
|
||||
|
||||
;; Y ahora la completamos mostrando el resultado en la otra ventana:
|
||||
(defun greeting (from-name)
|
||||
(let ((your-name (read-from-minibuffer "Enter your name: ")))
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
(insert (format "Hello %s!\n\nI am %s." your-name from-name))
|
||||
(other-window 1)))
|
||||
|
||||
;; Probémosla:
|
||||
(greeting "Bastien")
|
||||
|
||||
;; Descansa un poco y respira.
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; Creemos una lista de nombres:
|
||||
(setq list-of-names '("Sarah" "Chloe" "Mathilde"))
|
||||
|
||||
;; Para coger el primer elemento de la lista usaremos `car':
|
||||
(car list-of-names)
|
||||
|
||||
;; Para coger todos menos el primer elemento de la lista
|
||||
;; usaremos `cdr':
|
||||
(cdr list-of-names)
|
||||
|
||||
;; Para añadir un elemento al comienzo de la lista utilizamos `push':
|
||||
(push "Stephanie" list-of-names)
|
||||
|
||||
;; OJO: `car' y `cdr' no modifican la lista, mientras que `push' sí.
|
||||
;; ¡Es una diferencia importante! Algunas funciones no tienen efectos
|
||||
;; colaterales (como `car') mientras que otras sí (como `push').
|
||||
;; "N. del T.": estos efectos colaterales se les llama `side-effects' en
|
||||
;; las distintas variantes de lisp.
|
||||
|
||||
;; Llamemos a `hello' con cada elemento de `list-of-names':
|
||||
(mapcar 'hello list-of-names)
|
||||
|
||||
;; Retocamos `greeting' para que salude a todos los que estén en `list-of-names':
|
||||
(defun greeting ()
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
(mapcar 'hello list-of-names)
|
||||
(other-window 1))
|
||||
|
||||
(greeting)
|
||||
|
||||
;; ¿Te acuerdas de la función `hello' definida un poco más arriba?
|
||||
;; Recibía un parámetro: `name'. Así que `mapcar' llama a `hello' con cada
|
||||
;; elemento de `list-of-names' como parámetro de `hello'.
|
||||
|
||||
;; Ahora ordenaremos un poco lo que tenemos en el buffer:
|
||||
|
||||
(defun replace-hello-by-bonjour ()
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(goto-char (point-min))
|
||||
(while (search-forward "Hello")
|
||||
(replace-match "Bonjour"))
|
||||
(other-window 1))
|
||||
|
||||
;; (goto-char (point-min)) mueve el cursor al principio del buffer.
|
||||
;; (search-forward "Hello") busca un string "Hello".
|
||||
;; (while x y) evalua la/s sexpresion/es y mientras que x devuelva
|
||||
;; alguna cosa.
|
||||
;; En el momento que x devuelva `nil' (es decir nada), sale del
|
||||
;; bucle `while'.
|
||||
|
||||
(replace-hello-by-bonjour)
|
||||
|
||||
;; Observamos que todas las veces que teníamos la palabra "Hello" en el buffer *test*
|
||||
;; han sido reemplazadas por "Bonjour".
|
||||
|
||||
;; Y además, hemos obtenido un error: "Search failed: Hello".
|
||||
;;
|
||||
;; Para evitar este error, hay que decirle a `search-forward' si debería dejar de
|
||||
;; buscar en el buffer en algún momento y si debería fallar sin quejarse cuando
|
||||
;; no encuentra nada.
|
||||
|
||||
;; (search-forward "Hello" nil t) justo hace eso:
|
||||
|
||||
;; El argumento `nil' significa que la busqueda no está ligada a ninguna posición.
|
||||
;; Y el argumento `t' le pide que no diga nada si no encuentra el string.
|
||||
|
||||
;; Usaremos esta sexpresión en la función siguiente, la cual ya
|
||||
;; no muestra ningún error:
|
||||
|
||||
(defun hello-to-bonjour ()
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
;; Say hello to names in `list-of-names'
|
||||
(mapcar 'hello list-of-names)
|
||||
(goto-char (point-min))
|
||||
;; Replace "Hello" by "Bonjour"
|
||||
(while (search-forward "Hello" nil t)
|
||||
(replace-match "Bonjour"))
|
||||
(other-window 1))
|
||||
|
||||
(hello-to-bonjour)
|
||||
|
||||
;; Añadamos algo de color a los nombres:
|
||||
|
||||
(defun boldify-names ()
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "Bonjour \\(.+\\)!" nil t)
|
||||
(add-text-properties (match-beginning 1)
|
||||
(match-end 1)
|
||||
(list 'face 'bold)))
|
||||
(other-window 1))
|
||||
|
||||
;; Esta función nos presenta `re-search-forward': en vez de
|
||||
;; buscar el string "Bonjour" exacto, se busca por un patrón
|
||||
;; usando una "expresión regular" (lo cual se muestra abreviado
|
||||
;; en el prefijo "re-" del inglés "Regular Expression").
|
||||
|
||||
;; La expresión regular a utilizar es "Bonjour \\(.+\\)!" y se traduce como:
|
||||
;; el string "Bonjour ", seguido de
|
||||
;; un grupo de | representado por \\( ... \\)
|
||||
;; cualquier caracter | representado por .
|
||||
;; al menos una vez | representado por +
|
||||
;; y el string "!".
|
||||
|
||||
;; ¿Preparado? ¡Probemoslo!
|
||||
|
||||
(boldify-names)
|
||||
|
||||
;; `add-text-properties' añade propiedades al texto, como una fuente.
|
||||
|
||||
;; ¡Hale! ¡Ya lo tenemos! ¡Feliz hacking!
|
||||
|
||||
;; Si quieres saber más sobre una función o una variable:
|
||||
;;
|
||||
;; C-h v la-variable RET
|
||||
;; C-h f la-funcion RET
|
||||
;;
|
||||
;; Si quieres leer el manual de Emacs Lisp desde dentro de Emacs:
|
||||
;;
|
||||
;; C-h i m elisp RET
|
||||
;;
|
||||
;; Para leer una introducción en linea de Emacs Lisp:
|
||||
;; https://www.gnu.org/software/emacs/manual/html_node/eintr/index.html
|
||||
|
||||
;; Me gustaría agradecer a las siguientes personas su feedback y sugerencias:
|
||||
;; - Wes Hardaker
|
||||
;; - notbob
|
||||
;; - Kevin Montuori
|
||||
;; - Arne Babenhauserheide
|
||||
;; - Alan Schmitt
|
||||
;; - LinXitoW
|
||||
;; - Aaron Meurer
|
||||
```
|
@@ -232,7 +232,7 @@ filled_dict.setdefault("five", 6) #filled_dict["five"] is still 5
|
||||
# Sets store ... well sets
|
||||
empty_set = set()
|
||||
# Initialize a set with a bunch of values
|
||||
some_set = set([1,2,2,3,4]) # filled_set is now set([1, 2, 3, 4])
|
||||
some_set = set([1,2,2,3,4]) # some_set is now set([1, 2, 3, 4])
|
||||
|
||||
# Since Python 2.7, {} can be used to declare a set
|
||||
filled_set = {1, 2, 2, 3, 4} # => {1 2 3 4}
|
||||
@@ -470,12 +470,19 @@ dir(math)
|
||||
|
||||
```
|
||||
|
||||
## Further Reading
|
||||
## Ready For More?
|
||||
|
||||
Still up for more? Try:
|
||||
### Free Online
|
||||
|
||||
* [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/)
|
||||
|
||||
### Dead Tree
|
||||
|
||||
* [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)
|
||||
|
||||
|
@@ -120,7 +120,7 @@ $ git help
|
||||
$ git help -a
|
||||
|
||||
# 在文档当中查找特定的命令
|
||||
$ git help <命令>
|
||||
# git help <命令>
|
||||
$ git help add
|
||||
$ git help commit
|
||||
$ git help init
|
||||
|
407
zh-cn/haskell-cn.html.markdown
Executable file
407
zh-cn/haskell-cn.html.markdown
Executable file
@@ -0,0 +1,407 @@
|
||||
---
|
||||
language: haskell
|
||||
filename: learn-haskell.hs
|
||||
contributors:
|
||||
- ["Adit Bhargava", "http://adit.io"]
|
||||
translators:
|
||||
- ["Peiyong Lin", ""]
|
||||
lang: zh-cn
|
||||
---
|
||||
|
||||
Haskell 被设计成一种实用的纯函数式编程语言。它因为 monads 及其类型系统而出名,但是我回归到它本身因为。Haskell 使得编程对于我而言是一种真正的快乐。
|
||||
|
||||
```haskell
|
||||
-- 单行注释以两个破折号开头
|
||||
{- 多行注释像这样
|
||||
被一个闭合的块包围
|
||||
-}
|
||||
|
||||
----------------------------------------------------
|
||||
-- 1. 简单的数据类型和操作符
|
||||
----------------------------------------------------
|
||||
|
||||
-- 你有数字
|
||||
3 -- 3
|
||||
-- 数学计算就像你所期待的那样
|
||||
1 + 1 -- 2
|
||||
8 - 1 -- 7
|
||||
10 * 2 -- 20
|
||||
35 / 5 -- 7.0
|
||||
|
||||
-- 默认除法不是整除
|
||||
35 / 4 -- 8.75
|
||||
|
||||
-- 整除
|
||||
35 `div` 4 -- 8
|
||||
|
||||
-- 布尔值也简单
|
||||
True
|
||||
False
|
||||
|
||||
-- 布尔操作
|
||||
not True -- False
|
||||
not False -- True
|
||||
1 == 1 -- True
|
||||
1 /= 1 -- False
|
||||
1 < 10 -- True
|
||||
|
||||
-- 在上述的例子中,`not` 是一个接受一个值的函数。
|
||||
-- Haskell 不需要括号来调用函数。。。所有的参数
|
||||
-- 都只是在函数名之后列出来。因此,通常的函数调用模式是:
|
||||
-- func arg1 arg2 arg3...
|
||||
-- 查看关于函数的章节以获得如何写你自己的函数的相关信息。
|
||||
|
||||
-- 字符串和字符
|
||||
"This is a string."
|
||||
'a' -- 字符
|
||||
'对于字符串你不能使用单引号。' -- 错误!
|
||||
|
||||
-- 连结字符串
|
||||
"Hello " ++ "world!" -- "Hello world!"
|
||||
|
||||
-- 一个字符串是一系列字符
|
||||
"This is a string" !! 0 -- 'T'
|
||||
|
||||
|
||||
----------------------------------------------------
|
||||
-- 列表和元组
|
||||
----------------------------------------------------
|
||||
|
||||
-- 一个列表中的每一个元素都必须是相同的类型
|
||||
-- 下面两个列表一样
|
||||
[1, 2, 3, 4, 5]
|
||||
[1..5]
|
||||
|
||||
-- 在 Haskell 你可以拥有含有无限元素的列表
|
||||
[1..] -- 一个含有所有自然数的列表
|
||||
|
||||
-- 因为 Haskell 有“懒惰计算”,所以无限元素的列表可以正常运作。这意味着
|
||||
-- Haskell 可以只在它需要的时候计算。所以你可以请求
|
||||
-- 列表中的第1000个元素,Haskell 会返回给你
|
||||
|
||||
[1..] !! 999 -- 1000
|
||||
|
||||
-- Haskell 计算了列表中 1 - 1000 个元素。。。但是
|
||||
-- 这个无限元素的列表中剩下的元素还不存在! Haskell 不会
|
||||
-- 真正地计算它们知道它需要。
|
||||
|
||||
<FS>- 连接两个列表
|
||||
[1..5] ++ [6..10]
|
||||
|
||||
-- 往列表头增加元素
|
||||
0:[1..5] -- [0, 1, 2, 3, 4, 5]
|
||||
|
||||
-- 列表中的下标
|
||||
[0..] !! 5 -- 5
|
||||
|
||||
-- 更多列表操作
|
||||
head [1..5] -- 1
|
||||
tail [1..5] -- [2, 3, 4, 5]
|
||||
init [1..5] -- [1, 2, 3, 4]
|
||||
last [1..5] -- 5
|
||||
|
||||
-- 列表推导
|
||||
[x*2 | x <- [1..5]] -- [2, 4, 6, 8, 10]
|
||||
|
||||
-- 附带条件
|
||||
[x*2 | x <-[1..5], x*2 > 4] -- [6, 8, 10]
|
||||
|
||||
-- 元组中的每一个元素可以是不同类型的,但是一个元组
|
||||
-- 的长度是固定的
|
||||
-- 一个元组
|
||||
("haskell", 1)
|
||||
|
||||
-- 获取元组中的元素
|
||||
fst ("haskell", 1) -- "haskell"
|
||||
snd ("haskell", 1) -- 1
|
||||
|
||||
----------------------------------------------------
|
||||
-- 3. 函数
|
||||
----------------------------------------------------
|
||||
-- 一个接受两个变量的简单函数
|
||||
add a b = a + b
|
||||
|
||||
-- 注意,如果你使用 ghci (Hakell 解释器)
|
||||
-- 你将需要使用 `let`,也就是
|
||||
-- let add a b = a + b
|
||||
|
||||
-- 使用函数
|
||||
add 1 2 -- 3
|
||||
|
||||
-- 你也可以把函数放置在两个参数之间
|
||||
-- 附带倒引号:
|
||||
1 `add` 2 -- 3
|
||||
|
||||
-- 你也可以定义不带字符的函数!这使得
|
||||
-- 你定义自己的操作符!这里有一个操作符
|
||||
-- 来做整除
|
||||
(//) a b = a `div` b
|
||||
35 // 4 -- 8
|
||||
|
||||
-- 守卫:一个简单的方法在函数里做分支
|
||||
fib x
|
||||
| x < 2 = x
|
||||
| otherwise = fib (x - 1) + fib (x - 2)
|
||||
|
||||
-- 模式匹配是类型的。这里有三种不同的 fib
|
||||
-- 定义。Haskell 将自动调用第一个
|
||||
-- 匹配值的模式的函数。
|
||||
fib 1 = 1
|
||||
fib 2 = 2
|
||||
fib x = fib (x - 1) + fib (x - 2)
|
||||
|
||||
-- 元组的模式匹配:
|
||||
foo (x, y) = (x + 1, y + 2)
|
||||
|
||||
-- 列表的模式匹配。这里 `x` 是列表中第一个元素,
|
||||
-- 并且 `xs` 是列表剩余的部分。我们可以写
|
||||
-- 自己的 map 函数:
|
||||
myMap func [] = []
|
||||
myMap func (x:xs) = func x:(myMap func xs)
|
||||
|
||||
-- 编写出来的匿名函数带有一个反斜杠,后面跟着
|
||||
-- 所有的参数。
|
||||
myMap (\x -> x + 2) [1..5] -- [3, 4, 5, 6, 7]
|
||||
|
||||
-- 使用 fold (在一些语言称为`inject`)随着一个匿名的
|
||||
-- 函数。foldl1 意味着左折叠(fold left), 并且使用列表中第一个值
|
||||
-- 作为累加器的初始化值。
|
||||
foldl1 (\acc x -> acc + x) [1..5] -- 15
|
||||
|
||||
----------------------------------------------------
|
||||
-- 4. 更多的函数
|
||||
----------------------------------------------------
|
||||
|
||||
-- 柯里化(currying):如果你不传递函数中所有的参数,
|
||||
-- 它就变成“柯里化的”。这意味着,它返回一个接受剩余参数的函数。
|
||||
|
||||
add a b = a + b
|
||||
foo = add 10 -- foo 现在是一个接受一个数并对其加 10 的函数
|
||||
foo 5 -- 15
|
||||
|
||||
-- 另外一种方式去做同样的事
|
||||
foo = (+10)
|
||||
foo 5 -- 15
|
||||
|
||||
-- 函数组合
|
||||
-- (.) 函数把其它函数链接到一起
|
||||
-- 举个列子,这里 foo 是一个接受一个值的函数。它对接受的值加 10,
|
||||
-- 并对结果乘以 5,之后返回最后的值。
|
||||
foo = (*5) . (+10)
|
||||
|
||||
-- (5 + 10) * 5 = 75
|
||||
foo 5 -- 75
|
||||
|
||||
-- 修复优先级
|
||||
-- Haskell 有另外一个函数称为 `$`。它改变优先级
|
||||
-- 使得其左侧的每一个操作先计算然后应用到
|
||||
-- 右侧的每一个操作。你可以使用 `.` 和 `$` 来除去很多
|
||||
-- 括号:
|
||||
|
||||
-- before
|
||||
(even (fib 7)) -- true
|
||||
|
||||
-- after
|
||||
even . fib $ 7 -- true
|
||||
|
||||
----------------------------------------------------
|
||||
-- 5. 类型签名
|
||||
----------------------------------------------------
|
||||
|
||||
-- Haskell 有一个非常强壮的类型系统,一切都有一个类型签名。
|
||||
|
||||
-- 一些基本的类型:
|
||||
5 :: Integer
|
||||
"hello" :: String
|
||||
True :: Bool
|
||||
|
||||
-- 函数也有类型。
|
||||
-- `not` 接受一个布尔型返回一个布尔型:
|
||||
-- not :: Bool -> Bool
|
||||
|
||||
-- 这是接受两个参数的函数:
|
||||
-- add :: Integer -> Integer -> Integer
|
||||
|
||||
-- 当你定义一个值,在其上写明它的类型是一个好实践:
|
||||
double :: Integer -> Integer
|
||||
double x = x * 2
|
||||
|
||||
----------------------------------------------------
|
||||
-- 6. 控制流和 If 语句
|
||||
----------------------------------------------------
|
||||
|
||||
-- if 语句
|
||||
haskell = if 1 == 1 then "awesome" else "awful" -- haskell = "awesome"
|
||||
|
||||
-- if 语句也可以有多行,缩进是很重要的
|
||||
haskell = if 1 == 1
|
||||
then "awesome"
|
||||
else "awful"
|
||||
|
||||
-- case 语句:这里是你可以怎样去解析命令行参数
|
||||
case args of
|
||||
"help" -> printHelp
|
||||
"start" -> startProgram
|
||||
_ -> putStrLn "bad args"
|
||||
|
||||
-- Haskell 没有循环因为它使用递归取代之。
|
||||
-- map 应用一个函数到一个数组中的每一个元素
|
||||
|
||||
map (*2) [1..5] -- [2, 4, 6, 8, 10]
|
||||
|
||||
-- 你可以使用 map 来编写 for 函数
|
||||
for array func = map func array
|
||||
|
||||
-- 然后使用它
|
||||
for [0..5] $ \i -> show i
|
||||
|
||||
-- 我们也可以像这样写:
|
||||
for [0..5] show
|
||||
|
||||
-- 你可以使用 foldl 或者 foldr 来分解列表
|
||||
-- foldl <fn> <initial value> <list>
|
||||
foldl (\x y -> 2*x + y) 4 [1,2,3] -- 43
|
||||
|
||||
-- 这和下面是一样的
|
||||
(2 * (2 * (2 * 4 + 1) + 2) + 3)
|
||||
|
||||
-- foldl 是左手边的,foldr 是右手边的-
|
||||
foldr (\x y -> 2*x + y) 4 [1,2,3] -- 16
|
||||
|
||||
-- 这和下面是一样的
|
||||
(2 * 3 + (2 * 2 + (2 * 1 + 4)))
|
||||
|
||||
----------------------------------------------------
|
||||
-- 7. 数据类型
|
||||
----------------------------------------------------
|
||||
|
||||
-- 这里展示在 Haskell 中你怎样编写自己的数据类型
|
||||
|
||||
data Color = Red | Blue | Green
|
||||
|
||||
-- 现在你可以在函数中使用它:
|
||||
|
||||
|
||||
say :: Color -> String
|
||||
say Red = "You are Red!"
|
||||
say Blue = "You are Blue!"
|
||||
say Green = "You are Green!"
|
||||
|
||||
-- 你的数据类型也可以有参数:
|
||||
|
||||
data Maybe a = Nothing | Just a
|
||||
|
||||
-- 类型 Maybe 的所有
|
||||
Just "hello" -- of type `Maybe String`
|
||||
Just 1 -- of type `Maybe Int`
|
||||
Nothing -- of type `Maybe a` for any `a`
|
||||
|
||||
----------------------------------------------------
|
||||
-- 8. Haskell IO
|
||||
----------------------------------------------------
|
||||
|
||||
-- 虽然在没有解释 monads 的情况下 IO不能被完全地解释,
|
||||
-- 着手解释到位并不难。
|
||||
|
||||
-- 当一个 Haskell 程序被执行,函数 `main` 就被调用。
|
||||
-- 它必须返回一个类型 `IO ()` 的值。举个列子:
|
||||
|
||||
main :: IO ()
|
||||
main = putStrLn $ "Hello, sky! " ++ (say Blue)
|
||||
-- putStrLn has type String -> IO ()
|
||||
|
||||
-- 如果你能实现你的程序依照函数从 String 到 String,那样编写 IO 是最简单的。
|
||||
-- 函数
|
||||
-- interact :: (String -> String) -> IO ()
|
||||
-- 输入一些文本,在其上运行一个函数,并打印出输出
|
||||
|
||||
countLines :: String -> String
|
||||
countLines = show . length . lines
|
||||
|
||||
main' = interact countLines
|
||||
|
||||
-- 你可以考虑一个 `IO()` 类型的值,当做一系列计算机所完成的动作的代表,
|
||||
-- 就像一个以命令式语言编写的计算机程序。我们可以使用 `do` 符号来把动作链接到一起。
|
||||
-- 举个列子:
|
||||
|
||||
sayHello :: IO ()
|
||||
sayHello = do
|
||||
putStrLn "What is your name?"
|
||||
name <- getLine -- this gets a line and gives it the name "input"
|
||||
putStrLn $ "Hello, " ++ name
|
||||
|
||||
-- 练习:编写只读取一行输入的 `interact`
|
||||
|
||||
-- 然而,`sayHello` 中的代码将不会被执行。唯一被执行的动作是 `main` 的值。
|
||||
-- 为了运行 `sayHello`,注释上面 `main` 的定义,并代替它:
|
||||
-- main = sayHello
|
||||
|
||||
-- 让我们来更好地理解刚才所使用的函数 `getLine` 是怎样工作的。它的类型是:
|
||||
-- getLine :: IO String
|
||||
-- 你可以考虑一个 `IO a` 类型的值,代表一个当被执行的时候
|
||||
-- 将产生一个 `a` 类型的值的计算机程序(除了它所做的任何事之外)。我们可以保存和重用这个值通过 `<-`。
|
||||
-- 我们也可以写自己的 `IO String` 类型的动作:
|
||||
|
||||
action :: IO String
|
||||
action = do
|
||||
putStrLn "This is a line. Duh"
|
||||
input1 <- getLine
|
||||
input2 <- getLine
|
||||
-- The type of the `do` statement is that of its last line.
|
||||
-- `return` is not a keyword, but merely a function
|
||||
return (input1 ++ "\n" ++ input2) -- return :: String -> IO String
|
||||
|
||||
-- 我们可以使用这个动作就像我们使用 `getLine`:
|
||||
|
||||
main'' = do
|
||||
putStrLn "I will echo two lines!"
|
||||
result <- action
|
||||
putStrLn result
|
||||
putStrLn "This was all, folks!"
|
||||
|
||||
-- `IO` 类型是一个 "monad" 的例子。Haskell 使用一个 monad 来做 IO的方式允许它是一门纯函数式语言。
|
||||
-- 任何与外界交互的函数(也就是 IO) 都在它的类型签名处做一个 `IO` 标志
|
||||
-- 着让我们推出 什么样的函数是“纯洁的”(不与外界交互,不修改状态) 和 什么样的函数不是 “纯洁的”
|
||||
|
||||
-- 这是一个强有力的特征,因为并发地运行纯函数是简单的;因此,Haskell 中并发是非常简单的。
|
||||
|
||||
|
||||
----------------------------------------------------
|
||||
-- 9. The Haskell REPL
|
||||
----------------------------------------------------
|
||||
|
||||
-- 键入 `ghci` 开始 repl。
|
||||
-- 现在你可以键入 Haskell 代码。
|
||||
-- 任何新值都需要通过 `let` 来创建:
|
||||
|
||||
let foo = 5
|
||||
|
||||
-- 你可以查看任何值的类型,通过命令 `:t`:
|
||||
|
||||
>:t foo
|
||||
foo :: Integer
|
||||
|
||||
-- 你也可以运行任何 `IO ()`类型的动作
|
||||
|
||||
> sayHello
|
||||
What is your name?
|
||||
Friend!
|
||||
Hello, Friend!
|
||||
|
||||
```
|
||||
|
||||
还有很多关于 Haskell,包括类型类和 monads。这些是使得编码 Haskell 是如此有趣的主意。我用一个最后的 Haskell 例子来结束:一个 Haskell 的快排实现:
|
||||
|
||||
```haskell
|
||||
qsort [] = []
|
||||
qsort (p:xs) = qsort lesser ++ [p] ++ qsort greater
|
||||
where lesser = filter (< p) xs
|
||||
greater = filter (>= p) xs
|
||||
```
|
||||
|
||||
安装 Haskell 是简单的。你可以从[这里](http://www.haskell.org/platform/)获得它。
|
||||
|
||||
你可以从优秀的
|
||||
[Learn you a Haskell](http://learnyouahaskell.com/) 或者
|
||||
[Real World Haskell](http://book.realworldhaskell.org/)
|
||||
找到优雅不少的入门介绍。
|
475
zh-cn/python-cn.html.markdown
Executable file
475
zh-cn/python-cn.html.markdown
Executable file
@@ -0,0 +1,475 @@
|
||||
---
|
||||
language: python
|
||||
contributors:
|
||||
- ["Louie Dinh", "http://ldinh.ca"]
|
||||
translators:
|
||||
- ["Chenbo Li", "http://binarythink.net"]
|
||||
filename: learnpython.py
|
||||
lang: zh-cn
|
||||
---
|
||||
|
||||
Python 由 Guido Van Rossum 在90年代初创建。 它现在是最流行的语言之一
|
||||
我喜爱python是因为它有极为清晰的语法,甚至可以说,它就是可以执行的伪代码
|
||||
|
||||
很欢迎来自您的反馈,你可以在[@louiedinh](http://twitter.com/louiedinh) 和 louiedinh [at] [google's email service] 这里找到我
|
||||
|
||||
注意: 这篇文章针对的版本是Python 2.7,但大多也可使用于其他Python 2的版本
|
||||
如果是Python 3,请在网络上寻找其他教程
|
||||
|
||||
```python
|
||||
# 单行注释
|
||||
""" 多行字符串可以用
|
||||
三个引号包裹,不过这也可以被当做
|
||||
多行注释
|
||||
"""
|
||||
|
||||
####################################################
|
||||
## 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
|
||||
|
||||
# 字符串通过"或'括起来
|
||||
"This is a string."
|
||||
'This is also a string.'
|
||||
|
||||
# 字符串通过加号拼接
|
||||
"Hello " + "world!" #=> "Hello world!"
|
||||
|
||||
# 字符串可以被视为字符的列表
|
||||
"This is a string"[0] #=> 'T'
|
||||
|
||||
# % 可以用来格式化字符串
|
||||
"%s can be %s" % ("strings", "interpolated")
|
||||
|
||||
# 也可以用format方法来格式化字符串
|
||||
# 推荐使用这个方法
|
||||
"{0} can be {1}".format("strings", "formatted")
|
||||
# 也可以用变量名代替数字
|
||||
"{name} wants to eat {food}".format(name="Bob", food="lasagna")
|
||||
|
||||
# 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 "I'm Python. Nice to meet you!"
|
||||
|
||||
|
||||
# 给变量赋值前不需要事先生命
|
||||
some_var = 5 # 规范用小写字母和下划线来做为变量名
|
||||
some_var #=> 5
|
||||
|
||||
# 访问之前为赋值的变量会抛出异常
|
||||
# 查看控制流程一节来了解异常处理
|
||||
some_other_var # 抛出命名异常
|
||||
|
||||
# if语句可以作为表达式来使用
|
||||
"yahoo!" if 3 > 2 else 2 #=> "yahoo!"
|
||||
|
||||
# 列表用来保存序列
|
||||
li = []
|
||||
# 可以直接初始化列表
|
||||
other_li = [4, 5, 6]
|
||||
|
||||
# 在列表末尾添加元素
|
||||
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]
|
||||
# 移除列表末尾元素
|
||||
li.pop() #=> 3 and li is now [1, 2, 4]
|
||||
# 放回来
|
||||
li.append(3) # li is now [1, 2, 4, 3] again.
|
||||
|
||||
# 像其他语言访问数组一样访问列表
|
||||
li[0] #=> 1
|
||||
# 访问最后一个元素
|
||||
li[-1] #=> 3
|
||||
|
||||
# 越界会抛出异常
|
||||
li[4] # 抛出越界异常
|
||||
|
||||
# 切片语法需要用到列表的索引访问
|
||||
# 可以看做数学之中左闭右开区间
|
||||
li[1:3] #=> [2, 4]
|
||||
# 省略开头的元素
|
||||
li[2:] #=> [4, 3]
|
||||
# 省略末尾的元素
|
||||
li[:3] #=> [1, 2, 4]
|
||||
|
||||
# 删除特定元素
|
||||
del li[2] # li 现在是 [1, 2, 3]
|
||||
|
||||
# 合并列表
|
||||
li + other_li #=> [1, 2, 3, 4, 5, 6] - 不改变这两个列表
|
||||
|
||||
# 通过拼接合并列表
|
||||
li.extend(other_li) # li 是 [1, 2, 3, 4, 5, 6]
|
||||
|
||||
# 用in来返回元素是否在列表中
|
||||
1 in li #=> True
|
||||
|
||||
# 返回列表长度
|
||||
len(li) #=> 6
|
||||
|
||||
|
||||
# 元组类似于列表,但是他是不可改变的
|
||||
tup = (1, 2, 3)
|
||||
tup[0] #=> 1
|
||||
tup[0] = 3 # 类型错误
|
||||
|
||||
# 对于大多数的列表操作,也适用于元组
|
||||
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,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]
|
||||
# 和键的顺序相同
|
||||
|
||||
# 判断一个键是否存在
|
||||
"one" in filled_dict #=> True
|
||||
1 in filled_dict #=> False
|
||||
|
||||
# 查询一个不存在的键会抛出键异常
|
||||
filled_dict["four"] # 键异常
|
||||
|
||||
# 用get方法来避免键异常
|
||||
filled_dict.get("one") #=> 1
|
||||
filled_dict.get("four") #=> None
|
||||
# get方法支持在不存在的时候返回一个默认值
|
||||
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]) # filled_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 is smaller than 10"
|
||||
if some_var > 10:
|
||||
print "some_var is totally bigger than 10."
|
||||
elif some_var < 10: # 这个 elif 语句是不必须的
|
||||
print "some_var is smaller than 10."
|
||||
else: # 也不是必须的
|
||||
print "some_var is indeed 10."
|
||||
|
||||
|
||||
"""
|
||||
用for循环遍历列表
|
||||
输出:
|
||||
dog is a mammal
|
||||
cat is a mammal
|
||||
mouse is a mammal
|
||||
"""
|
||||
for animal in ["dog", "cat", "mouse"]:
|
||||
# 你可以用 % 来格式化字符串
|
||||
print "%s is a mammal" % animal
|
||||
|
||||
"""
|
||||
`range(number)` 返回从0到给定数字的列表
|
||||
输出:
|
||||
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 # Shorthand for x = x + 1
|
||||
|
||||
# 用 try/except块来处理异常
|
||||
|
||||
# Python 2.6 及以上适用:
|
||||
try:
|
||||
# 用raise来抛出异常
|
||||
raise IndexError("This is an index error")
|
||||
except IndexError as e:
|
||||
pass # Pass就是什么都不做,不过通常这里会做一些恢复工作
|
||||
|
||||
|
||||
####################################################
|
||||
## 4. 函数
|
||||
####################################################
|
||||
|
||||
# 用def来新建函数
|
||||
def add(x, y):
|
||||
print "x is %s and y is %s" % (x, y)
|
||||
return x + y # Return values with a return statement
|
||||
|
||||
# 调用带参数的函数
|
||||
add(5, 6) #=> 输出 "x is 5 and y is 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) prints:
|
||||
(1, 2)
|
||||
{"a": 3, "b": 4}
|
||||
"""
|
||||
|
||||
# 当调用函数的时候,我们也可以和之前所做的相反,把元组和字典展开为参数
|
||||
args = (1, 2, 3, 4)
|
||||
kwargs = {"a": 3, "b": 4}
|
||||
all_the_args(*args) # equivalent to foo(1, 2, 3, 4)
|
||||
all_the_args(**kwargs) # equivalent to foo(a=3, b=4)
|
||||
all_the_args(*args, **kwargs) # equivalent to 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):
|
||||
# 将参数赋给对象成员属性
|
||||
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="Ian")
|
||||
print i.say("hi") # 输出 "Ian: hi"
|
||||
|
||||
j = Human("Joel")
|
||||
print j.say("hello") # 输出 "Joel: hello"
|
||||
|
||||
# 访问类的方法
|
||||
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/)
|
329
zh-cn/ruby-cn.html.markdown
Normal file
329
zh-cn/ruby-cn.html.markdown
Normal file
@@ -0,0 +1,329 @@
|
||||
---
|
||||
language: ruby
|
||||
filename: learnruby.rb
|
||||
contributors:
|
||||
- ["David Underwood", "http://theflyingdeveloper.com"]
|
||||
- ["Joel Walden", "http://joelwalden.net"]
|
||||
- ["Luke Holder", "http://twitter.com/lukeholder"]
|
||||
translators:
|
||||
- ["Lin Xiangyu", "https://github.com/oa414"]
|
||||
---
|
||||
|
||||
```ruby
|
||||
# 这是单行注释
|
||||
|
||||
=begin
|
||||
这是多行注释
|
||||
没人用这个
|
||||
你也不该用
|
||||
=end
|
||||
|
||||
# 首先,也是最重要的,所有东西都是对象
|
||||
|
||||
# 数字是对象
|
||||
|
||||
3.class #=> Fixnum
|
||||
|
||||
3.to_s #=> "3"
|
||||
|
||||
|
||||
# 一些基本的算术符号
|
||||
1 + 1 #=> 2
|
||||
8 - 1 #=> 7
|
||||
10 * 2 #=> 20
|
||||
35 / 5 #=> 7
|
||||
|
||||
# 算术符号只是语法糖而已
|
||||
# 实际上是调用对象的方法
|
||||
1.+(3) #=> 4
|
||||
10.* 5 #=> 50
|
||||
|
||||
# 特殊的只也是对象
|
||||
nil # 空
|
||||
true # 真
|
||||
false # 假
|
||||
|
||||
nil.class #=> NilClass
|
||||
true.class #=> TrueClass
|
||||
false.class #=> FalseClass
|
||||
|
||||
# 相等运算符
|
||||
1 == 1 #=> true
|
||||
2 == 1 #=> false
|
||||
|
||||
# 不等运算符
|
||||
1 != 1 #=> false
|
||||
2 != 1 #=> true
|
||||
!true #=> false
|
||||
!false #=> true
|
||||
|
||||
# 除了false自己,nil是唯一的值为false的对象
|
||||
|
||||
!nil #=> true
|
||||
!false #=> true
|
||||
!0 #=> false
|
||||
|
||||
# 更多比较
|
||||
1 < 10 #=> true
|
||||
1 > 10 #=> false
|
||||
2 <= 2 #=> true
|
||||
2 >= 2 #=> true
|
||||
|
||||
# 字符串是对象
|
||||
|
||||
'I am a string'.class #=> String
|
||||
"I am a string too".class #=> String
|
||||
|
||||
placeholder = "use string interpolation"
|
||||
"I can #{placeholder} when using double quoted strings"
|
||||
#=> "I can use string interpolation when using double quoted strings"
|
||||
|
||||
|
||||
# 输出值
|
||||
puts "I'm printing!"
|
||||
|
||||
# 变量
|
||||
x = 25 #=> 25
|
||||
x #=> 25
|
||||
|
||||
# 注意赋值语句返回了赋的值
|
||||
# 这意味着你可以用多重赋值语句
|
||||
|
||||
x = y = 10 #=> 10
|
||||
x #=> 10
|
||||
y #=> 10
|
||||
|
||||
# 按照惯例,用snake_case 作为变量名
|
||||
snake_case = true
|
||||
|
||||
# 使用具有描述性的运算符
|
||||
path_to_project_root = '/good/name/'
|
||||
path = '/bad/name/'
|
||||
|
||||
# 符号(Symbols,也是对象)
|
||||
# 符号是不可变的,内部用整数类型表示的可重用的值。通常用它代替字符串来有效地表达有意义的值
|
||||
|
||||
|
||||
:pending.class #=> Symbol
|
||||
|
||||
status = :pending
|
||||
|
||||
status == :pending #=> true
|
||||
|
||||
status == 'pending' #=> false
|
||||
|
||||
status == :approved #=> false
|
||||
|
||||
# 数组
|
||||
|
||||
# 这是一个数组
|
||||
[1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]
|
||||
|
||||
# 数组可以包含不同类型的元素
|
||||
|
||||
array = [1, "hello", false] #=> => [1, "hello", false]
|
||||
|
||||
# 数组可以被索引
|
||||
# 从前面开始
|
||||
array[0] #=> 1
|
||||
array[12] #=> nil
|
||||
|
||||
# 像运算符一样,[var]形式的访问
|
||||
# 也就是一个语法糖
|
||||
# 实际上是调用对象的[] 方法
|
||||
array.[] 0 #=> 1
|
||||
array.[] 12 #=> nil
|
||||
|
||||
# 从尾部开始
|
||||
array[-1] #=> 5
|
||||
|
||||
# 同时指定开始的位置和结束的位置
|
||||
array[2, 4] #=> [3, 4, 5]
|
||||
|
||||
# 或者指定一个范围
|
||||
array[1..3] #=> [2, 3, 4]
|
||||
|
||||
# 像这样往数组增加一个元素
|
||||
array << 6 #=> [1, 2, 3, 4, 5, 6]
|
||||
|
||||
# 哈希表是Ruby的键值对的基本数据结构
|
||||
# 哈希表由大括号定义
|
||||
hash = {'color' => 'green', 'number' => 5}
|
||||
|
||||
hash.keys #=> ['color', 'number']
|
||||
|
||||
# 哈希表可以通过键快速地查询
|
||||
hash['color'] #=> 'green'
|
||||
hash['number'] #=> 5
|
||||
|
||||
# 查询一个不存在地键将会返回nil
|
||||
hash['nothing here'] #=> nil
|
||||
|
||||
# 用 #each 方法来枚举哈希表:
|
||||
hash.each do |k, v|
|
||||
puts "#{k} is #{v}"
|
||||
end
|
||||
|
||||
# 从Ruby 1.9开始, 用符号作为键的时候有特别的记号表示:
|
||||
|
||||
new_hash = { defcon: 3, action: true}
|
||||
|
||||
new_hash.keys #=> [:defcon, :action]
|
||||
|
||||
# 小贴士:数组和哈希表都是可枚举的
|
||||
# 它们可以共享一些有用的方法,比如each, map, count, 和more
|
||||
|
||||
# 控制流
|
||||
|
||||
if true
|
||||
"if statement"
|
||||
elsif false
|
||||
"else if, optional"
|
||||
else
|
||||
"else, also optional"
|
||||
end
|
||||
|
||||
for counter in 1..5
|
||||
puts "iteration #{counter}"
|
||||
end
|
||||
#=> iteration 1
|
||||
#=> iteration 2
|
||||
#=> iteration 3
|
||||
#=> iteration 4
|
||||
#=> iteration 5
|
||||
|
||||
# 然而
|
||||
# 没人用for循环
|
||||
# 用`each`来代替,就像这样
|
||||
|
||||
(1..5).each do |counter|
|
||||
puts "iteration #{counter}"
|
||||
end
|
||||
#=> iteration 1
|
||||
#=> iteration 2
|
||||
#=> iteration 3
|
||||
#=> iteration 4
|
||||
#=> iteration 5
|
||||
|
||||
counter = 1
|
||||
while counter <= 5 do
|
||||
puts "iteration #{counter}"
|
||||
counter += 1
|
||||
end
|
||||
#=> iteration 1
|
||||
#=> iteration 2
|
||||
#=> iteration 3
|
||||
#=> iteration 4
|
||||
#=> iteration 5
|
||||
|
||||
grade = 'B'
|
||||
|
||||
case grade
|
||||
when 'A'
|
||||
puts "Way to go kiddo"
|
||||
when 'B'
|
||||
puts "Better luck next time"
|
||||
when 'C'
|
||||
puts "You can do better"
|
||||
when 'D'
|
||||
puts "Scraping through"
|
||||
when 'F'
|
||||
puts "You failed!"
|
||||
else
|
||||
puts "Alternative grading system, eh?"
|
||||
end
|
||||
|
||||
# 函数
|
||||
|
||||
def double(x)
|
||||
x * 2
|
||||
end
|
||||
|
||||
# 函数 (以及所有的方法块) 隐式地返回了最后语句的值
|
||||
double(2) #=> 4
|
||||
|
||||
# 当不存在歧义的时候括号是可有可无的
|
||||
double 3 #=> 6
|
||||
|
||||
double double 3 #=> 12
|
||||
|
||||
def sum(x,y)
|
||||
x + y
|
||||
end
|
||||
|
||||
# 方法的参数通过逗号分隔
|
||||
sum 3, 4 #=> 7
|
||||
|
||||
sum sum(3,4), 5 #=> 12
|
||||
|
||||
# yield
|
||||
# 所有的方法都有一个隐式的块参数
|
||||
# 可以用yield参数调用
|
||||
|
||||
def surround
|
||||
puts "{"
|
||||
yield
|
||||
puts "}"
|
||||
end
|
||||
|
||||
surround { puts 'hello world' }
|
||||
|
||||
# {
|
||||
# hello world
|
||||
# }
|
||||
|
||||
|
||||
# 用class关键字定义一个类
|
||||
class Human
|
||||
|
||||
# 一个类变量,它被这个类地所有实例变量共享
|
||||
@@species = "H. sapiens"
|
||||
|
||||
# 构造函数
|
||||
def initialize(name, age=0)
|
||||
# 将参数name的值赋给实例变量@name
|
||||
@name = name
|
||||
# 如果没有给出age, 那么会采用参数列表中地默认地值
|
||||
@age = age
|
||||
end
|
||||
|
||||
# 基本的 setter 方法
|
||||
def name=(name)
|
||||
@name = name
|
||||
end
|
||||
|
||||
# 基本地 getter 方法
|
||||
def name
|
||||
@name
|
||||
end
|
||||
|
||||
# 一个类方法以self.开头
|
||||
# 它可以被类调用,但不能被类的实例调用
|
||||
def self.say(msg)
|
||||
puts "#{msg}"
|
||||
end
|
||||
|
||||
def species
|
||||
@@species
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
# 类的例子
|
||||
jim = Human.new("Jim Halpert")
|
||||
|
||||
dwight = Human.new("Dwight K. Schrute")
|
||||
|
||||
# 让我们来调用一些方法
|
||||
jim.species #=> "H. sapiens"
|
||||
jim.name #=> "Jim Halpert"
|
||||
jim.name = "Jim Halpert II" #=> "Jim Halpert II"
|
||||
jim.name #=> "Jim Halpert II"
|
||||
dwight.species #=> "H. sapiens"
|
||||
dwight.name #=> "Dwight K. Schrute"
|
||||
|
||||
# 调用对象的方法
|
||||
Human.say("Hi") #=> "Hi"
|
||||
|
||||
```
|
Reference in New Issue
Block a user