diff options
| -rw-r--r-- | clojure-macros.html.markdown | 152 | ||||
| -rw-r--r-- | javascript.html.markdown | 14 | ||||
| -rw-r--r-- | julia.html.markdown | 81 | ||||
| -rw-r--r-- | ko-kr/go-kr.html.markdown | 314 | ||||
| -rw-r--r-- | php.html.markdown | 2 | ||||
| -rw-r--r-- | zh-cn/php-cn.html.markdown | 6 | 
6 files changed, 556 insertions, 13 deletions
| diff --git a/clojure-macros.html.markdown b/clojure-macros.html.markdown new file mode 100644 index 00000000..8e671936 --- /dev/null +++ b/clojure-macros.html.markdown @@ -0,0 +1,152 @@ +--- +language: "clojure macros" +filename: learnclojuremacros.clj +contributors: +    - ["Adam Bard", "http://adambard.com/"] +--- + +As with all Lisps, Clojure's inherent [homoiconicity](https://en.wikipedia.org/wiki/Homoiconic) +gives you access to the full extent of the language to write code-generation routines +called "macros". Macros provide a powerful way to tailor the language to your needs. + +Be careful though. It's considered bad form to write a macro when a function will do. +Use a macro only when you need control over when or if the arguments to a form will +be evaluated. + +You'll want to be familiar with Clojure. Make sure you understand everything in +[Clojure in Y Minutes](/docs/clojure/). + +```clojure +;; Define a macro using defmacro. Your macro should output a list that can +;; be evaluated as clojure code. +;; +;; This macro is the same as if you wrote (reverse "Hello World") +(defmacro my-first-macro [] +  (list reverse "Hello World")) + +;; Inspect the result of a macro using macroexpand or macroexpand-1. +;; +;; Note that the call must be quoted. +(macroexpand '(my-first-macro)) +;; -> (#<core$reverse clojure.core$reverse@xxxxxxxx> "Hello World") + +;; You can eval the result of macroexpand directly: +(eval (macroexpand '(my-first-macro))) +; -> (\d \l \o \r \W \space \o \l \l \e \H) + +;; But you should use this more succinct, function-like syntax: +(my-first-macro)  ; -> (\d \l \o \r \W \space \o \l \l \e \H) + +;; You can make things easier on yourself by using the more succinct quote syntax +;; to create lists in your macros: +(defmacro my-first-quoted-macro [] +  '(reverse "Hello World")) + +(macroexpand '(my-first-quoted-macro)) +;; -> (reverse "Hello World") +;; Notice that reverse is no longer function object, but a symbol. + +;; Macros can take arguments. +(defmacro inc2 [arg] +  (list + 2 arg)) + +(inc2 2) ; -> 4 + +;; But, if you try to do this with a quoted list, you'll get an error, because +;; the argument will be quoted too. To get around this, clojure provides a +;; way of quoting macros: `. Inside `, you can use ~ to get at the outer scope +(defmacro inc2-quoted [arg] +  `(+ 2 ~arg)) + +(inc2-quoted 2) + +;; You can use the usual destructuring args. Expand list variables using ~@ +(defmacro unless [arg & body] +  `(if (not ~arg) +     (do ~@body))) ; Remember the do! + +(macroexpand '(unless true (reverse "Hello World"))) +;; -> +;; (if (clojure.core/not true) (do (reverse "Hello World"))) + +;; (unless) evaluates and returns its body if the first argument is false. +;; Otherwise, it returns nil + +(unless true "Hello") ; -> nil +(unless false "Hello") ; -> "Hello" + +;; Used without care, macros can do great evil by clobbering your vars +(defmacro define-x [] +  '(do +     (def x 2) +     (list x))) + +(def x 4) +(define-x) ; -> (2) +(list x) ; -> (2) + +;; To avoid this, use gensym to get a unique identifier +(gensym 'x) ; -> x1281 (or some such thing) + +(defmacro define-x-safely [] +  (let [sym (gensym 'x)] +    `(do +       (def ~sym 2) +       (list ~sym)))) + +(def x 4) +(define-x-safely) ; -> (2) +(list x) ; -> (4) + +;; You can use # within ` to produce a gensym for each symbol automatically +(defmacro define-x-hygenically [] +  `(do +     (def x# 2) +     (list x#))) + +(def x 4) +(define-x-hygenically) ; -> (2) +(list x) ; -> (4) + +;; It's typical to use helper functions with macros. Let's create a few to +;; help us support a (dumb) inline arithmatic syntax +(declare inline-2-helper) +(defn clean-arg [arg] +  (if (seq? arg) +    (inline-2-helper arg) +    arg)) + +(defn apply-arg +  "Given args [x (+ y)], return (+ x y)" +  [val [op arg]] +  (list op val (clean-arg arg))) + +(defn inline-2-helper +  [[arg1 & ops-and-args]] +  (let [ops (partition 2 ops-and-args)] +    (reduce apply-arg (clean-arg arg1) ops))) + +;; We can test it immediately, without creating a macro +(inline-2-helper '(a + (b - 2) - (c * 5))) ; -> (- (+ a (- b 2)) (* c 5)) + +; However, we'll need to make it a macro if we want it to be run at compile time +(defmacro inline-2 [form] +  (inline-2-helper form))) + +(macroexpand '(inline-2 (1 + (3 / 2) - (1 / 2) + 1))) +; -> (+ (- (+ 1 (/ 3 2)) (/ 1 2)) 1) + +(inline-2 (1 + (3 / 2) - (1 / 2) + 1)) +; -> 3 (actually, 3N, since the number got cast to a rational fraction with /) +``` + +### Further Reading + +Writing Macros from [Clojure for the Brave and True](http://www.braveclojure.com/)   +[http://www.braveclojure.com/writing-macros/](http://www.braveclojure.com/writing-macros/) + +Official docs   +[http://clojure.org/macros](http://clojure.org/macros) + +When to use macros?   +[http://dunsmor.com/lisp/onlisp/onlisp_12.html](http://dunsmor.com/lisp/onlisp/onlisp_12.html) diff --git a/javascript.html.markdown b/javascript.html.markdown index 7fb7ba55..85c5d817 100644 --- a/javascript.html.markdown +++ b/javascript.html.markdown @@ -5,7 +5,7 @@ contributors:  filename: javascript.js  --- -Javascript was created by Netscape's Brendan Eich in 1995. It was originally +JavaScript was created by Netscape's Brendan Eich in 1995. It was originally  intended as a simpler scripting language for websites, complimenting the use of  Java for more complex web applications, but its tight integration with Web pages  and built-in support in browsers has caused it to become far more common than @@ -37,7 +37,7 @@ doStuff()  ///////////////////////////////////  // 1. Numbers, Strings and Operators -// Javascript has one number type (which is a 64-bit IEEE 754 double). +// JavaScript has one number type (which is a 64-bit IEEE 754 double).  // As with Lua, don't freak out about the lack of ints: doubles have a 52-bit  // mantissa, which is enough to store integers up to about 9✕10¹⁵ precisely.  3; // = 3 @@ -116,7 +116,7 @@ undefined; // used to indicate a value is not currently present (although  ///////////////////////////////////  // 2. Variables, Arrays and Objects -// Variables are declared with the var keyword. Javascript is dynamically typed, +// 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; @@ -175,14 +175,14 @@ myObj.myFourthKey; // = undefined  var count = 1;  if (count == 3){      // evaluated if count is 3 -} else if (count == 4) { +} else if (count == 4){      // evaluated if count is 4  } else {      // evaluated if it's not either 3 or 4  }  // As does while. -while (true) { +while (true){      // An infinite loop!  } @@ -327,7 +327,7 @@ var anotherFunc = function(s){  }  anotherFunc.call(myObj, " And Hello Moon!"); // = "Hello World! And Hello Moon!" -// The 'apply' function is nearly identical, but takes an array for an argument list.  +// The 'apply' function is nearly identical, but takes an array for an argument list.  anotherFunc.apply(myObj, [" And Hello Sun!"]); // = "Hello World! And Hello Sun!" @@ -477,7 +477,7 @@ more about how to use JavaScript in web pages, start by learning about the  [Document Object  Model](https://developer.mozilla.org/en-US/docs/Using_the_W3C_DOM_Level_1_Core) -[Javascript Garden](http://bonsaiden.github.io/JavaScript-Garden/) is an in-depth +[JavaScript Garden](http://bonsaiden.github.io/JavaScript-Garden/) is an in-depth  guide of all the counter-intuitive parts of the language.  In addition to direct contributors to this article, some content is adapted diff --git a/julia.html.markdown b/julia.html.markdown index 4b946d46..3bc660cf 100644 --- a/julia.html.markdown +++ b/julia.html.markdown @@ -427,7 +427,7 @@ end  keyword_args(name2="ness") #=> ["name2"=>"ness","k1"=>4]  keyword_args(k1="mine") #=> ["k1"=>"mine","name2"=>"hello"] -keyword_args() #=> ["name2"=>"hello","k2"=>4] +keyword_args() #=> ["name2"=>"hello","k1"=>4]  # You can combine all kinds of arguments in the same function  function all_the_args(normal_arg, optional_positional_arg=2; keyword_arg="foo") @@ -560,7 +560,7 @@ type Panther <: Cat # Panther is also a subtype of Cat    Panther() = new("green")    # Panthers will only have this constructor, and no default constructor.  end -# Using inner constructors, like Panter does, gives you control +# Using inner constructors, like Panther does, gives you control  # over how values of the type can be created.  # When possible, you should use outer constructors rather than inner ones. @@ -657,6 +657,83 @@ fight(Lion("RAR"),Lion("brown","rarrr")) #=> prints The victorious cat says rarr  fight(l::Lion,l2::Lion) = println("The lions come to a tie")  fight(Lion("RAR"),Lion("brown","rarrr")) #=> prints The lions come to a tie + +# Under the hood +# You can take a look at the llvm  and the assembly code generated. + +square_area(l) = l * l      # square_area (generic function with 1 method) + +square_area(5) #25 + +# What happens when we feed square_area an integer? +code_native(square_area, (Int32,))   +	#	    .section    __TEXT,__text,regular,pure_instructions +	#	Filename: none +	#	Source line: 1              # Prologue +	#	    push    RBP +	#	    mov RBP, RSP +	#	Source line: 1 +	#	    movsxd  RAX, EDI        # Fetch l from memory? +	#	    imul    RAX, RAX        # Square l and store the result in RAX +	#	    pop RBP                 # Restore old base pointer +	#	    ret                     # Result will still be in RAX + +code_native(square_area, (Float32,)) +	#	    .section    __TEXT,__text,regular,pure_instructions +	#	Filename: none +	#	Source line: 1 +	#	    push    RBP +	#	    mov RBP, RSP +	#	Source line: 1 +	#	    vmulss  XMM0, XMM0, XMM0  # Scalar single precision multiply (AVX) +	#	    pop RBP +	#	    ret + +code_native(square_area, (Float64,)) +	#	    .section    __TEXT,__text,regular,pure_instructions +	#	Filename: none +	#	Source line: 1 +	#	    push    RBP +	#	    mov RBP, RSP +	#	Source line: 1 +	#	    vmulsd  XMM0, XMM0, XMM0 # Scalar double precision multiply (AVX) +	#	    pop RBP +	#	    ret +	#	 +# Note that julia will use floating point instructions if any of the +# arguements are floats. +# Let's calculate the area of a circle  +circle_area(r) = pi * r * r     # circle_area (generic function with 1 method) +circle_area(5)                  # 78.53981633974483 + +code_native(circle_area, (Int32,)) +	#	    .section    __TEXT,__text,regular,pure_instructions +	#	Filename: none +	#	Source line: 1 +	#	    push    RBP +	#	    mov RBP, RSP +	#	Source line: 1 +	#	    vcvtsi2sd   XMM0, XMM0, EDI          # Load integer (r) from memory +	#	    movabs  RAX, 4593140240              # Load pi +	#	    vmulsd  XMM1, XMM0, QWORD PTR [RAX]  # pi * r +	#	    vmulsd  XMM0, XMM0, XMM1             # (pi * r) * r +	#	    pop RBP +	#	    ret +	# + +code_native(circle_area, (Float64,)) +	#	    .section    __TEXT,__text,regular,pure_instructions +	#	Filename: none +	#	Source line: 1 +	#	    push    RBP +	#	    mov RBP, RSP +	#	    movabs  RAX, 4593140496 +	#	Source line: 1 +	#	    vmulsd  XMM1, XMM0, QWORD PTR [RAX] +	#	    vmulsd  XMM0, XMM1, XMM0 +	#	    pop RBP +	#	    ret +	#	  ```  ## Further Reading diff --git a/ko-kr/go-kr.html.markdown b/ko-kr/go-kr.html.markdown new file mode 100644 index 00000000..7404572c --- /dev/null +++ b/ko-kr/go-kr.html.markdown @@ -0,0 +1,314 @@ +--- +name: Go +category: language +language: Go +filename: learngo.go +contributors: +    - ["Sonia Keys", "https://github.com/soniakeys"] +translators: +    - ["Jongmin Kim", "http://github.com/atomaths"] +lang: ko-kr +--- + +Go는 어떤 일을 잘 끝낼 수 있도록 하기위해 만들어졌다. Go가 잘 알려진 최신의 +트렌드는 아니지만, 실세계의 문제들을 해결하기 위해서는 가장 +새롭고 빠른 방법이다. + +Go는 정적 타이핑(static typing)의 명령형 언어들(imperative languages)이 +갖고 있는 특징과 유사한 개념들을 가지고 있다. Go는 컴파일과 실행속도가 +빠르며, 오늘날의 멀티코어 CPU를 위해 이해하기 쉬운 동시성(concurrency) +기능이 추가되었다. 그리고 큰 스케일의 프로그래밍에도 도움이 되는 +기능들을 가지고 있다. + +또한 Go에는 훌륭한 표준 라이브러리와 열정적인 커뮤니티가 있다. + +```go +// 한 줄 주석 +/* 여러 줄 +   주석 */ + +// 모든 Go 소스 파일은 package로 시작한다. +// 패키지 이름 중 main은 라이브러리가 아닌 실행파일을 선언하는 특별한 이름이다. +package main + +// import는 이 Go 소스 파일 내에서 참조하는 라이브러리 패키지들을 선언한다. +import ( +    "fmt"      // Go 표준 라이브러리에 있는 패키지 +    "net/http" // 표준 라이브러리에는 웹 서버 패키지도 있다! (클라이언트도 있음) +    "strconv"  // 문자열 변환 패키지 +) + +// 함수 선언. main은 실행 프로그램에서 시작점이 되는 특별한 함수다. +// 중괄호를 사용한다. +func main() { +    // Println은 표준 출력으로 개행을 출력한다. +    // fmt 패키지를 통해 이용할 수 있다. +    fmt.Println("Hello world!") + +    // 다른 함수를 호출한다. +    beyondHello() +} + +// 함수에 파라미터가 없더라도 빈 괄호는 있어야 한다. +func beyondHello() { +    var x int // 변수 선언. 변수는 사용하기 전에 선언해야 한다. +    x = 3     // 변수에 값 할당. +    // 짧은 선언(short declaration)으로 := 를 사용하는데, +    // 이렇게 값을 할당하면 값의 타입에 따라 변수의 타입이 결정된다. +    y := 4 +    sum, prod := learnMultiple(x, y)        // 함수는 두 개 이상의 리턴 값을 줄 수 있다. +    fmt.Println("sum:", sum, "prod:", prod) // 간단한 출력 +    learnTypes()                            // 잠시 후에 좀더 자세히! +} + +// 함수는 파라미터들을 가질 수 있고, 복수개의 값을 리턴할 수 있다. +func learnMultiple(x, y int) (sum, prod int) { +    return x + y, x * y // 두 개의 값을 리턴. +} + +// 내장 타입과 리터럴 +func learnTypes() { +    // 짧은 선언은 유용하다. +    s := "Learn Go!" // string 타입 + +    s2 := `역따옴표 안의 string 리터럴은 +개행을 포함할 수 있다.` // 같은 string 타입 + +    // non-ASCII 리터럴. Go 소스는 UTF-8로 작성해야 한다. +    g := 'Σ' // 유니코드 코드 포인트를 담고 있고, uint32 타입의 가칭(alias)인 rune 타입 + +    f := 3.14195 // float64, an IEEE-754 64-bit 부동소수 타입 +    c := 3 + 4i  // complex128, 내부적으로는 두 개의 float64 타입으로 표현됨 + +    // 초기값과 함께 사용하는 var 키워드. +    var u uint = 7 // unsigned, 하지만 int에 따른 구현의존적인 크기 +    var pi float32 = 22. / 7 + +    // 짧은 선언으로 변환(conversion)하는 문법. +    // Go에서는 type casting 이라고 하지않고 type conversion 이라고 함. +    n := byte('\n') // byte는 uint8의 가칭(alias) + +    // 배열은 컴파일 시에 크기가 정해진다. +    var a4 [4]int           // 모두 0으로 초기화되는 int 타입 4개짜리 배열 +    a3 := [...]int{3, 1, 5} // 3, 1, 5로 초기화되는 int 타입 3개짜리 배열 + +    // 슬라이스(slice)라고 하는 타입은 배열에 대한 가변 크기를 가진다. +    // 배열, 슬라이스 각자 장점이 있지만, 슬라이스가 더 많이 사용된다. +    s3 := []int{4, 5, 9}    // 위의 a3와 비교해보면 생략부호(...)가 없다. +    s4 := make([]int, 4)    // 모두 0으로 초기화되는 int 4개에 대한 슬라이스를 할당. +    var d2 [][]float64      // 여기에서는 선언만 있고 할당은 없다. +    bs := []byte("a slice") // string 타입을 byte 슬라이스 타입으로 형변환(type conversion) + +    p, q := learnMemory() // int에 대한 포인터 타입인 p와 q를 선언 +    fmt.Println(*p, *q)   // C에서처럼 *는 포인터를 따라가 값을 참조한다. 여기서는 두 개의 int를 출력. + +    // 맵(map)은 다른 언어의 해시(hash)나 딕셔너리(dictionary)처럼 가변의 연관배열 타입. +    m := map[string]int{"three": 3, "four": 4} +    m["one"] = 1 + +    // 선언만 하고 사용하지 않는 변수가 있다면 Go에서는 컴파일 시 에러가 난다. +    // 언더바를 이용해서 변수를 사용한 것처럼 하고 그 값은 무시해버릴 수 있다. +    _, _, _, _, _, _, _, _, _ = s2, g, f, u, pi, n, a3, s4, bs +    // 물론 출력을 하면 변수로 취급한다. +    fmt.Println(s, c, a4, s3, d2, m) + +    learnFlowControl() // 잠시 후에 다시 나옴 +} + +// Go는 가비지 컬렉션 기능을 JVM 같은 곳이 아닌 실행파일 런타임에 포함하고 있다. +// 그리고 포인터는 있지만, 포인터 연산(*p++ 같은)은 없다. +// 그래서 nil 포인터 접근같은 것 때문에 실수를 할 수는 있지만 +// 포인터 연산으로 인한 실수는 없게 된다. +func learnMemory() (p, q *int) { +    // 지명된 리턴 값(named return value)인 p와 q는 int에 대한 포인터 타입이다. +    p = new(int) // 내장함수인 new는 메모리를 할당해준다. +    // 메모리 할당된 int는 0으로 초기화 되고, p는 이제 nil이 아니다. +    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 소스의 코드 포맷팅은 "go fmt" 커맨드라인 명령으로 소스코드의 포맷을 맞춘다. +    if false { +        // pout +    } else { +        // gloat +    } +    // if-else 체인 형태보다 switch 사용이 권장된다. +    x := 1 +    switch x { +    case 0: +    case 1: +        // case 안에서는 break가 없어도 자동으로 다음 case로 내려가지 않는다. +        // 자동으로 내려가게 하려면 fallthrough 키워드를 사용한다. +    case 2: +        // x는 1이므로 여기는 실행되지 않음. +    } +    // if 에서처럼 for 에서도 양쪽에 소괄호를 쓰지 않는다. +    for x := 0; x < 3; x++ { // ++ 은 실행을 제어하는 하나의 구문(statement)이다. +        fmt.Println("iteration", x) +    } +    // 여기서 x는 1이다. 위 for에서 x는 for 안의 블록 범위에 있기 때문. + +    // For is the only loop statement in Go, but it has alternate forms. +    // for 는 Go에서 유일한 루프 구문이지만 다양한 형태로 조건을 주거나 while  +    // 처럼 쓸 수도 있다. +    for { // 무한루프 +        break    // 여기서 곧바로 break를 한 건 단지 +        continue // break, continue를 루프 안에서 쓸 수 있다는 것을 보여주기 위함. +    } +    // for 에서처럼 if 에서 := 를 사용하는것은 y에 먼저 값을 대입하고, +    // 그리고 y > x를 검사한다는 의미. +    if y := expensiveComputation(); y > x { +        x = y +    } +    // 함수 리터럴은 클로저다. +    xBig := func() bool { +        return x > 100 // 위 switch 문 바로 위에 있는 x를 참조한다. +    } +    fmt.Println("xBig:", xBig()) // true (x에 1e6를 대입했었다.) +    x /= 1e5 // x는 10이 된다. +    fmt.Println("xBig:", xBig()) // 이제 xBig()의 결과는 false가 된다. + +    // `goto`가 필요하다면, 좋아하게 될지도... +    goto love +love: + +    learnInterfaces() // 곧이어서 좋은 기능에 대한 설명이 나올 거다. +} + +// String 이라는 메서드 하나를 가진 Stringer 라는 인터페이스 타입을 정의하자. +type Stringer interface { +    String() string +} + +// x와 y라는 이름의 int 타입 필드를 가진 pair라는 struct를 정의하자. +type pair struct { +    x, y int +} + +// pair 타입에 메서드 String을 정의하자. +// 이제 pair는 Stringer 인터페이스를 구현(implement)한 것이 되었다. +func (p pair) String() string { // 여기서 p는 리시버(receiver)라고 부른다. +    // Sprintf는 fmt 패키지 안에 있는 외부로 공개된(exported) 함수다. +    // 점(.)으로 p의 필드들을 참조할 수 있다. +    return fmt.Sprintf("(%d, %d)", p.x, p.y) +} + +func learnInterfaces() { +    // 중괄호 문법은 "구조체 리터럴(struct literal)"인데, 초기화된 구조체로 +    // 취급하게 해준다. := 문법으로 p를 이 구조체로 선언하고 초기화한다. +    p := pair{3, 4} +    fmt.Println(p.String()) // 타입 pair인 p의 String 메서드를 호출. +    var i Stringer          // Stringer 인터페이스 타입 i를 선언. +    i = p                   // pair는 Stringer를 구현했기 때문에 이 대입은 유효하다. +    // 타입 Stringer인 i의 String 메서드 호출. 결과는 위와 같다. +    fmt.Println(i.String()) + +    // fmt 패키지의 함수들을 통해 어떤 객체를 출력해보려고 할 때, +    // fmt 패키지 내에서는 그 객체가 가진 String 메서드를 호출하도록 되어 있다. +    fmt.Println(p) // 결과는 위와 같다. Println은 String 메서드를 호출한다. +    fmt.Println(i) // 결과는 위와 같다. + +    learnErrorHandling() +} + +func learnErrorHandling() { +    // ", ok" (comma okay)표현은 무언가가 맞는 것인지 아닌지 확인하는데 사용된다. +    m := map[int]string{3: "three", 4: "four"} +    if x, ok := m[1]; !ok { // 이 map 안에 키가 1인 것은 없으므로 ok는 false가 된다. +        fmt.Println("no one there") +    } else { +        fmt.Print(x) // 만일 1이 map에 있었다면 x는 키 1의 값이 들어가게 된다. +    } + +    // Go에서는 함수가 복수 개의 리턴 값을 줄 수 있다는 점을 활용해 함수의 두 번째 리턴 +    // 값으로 error를 리턴해주고 그 error가 nil 인지 아닌지 확인하는 관례가 있다. +    // 이때 이 error 값은 단지 위에서처럼 함수의 결과가 성공했는지 실패했는지를 확인하는 +    // 것뿐만 아니라 실패 시 어떤 문제가 있었는지 확인할 수 있는 수단도 된다. +    if _, err := strconv.Atoi("non-int"); err != nil { // _ 는 값을 안 쓰고 버린다는 의미. +        // "strconv.ParseInt: parsing "non-int": invalid syntax" 이런 에러가 출력된다. +        fmt.Println(err) +    } +    // 인터페이스에 대해 잠시 후에 다시 잠깐 볼 것이다. +    learnConcurrency() +} + +// c는 goroutine 간의 통신을 위한 채널(channel)이다. +func inc(i int, c chan int) { +    c <- i + 1 // 채널이 <- 이 연산자 왼쪽에 온다면 그 채널로 데이터를 보낸다는 의미다. +} + +// 우리는 어떤 숫자들을 동시에 증가시키기 위해 inc 함수를 사용할 것이다. +func learnConcurrency() { +    // make는 slice, map, channel 타입들에 대해 메모리를 할당하고 초기화를 한다. +    // Go에는 메모리 할당 방법으로 new와 make가 있다. +    c := make(chan int) +    // 3개의 동시에 실행되는 goroutine를 시작한다. 만약 실행하고 있는 머신이 +    // 멀티코어 CPU를 가지고 있고 올바르게 설정되어(GOMAXPROCS) 있다면 +    // 숫자가 정말로 병렬적으로 증가하게 될 것이다. +    go inc(0, c) // go는 새로운 goroutine을 시작하는 구문이다. +    go inc(10, c) +    go inc(-805, c) +    // 채널로부터 3개의 결과를 읽어 출력한다. +    // 결과가 어떤 순서로 오는지는 알 수 없다. +    fmt.Println(<-c, <-c, <-c) // 채널이 <- 연산자 오른쪽에 있는 건, 채널로부터 데이터를 받는 연산이다. + +    cs := make(chan string)       // string을 다루는 또 다른 채널 +    cc := make(chan chan string)  // string 채널의 채널 +    go func() { c <- 84 }()       // c 채널로 값을 보내는 goroutine 시작. +    go func() { cs <- "wordy" }() // cs 채널로 값을 보내느 goroutine 시작. +    // select 구문은 switch 문과 비슷하지만, case에서 채널 연산에 관한 일을 한다. +    // select의 case들은 채널통신을 할 준비가 된 case 하나가 무작위로 선택되어  +    // 그 부분이 실행된다. +    select { +    case i := <-c: // 채널로부터 받아진 값은 변수에 대입할 수 있다. +        fmt.Printf("it's a %T", i) +    case <-cs: // 또는 받은 값을 그냥 버릴 수도 있다. +        fmt.Println("it's a string") +    case <-cc: // 통신할 준비가 되어 있지 않은 비어있는 채널. +        fmt.Println("didn't happen.") +    } +    // 여기서는 c나 cs 채널로부터 값 하나를 받을 수 있다. 위에서 실행한 두 개의 +    // goroutine 중 하나가 완료되면 다른 하나는 블락된 상태로 있게 된다. + +    learnWebProgramming() // Go에서는 웹 서버쪽 개발도 쉽게 할 수 있다. +} + +// http 패키지의 함수 하나로 웹 서버를 실행시킨다. +func learnWebProgramming() { +    // ListenAndServe의 첫 번째 파라미터는 listen 하기 위한 TCP 주소고, +    // 두 번째 파라미터는 http.Handler 인터페이스다. +    err := http.ListenAndServe(":8080", pair{}) +    fmt.Println(err) // don't ignore errors +} + +// http.Handler의 하나 뿐인 메서드, ServeHTTP를 pair에서 구현한다. +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/)를 참고하자. +여기에는 따라해볼 튜토리얼, 웹 기반의 인터랙티브 실행환경과 많은 읽을거리들이 있다. + +Go 언어 자체에 대한 스펙도 읽어보기를 적극 추천한다. 읽기 쉽게 되어있고 +그리 길지는 않다. + +Go 소스코드에 대해 좀더 알아보고 싶다면 [Go 표준 라이브러리](http://golang.org/src/pkg/)를 +분석해보기 바란다. 이해하기 쉽게 문서화되어 있고, Go 스타일 그리고 Go에서의 +관례 배우기에 가장 좋은 방법일 것이다. 또는 [문서](http://golang.org/pkg/) 안에서 +함수 이름 하나를 클릭해보면 소스코드를 브라우저에서 살펴볼 수도 있다. diff --git a/php.html.markdown b/php.html.markdown index c3317d59..e1bb86a0 100644 --- a/php.html.markdown +++ b/php.html.markdown @@ -212,7 +212,7 @@ assert($c >= $d);  // The following will only be true if the values match and are the same type.  assert($c === $d);  assert($a !== $d); -assert(1 == '1'); +assert(1 === '1');  assert(1 !== '1');  // Variables can be converted between types, depending on their usage. diff --git a/zh-cn/php-cn.html.markdown b/zh-cn/php-cn.html.markdown index c6ebb515..24939681 100644 --- a/zh-cn/php-cn.html.markdown +++ b/zh-cn/php-cn.html.markdown @@ -180,7 +180,7 @@ assert($c >= $d);  // 下面的比较只有在类型相同、值相同的情况下才为真  assert($c === $d);  assert($a !== $d); -assert(1 == '1'); +assert(1 === '1');  assert(1 !== '1');  // 变量可以根据其使用来进行类型转换 @@ -243,7 +243,7 @@ if ($x === '0') { -// 下面的语法常用语模板中: +// 下面的语法常用于模板中:  ?>  <?php if ($x): ?> @@ -333,7 +333,7 @@ function my_function () {  echo my_function(); // => "Hello"  // 函数名需要以字母或者下划线开头,  -// 后面可以跟着任意的字幕、下划线、数字. +// 后面可以跟着任意的字母、下划线、数字.  function add ($x, $y = 1) { // $y 是可选参数,默认值为 1    $result = $x + $y; | 
