diff options
Diffstat (limited to 'ko-kr')
-rw-r--r-- | ko-kr/brainfuck-kr.html.markdown | 84 | ||||
-rw-r--r-- | ko-kr/clojure-kr.html.markdown | 383 | ||||
-rw-r--r-- | ko-kr/coffeescript-kr.html.markdown | 58 | ||||
-rw-r--r-- | ko-kr/go-kr.html.markdown | 346 | ||||
-rw-r--r-- | ko-kr/java-kr.html.markdown | 408 | ||||
-rw-r--r-- | ko-kr/javascript-kr.html.markdown | 433 | ||||
-rw-r--r-- | ko-kr/lua-kr.html.markdown | 422 | ||||
-rw-r--r-- | ko-kr/php-kr.html.markdown | 662 | ||||
-rw-r--r-- | ko-kr/python-kr.html.markdown | 484 | ||||
-rw-r--r-- | ko-kr/racket-kr.html.markdown | 640 |
10 files changed, 3920 insertions, 0 deletions
diff --git a/ko-kr/brainfuck-kr.html.markdown b/ko-kr/brainfuck-kr.html.markdown new file mode 100644 index 00000000..c2e4341f --- /dev/null +++ b/ko-kr/brainfuck-kr.html.markdown @@ -0,0 +1,84 @@ +--- +language: brainfuck +contributors: + - ["Prajit Ramachandran", "http://prajitr.github.io/"] + - ["Mathias Bynens", "http://mathiasbynens.be/"] +translators: + - ["JongChan Choi", "http://0xABCDEF.com/"] + - ["Peter Lee", "http://peterjlee.com/"] +lang: ko-kr +--- + +Brainfuck(문장을 시작하는 단어가 아닌이상 첫글자는 대문자를 사용하지 않습니다)은 +여덟가지 명령어만으로 튜링-완전한 최소주의 프로그래밍 언어입니다. + +``` +"><+-.,[]" 이외의 문자들은 무시됩니다. (쌍따옴표는 제외) + +브레인퍽은 30,000 칸 짜리의 0으로 초기화된 배열과, +현재 칸을 가르키는 포인터로 표현됩니다. + +여덟가지의 명령어는 다음과 같습니다: ++ : 포인터가 가르키는 현재 칸의 값을 1 증가시킵니다. +- : 포인터가 가르키는 현재 칸의 값을 1 감소시킵니다. +> : 포인터가 다음 칸(오른쪽 칸)을 가르키도록 이동시킵니다. +< : 포인터가 이전 칸(왼쪽 칸)을 가르키도록 이동시킵니다. +. : 현재 칸의 값을 ASCII 문자로 출력합니다. (즉, 65 = 'A') +, : 하나의 문자를 입력받고 그 값을 현재 칸에 대입합니다. +[ : 현재 칸의 값이 0이면 짝이 맞는 ] 명령으로 넘어갑니다. + 0이 아니면 다음 명령어로 넘어갑니다. +] : 현재 칸의 값이 0이면 다음 명령어로 넘어갑니다. + 0이 아니면 짝이 맞는 [ 명령으로 다시 돌아갑니다. + +[이랑 ]은 while 루프를 만들어냅니다. 무조건, 짝이 맞아야 합니다. + +몇가지 간단한 브레인퍽 프로그램을 보겠습니다. + +++++++ [ > ++++++++++ < - ] > +++++ . + +이 프로그램은 문자 'A'를 출력합니다. 처음에는, 반복할 횟수를 정하기 위한 값을 +만들기 위해 첫번째 칸의 값을 6으로 증가시킵니다. 그리고 루프로 들어가서([) +두번째 칸으로 넘어갑니다. 루프 안에서는 두번째 칸의 값을 10 증가시키고, +다시 첫번째 칸으로 넘어가서 값을 1 감소시킵니다. 이 루프는 여섯번 돕니다. +(첫번째 칸의 값을 6번 감소시켜서 0이 될 때 까지는 ] 명령을 만날 때마다 +루프의 시작 지점으로 돌아갑니다) + +이 시점에서, 두번째 칸의 값은 60이고, 포인터는 값이 0인 첫번째 칸에 위치합니다. +여기서 두번째 칸으로 넘어간 다음 값을 5 증가시키면 두번째 칸의 값이 65가 되고, +65는 문자 'A'에 대응하는 아스키 코드이기 때문에, 두번째 칸의 값을 출력하면 +터미널에 'A'가 출력됩니다. + +, [ > + < - ] > . + +이 프로그램은 사용자로부터 문자 하나를 입력받아 첫번째 칸에 집어넣습니다. +그리고 루프에 들어가서, 두번째 칸으로 넘어가 값을 한 번 증가시킨 다음, +다시 첫번째 칸으로 넘어가서 값을 한 번 감소시킵니다. +이는 첫번째 칸의 값이 0이 될 때까지 지속되며, +두번째 칸은 첫번째 칸이 갖고있던 값을 가지게 됩니다. +루프가 종료되면 포인터는 첫번째 칸을 가르키기 때문에 두번째 칸으로 넘어가고, +해당 아스키 코드에 대응하는 문자를 출력합니다. + +또한 공백문자는 순전히 가독성을 위해서 작성되었다는 것을 기억하세요. +다음과 같이 작성해도 똑같이 돌아갑니다: + +,[>+<-]>. + +한 번 돌려보고 아래의 프로그램이 실제로 무슨 일을 하는지 맞춰보세요: + +,>,< [ > [ >+ >+ << -] >> [- << + >>] <<< -] >> + +이 프로그램은 두 개의 숫자를 입력받은 뒤, 그 둘을 곱합니다. + +위 코드는 일단 두 번의 입력을 받고, 첫번째 칸의 값만큼 바깥 루프를 돕니다. +그리고 루프 안에서 다시 두번째 칸의 값만큼 안쪽의 루프를 돕니다. +그리고 그 루프에서는 세번째 칸의 값을 증가시키는데, 문제가 하나 있습니다: +내부 루프가 한 번 끝나게 되면 두번째 칸의 값은 0이 됩니다. +그럼 다시 바깥 루프를 돌 때에 안쪽의 루프를 돌지 않게 되는데, 이를 해결하려면 +네번째 칸의 값도 같이 증가시킨 다음, 그 값을 두번째 칸으로 옮기면 됩니다. +그러면 세번째 칸에 곱셈의 결과가 남습니다. +``` + +여기까지 브레인퍽이었습니다. 참 쉽죠? +재미삼아 브레인퍽 프로그램이나 다른 언어로 브레인퍽 인터프리터를 작성해보세요. +인터프리터 구현은 간단한 편인데, +사서 고생하는 것을 즐기는 편이라면 한 번 작성해보세요… 브레인퍽으로. diff --git a/ko-kr/clojure-kr.html.markdown b/ko-kr/clojure-kr.html.markdown new file mode 100644 index 00000000..1d9e53cd --- /dev/null +++ b/ko-kr/clojure-kr.html.markdown @@ -0,0 +1,383 @@ +--- +language: clojure +filename: learnclojure-kr.clj +contributors: + - ["Adam Bard", "http://adambard.com/"] +translators: + - ["netpyoung", "http://netpyoung.github.io/"] +lang: ko-kr +--- + +Clojure는 Java 가상머신을 위해 개발된 Lisp 계통의 언어입니다 +이는 Common Lisp보다 순수 [함수형 프로그래밍](https://en.wikipedia.org/wiki/Functional_programming)을 더욱 강조했으며, +상태를 있는 그대로 다루기 위해 다양한 [STM](https://en.wikipedia.org/wiki/Software_transactional_memory) 을 지원하는 프로그램들을 갖췄습니다. + +이를 조합하여, 병행처리(concurrent processing)를 매우 단순하게 처리할 수 있으며, +대게 자동으로 처리될 수 있도록 만들 수 있습니다. + +(Clojure 1.2 이상의 버전이 필요로 합니다.) + + +```clojure +; 주석은 세미콜론(;)으로 시작합니다. + +; Clojure는 "폼(forms)"으로 구성되었으며, +; 폼은 괄호로 감싸져있으며, 공백으로 구분된 것들이 나열된 것입니다. +; +; clojure의 reader는 첫번째로 오는 것을 +; 함수 혹은 매크로를 호출하는 것, 그리고 나머지를 인자라고 가정합니다. + +; namespace를 지정하기 위해, 파일에서 우선적으로 호출해야될 것은 ns입니다. +(ns learnclojure) + +; 간단한 예제들: + +; str 은 인자로 받은 것들을 하나의 문자열로 만들어줍니다. +(str "Hello" " " "World") ; => "Hello World" + +; 직관적인 수학 함수들을 갖고 있습니다. +(+ 1 1) ; => 2 +(- 2 1) ; => 1 +(* 1 2) ; => 2 +(/ 2 1) ; => 2 + +; = 로 동일성을 판별할 수 있습니다. +(= 1 1) ; => true +(= 2 1) ; => false + +; 논리연산을 위한 not 역시 필요합니다. +(not true) ; => false + +; 중첩된 폼(forms)은 기대한대로 동작합니다. +(+ 1 (- 3 2)) ; = 1 + (3 - 2) => 2 + +; 타입 +;;;;;;;;;;;;; + +; Clojure는 부울(boolean), 문자열, 숫자를 위해 Java의 object 타입을 이용합니다. +; `class` 를 이용하여 이를 확인할 수 있습니다. +(class 1) ; 정수는 기본적으로 java.lang.Long입니다. +(class 1.); 소수는 java.lang.Double입니다. +(class ""); 문자열은 쌍따옴표로 감싸져 있으며, java.lang.String입니다. +(class false) ; 부울값은 java.lang.Boolean입니다. +(class nil); nil은 "null"값입니다. + +; 데이터 리스트 자체를 만들고자 한다면, +; '를 이용하여 평가(evaluate)되지 않도록 막아야 합니다. +'(+ 1 2) ; => (+ 1 2) +; (quote (+ 1 2)) 를 줄여서 쓴것 + +; quote 가 된 리스트를 평가할 수 도 있습니다. +(eval '(+ 1 2)) ; => 3 + +; 컬렉션(Collections) & 시퀀스(Sequences) +;;;;;;;;;;;;;;;;;;; + +; 리스트(List)는 연결된(linked-list) 자료구조이며, 벡터(Vector)는 배열이 뒤로붙는(array-backed) 자료구조입니다. +; 리스트와 벡터 모두 java 클래스입니다! +(class [1 2 3]); => clojure.lang.PersistentVector +(class '(1 2 3)); => clojure.lang.PersistentList + +; 간단하게 (1 2 3)로 리스트를 나타낼 수 있지만, +; reader가 함수라고 여기지 못하게 quote(')를 해줘야 합니다. +; 따라서, (list 1 2 3)는 '(1 2 3)와 같습니다. + +; "컬렉션"은 단순하게 데이터의 그룹입니다. +; 리스트와 벡터 모두 컬렉션입니다: +(coll? '(1 2 3)) ; => true +(coll? [1 2 3]) ; => true + +; "시퀀스" (seq) 는 데이터 리스트를 추상적으로 기술한 것입니다. +; 리스트는 시퀀스입니다. +(seq? '(1 2 3)) ; => true +(seq? [1 2 3]) ; => false + +; 시퀀스는 접근하고자 하는 항목만 제공해주면 됩니다. +; 따라서, 시퀀스는 lazy 할 수 있습니다 -- 무한하게 늘어나는 것을 정의할 수 있습니다: +(range 4) ; => (0 1 2 3) +(range) ; => (0 1 2 3 4 ...) (an infinite series) +(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 [] "Hello World")) ; => "Hello World" + +; def 를 이용하여 var 를 만들 수 있습니다. +(def x 1) +x ; => 1 + +; var 에 함수를 할당시켜보겠습니다. +(def hello-world (fn [] "Hello World")) +(hello-world) ; => "Hello World" + +; defn 을 이용하여 짧게 쓸 수 도 있습니다. +(defn hello-world [] "Hello World") + +; [] 는 함수의 인자 목록을 나타냅니다. +(defn hello [name] + (str "Hello " name)) +(hello "Steve") ; => "Hello Steve" + +; 약자(shorthand)를 써서 함수를 만들 수 도 있습니다: +(def hello2 #(str "Hello " %1)) +(hello2 "Fanny") ; => "Hello Fanny" + +; 함수가 다양한 인자를 받도록 정의할 수 도 있습니다. +(defn hello3 + ([] "Hello World") + ([name] (str "Hello " name))) +(hello3 "Jake") ; => "Hello Jake" +(hello3) ; => "Hello World" + +; 함수는 여러 인자를 시퀀스로 취할 수 있습니다. +(defn count-args [& args] + (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" + + +; 맵(Maps) +;;;;;;;;;; + +; 해쉬맵(hash map)과 배열맵(array map)은 공통된 인터페이스를 공유합니다. +; 해쉬맵은 찾기가 빠르지만, 키의 순서가 유지되지 않습니다. +(class {:a 1 :b 2 :c 3}) ; => clojure.lang.PersistentArrayMap +(class (hash-map :a 1 :b 2 :c 3)) ; => clojure.lang.PersistentHashMap + +; 배열맵은 여러 연산을 거쳐 자연스레 해쉬맵이 됩니다. +; 만일 이게 커진다 하더라도, 걱정할 필요가 없습니다. + +; 맵은 해쉬가 가능한 타입이라면 어떠한 것이든 키로써 활용이 가능하지만, 보통 키워드를 이용하는 것이 가장 좋습니다. +; 키워드(Keyword)는 문자열과 비슷하지만, 보다 효율적인 면이 있습니다. +(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} + +; 여기서, 쉽표가 공백으로 취급되며, 아무 일도 하지 않는다는 것을 주목하시기 바랍니다. + +; 맵에서 값을 얻어오기 위해선, 함수로써 맵을 호출해야 합니다. +(stringmap "a") ; => 1 +(keymap :a) ; => 1 + +; 키워드 역시 맵에서 함수를 얻어올 때 사용할 수 있습니다! +(:b keymap) ; => 2 + +; 하지만, 문자열로는 하면 안됩니다. +;("a" stringmap) +; => Exception: java.lang.String cannot be cast to clojure.lang.IFn + +; 없는 값을 얻어오고자 하면, nil이 반환됩니다. +(stringmap "d") ; => nil + +; assoc 를 이용하여 해쉬맵에 새로운 키를 추가할 수 있습니다. +(def newkeymap (assoc keymap :d 4)) +newkeymap ; => {:a 1, :b 2, :c 3, :d 4} + +; 하지만, 변경할 수 없는(immutable) clojure 타입이라는 것을 기억해야 합니다! +keymap ; => {:a 1, :b 2, :c 3} + +; dissoc 를 이용하여 키를 제거할 수 있습니다. +(dissoc keymap :a :b) ; => {:c 3} + +; 쎗(Set:집합) +;;;;;; + +(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 네임스페이스(namespace)에는 더 많은 함수들이 있습니다. + +; 유용한 폼(forms) +;;;;;;;;;;;;;;;;; + +; clojure에선, if 와 매크로(macro)를 가지고, +; 다른 여러 논리 연산들을 만들 수 있습니다. +(if false "a" "b") ; => "b" +(if false "a") ; => nil + +; let 을 이용하여 임시적으로 바인딩(binding)을 구축할 수 있습니다. +(let [a 1 b 2] + (> a b)) ; => false + +; 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") + +; 모듈(Modules) +;;;;;;;;;;;;;;; + +; "use" 를 이용하여 module에 있는 모든 함수들을 얻어올 수 있습니다. +(use 'clojure.set) + +; 이제 쎗(set:집합)연산을 사용 할 수 있습니다. +(intersection #{1 2 3} #{2 3 4}) ; => #{2 3} +(difference #{1 2 3} #{2 3 4}) ; => #{1} + +; 함수들 중에 일 부분만을 가져올 수 도 있습니다. +(use '[clojure.set :only [intersection]]) + +; require 를 이용하여 모듈을 import할 수 있습니다. +(require 'clojure.string) + +; / 를 이용하여 모듈에 있는 함수를 호출 할 수 있습니다. +; 여기, clojure.string 라는 모듈에, blank? 라는 함수가 있습니다. +(clojure.string/blank? "") ; => true + +; import시, 모듈에 짧은 이름을 붙여줄 수 있습니다. +(require '[clojure.string :as str]) +(str/replace "This is a test." #"[a-o]" str/upper-case) ; => "THIs Is A tEst." +; (#"" denotes a regular expression literal) + +; :require 를 이용하여, 네임스페이스에서 require 를 사용할 수 있습니다. +; 아레와 같은 방법을 이용하면, 모듈을 quote하지 않아도 됩니다. +(ns test + (:require + [clojure.string :as str] + [clojure.set :as set])) + +; Java +;;;;;;;;;;;;;;;;; + +; Java는 유용한 많은 표준 라이브러리를 가지고 있으며, +; 이를 어떻게 활용할 수 있는지 알아보도록 하겠습니다. + +; import 로 java 모듈을 불러올 수 있습니다. +(import java.util.Date) + +; ns 와 함께 import 를 할 수 도 있습니다. +(ns test + (:import java.util.Date + java.util.Calendar)) + +; 새로운 인스턴스를 만들기 위해선, 클래스 이름 끝에 "."을 찍습니다. +(Date.) ; <a date object> + +; . 을 이용하여 메소드를 호출할 수 있습니다. +; 아니면, 줄여서 ".메소드"로도 호출 할 수 있습니다. +(. (Date.) getTime) ; <a timestamp> +(.getTime (Date.)) ; exactly the same thing. + +; / 를 이용하여 정적메소드를 호출 할 수 있습니다. +(System/currentTimeMillis) ; <a timestamp> (system is always present) + +; doto 를 이용하여 상태가 변하는(mutable) 클래스들을 좀 더 편하게(tolerable) 다룰 수 있습니다. +(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 + +; STM +;;;;;;;;;;;;;;;;; + +; Software Transactional Memory 는 clojure가 영구적인(persistent) 상태를 다루는 방식입니다. +; clojure가 이용하는 몇몇 자료형(construct)이 있습니다. + +; 가장 단순한 것은 atom 입니다. 초기 값을 넣어보도록 하겠습니다. +(def my-atom (atom {})) + +; swap! 으로 atom을 갱신(update)할 수 있습니다! +; swap! 은 함수를 인자로 받아, 그 함수에 대해 현재 atom에 들어있는 값을 첫번째 인자로, +; 나머지를 두번째 인자로 하여 호출합니다. +(swap! my-atom assoc :a 1) ; Sets my-atom to the result of (assoc {} :a 1) +(swap! my-atom assoc :b 2) ; Sets my-atom to the result of (assoc {:a 1} :b 2) + +; '@' 를 이용하여 atom을 역참조(dereference)하여 값을 얻을 수 있습니다. +my-atom ;=> Atom<#...> (atom 객체가 반환됩니다.) +@my-atom ; => {:a 1 :b 2} + +; 여기 atom을 이용한 단순한 카운터가 있습니다. +(def counter (atom 0)) +(defn inc-counter [] + (swap! counter inc)) + +(inc-counter) +(inc-counter) +(inc-counter) +(inc-counter) +(inc-counter) + +@counter ; => 5 + +; STM을 구성하는 다른 것들에는 ref 와 agent 가 있습니다. +; Refs: http://clojure.org/refs +; Agents: http://clojure.org/agents +``` + +### 읽어볼거리 + +부족한 것이 많았지만, 다행히도 채울 수 있는 것들이 많이 있습니다. + +Clojure.org에 많은 문서들이 보관되어 있습니다: +[http://clojure.org/](http://clojure.org/) + +Clojuredocs.org는 core 함수들에 대해 다양한 예제와 문서를 보유하고 있습니다: +[http://clojuredocs.org/quickref/Clojure%20Core](http://clojuredocs.org/quickref/Clojure%20Core) + +4Clojure는 clojure/FP 스킬을 올릴 수 있는 좋은 길입니다: +[http://www.4clojure.com/](http://www.4clojure.com/) + +Clojure-doc.org는 많고 많은 문서들을 보유하고 있습니다: +[http://clojure-doc.org/](http://clojure-doc.org/) diff --git a/ko-kr/coffeescript-kr.html.markdown b/ko-kr/coffeescript-kr.html.markdown new file mode 100644 index 00000000..f8ac8069 --- /dev/null +++ b/ko-kr/coffeescript-kr.html.markdown @@ -0,0 +1,58 @@ +--- +language: coffeescript +category: language +contributors: + - ["Tenor Biel", "http://github.com/L8D"] +filename: coffeescript-kr.coffee +translators: + - ["wikibook", "http://wikibook.co.kr"] +lang: ko-kr +--- + +``` coffeescript +# 커피스크립트(CoffeeScript)는 최신 유행을 따르는 언어입니다. +# 커피스크립트는 여러 현대 언어의 트렌드를 따르는데, +# 그래서 주석을 작성할 때는 루비나 파이썬과 같이 해시를 씁니다. + +### +블록 주석은 이처럼 작성하며, 자바스크립트 코드로 만들어지도록 +'/ *'와 '* /'로 직접적으로 변환됩니다. + +계속하기에 앞서 자바스크립트 시맨틱을 대부분 이해하고 있어야 합니다. +### + +# 할당: +number = 42 #=> var number = 42; +opposite = true #=> var opposite = true; + +# 조건문: +number = -42 if opposite #=> if(opposite) { number = -42; } + +# 함수: +square = (x) -> x * x #=> var square = function(x) { return x * x; } + +# 범위: +list = [1..5] #=> var list = [1, 2, 3, 4, 5]; + +# 객체: +math = + root: Math.sqrt + square: square + cube: (x) -> x * square x +#=> var math = { +# "root": Math.sqrt, +# "square": square, +# "cube": function(x) { return x * square(x); } +#} + +# 가변 인자(splat): +race = (winner, runners...) -> + print winner, runners + +# 존재 여부 확인: +alert "I knew it!" if elvis? +#=> if(typeof elvis !== "undefined" && elvis !== null) { alert("I knew it!"); } + +# 배열 조건 제시법(comprehensions): +cubes = (math.cube num for num in list) #=> ... +``` diff --git a/ko-kr/go-kr.html.markdown b/ko-kr/go-kr.html.markdown new file mode 100644 index 00000000..3012c04f --- /dev/null +++ b/ko-kr/go-kr.html.markdown @@ -0,0 +1,346 @@ +--- +name: Go +category: language +language: Go +filename: learngo-kr.go +contributors: + - ["Sonia Keys", "https://github.com/soniakeys"] + - ["Christopher Bess", "https://github.com/cbess"] + - ["Jesse Johnson", "https://github.com/holocronweaver"] + - ["Quint Guvernator", "https://github.com/qguv"] +translators: + - ["Jongmin Kim", "http://github.com/atomaths"] + - ["Peter Lee", "http://github.com/ins429"] +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 := 'Σ' // 유니코드 코드 포인트를 담고 있고, int32 타입의 가칭(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: + + learnDefer() // defer에 대해 + learnInterfaces() // 곧이어서 좋은 기능에 대한 설명이 나올 거다. +} + +func learnDefer() (ok bool) { + // deferred statements are executed just before the function returns. + // 연기된(deferred) 구문은 함수가 리턴하기 직전에 실행된다. + defer fmt.Println("deferred statements execute in reverse (LIFO) order.") // 연기된 구문은 LIFO순으로 실행된다. + defer fmt.Println("\nThis line is being printed first because") // 이 줄이 먼저 실행된다. + // defer는 주로 파일을 닫는데 사용된다. + // 파일을 닫는함수를 파일을 여는함수에 가까이 둘수 있다. + return true +} + +// 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) // 결과는 위와 같다. + + learnVariadicParams("great", "learning", "here!") +} + +// 함수는 가변 인수(variadic) 파라미터를 가질수 있다. +func learnVariadicParams(myStrings ...interface{}) { + // 가변 인수를 차례로 반복한다. + // 여기서 언더바(언더스코어, `_`)는 배열의 인덱스 인수를 무시한다. + // The underbar here is ignoring the index argument of the array. + for _, param := range myStrings { + fmt.Println("param:", param) + } + + // 가변 인수 값을 가변인수 파라미터로 보내기. + fmt.Println("params:", fmt.Sprintln(myStrings...)) + + 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/) 안에서 +함수 이름 하나를 클릭해보면 소스코드를 브라우저에서 살펴볼 수도 있다. + +Go를 배울수 있는 또하나의 좋은 방법은 [Go by example](https://gobyexample.com/). diff --git a/ko-kr/java-kr.html.markdown b/ko-kr/java-kr.html.markdown new file mode 100644 index 00000000..dc7a356f --- /dev/null +++ b/ko-kr/java-kr.html.markdown @@ -0,0 +1,408 @@ +--- +language: java +filename: java-kr.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) diff --git a/ko-kr/javascript-kr.html.markdown b/ko-kr/javascript-kr.html.markdown new file mode 100644 index 00000000..9561e80c --- /dev/null +++ b/ko-kr/javascript-kr.html.markdown @@ -0,0 +1,433 @@ +--- +language: javascript +category: language +contributors: + - ["Adam Brenecki", "http://adam.brenecki.id.au"] +translators: + - ["wikibook", "http://wikibook.co.kr"] +filename: javascript-kr.js +lang: ko-kr +--- + +자바스크립트는 넷스케이프의 브렌던 아이크(Brendan Eich)가 1995년에 만들었습니다. +원래 자바스크립트는 웹사이트를 위한 단순한 스크립트 언어를 목표로 만들어졌는데, +좀 더 복잡한 웹 애플리케이션을 만들기 위해 자바를 보완하는 역할이었지만 +웹 페이지와의 긴밀한 상호작용과 브라우저에 대한 지원 기능 덕분에 웹 프론트엔드에서 +자바보다 훨씬 더 보편적으로 쓰이게 됐습니다. + +그렇지만 자바스크립트는 웹 브라우저에만 국한되지 않습니다. 구글 크롬의 V8 자바스크립트 +엔진을 위한 독립형 런타임을 제공하는 Node.js는 점점 인기를 얻고 있습니다. + +피드백 주시면 대단히 감사하겠습니다! [@adambrenecki](https://twitter.com/adambrenecki)나 +[adam@brenecki.id.au](mailto:adam@brenecki.id.au)를 통해 저와 만나실 수 있습니다. + +```js +// 주석은 C와 비슷합니다. 한 줄짜리 주석은 두 개의 슬래시로 시작하고, +/* 여러 줄 주석은 슬래시 별표로 시작해서 + 별표 슬래시로 끝납니다. */ + +// 구문은 세미콜론(;)으로 끝낼 수 있습니다. +doStuff(); + +// 하지만 꼭 그럴 필요는 없는데, 특정 경우를 제외하고 +// 새 줄이 시작할 때마다 세미콜론이 자동으로 삽입되기 때문입니다. +doStuff() + +// 여기서는 세미콜론을 생략하겠습니다. 세미콜론을 생략할지 여부는 +// 개인적인 취향이나 프로젝트의 스타일 가이드를 따릅니다. + +/////////////////////////////////// +// 1. 숫자, 문자열, 연산자 + +// 자바스크립트에는 단 하나의 숫자 타입(64비트 IEEE 754 배정도 숫자)만이 +// 있습니다. +3 // = 3 +1.5 // = 1.5 + +// 모든 기초 산술 연산은 기대한 대로 동작합니다. +1 + 1 // = 2 +8 - 1 // = 7 +10 * 2 // = 20 +35 / 5 // = 7 + +// 나누어 떨어지지 않는 나눗셈도 포함됩니다. +5 / 2 // = 2.5 + +// 비트 연산도 지원됩니다. float을 대상으로 비트 연산을 수행하면 +// 32비트까지 부호가 있는 int로 변환됩니다. +1 << 2 // = 4 + +// 괄호를 이용하면 우선순위를 지정할 수 있습니다. +(1 + 3) * 2 // = 8 + +// 실제 숫자가 아닌 특별한 세 가지 값이 있습니다. +Infinity // 1/0 1/0과 같은 연산의 결과 +-Infinity // -1/0과 같은 연산의 결과 +NaN // 0/0과 같은 연산의 결과 + +// 불린 타입도 있습니다. +true +false + +// 문자열은 '나 "로 생성합니다. +'abc' +"Hello, world" + +// 부정 연산에는 ! 기호를 이용합니다. +!true // = false +!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 + +// 문자열은 +로 연결할 수 있습니다. +"Hello " + "world!" // = "Hello world!" + +// 그리고 <와 >로 비교할 수 있습니다. +"a" < "b" // = true + +// 비교 시 타입 강제변환이 수행됩니다. +"5" == 5 // = true + +// ===를 쓰지 않는다면 말이죠. +"5" === 5 // = false + +// charAt을 이용하면 문자열 내의 문자에 접근할 수 있습니다. +"This is a string".charAt(0) + +// null과 undefined도 있습니다. +null // 의도적으로 값이 아님을 나타내는 데 사용합니다. +undefined // 값이 아직 설정되지 않음을 나타내는 데 사용합니다. + +// null, undefinded, NaN, 0, ""은 거짓이며, 그 밖의 다른 모든 값은 참입니다. +// 참고로 0은 거짓이며, "0"은 참입니다(심지어 0 == "0"이더라도). + +/////////////////////////////////// +// 2. 변수, 배열, 객체 + +// 변수는 var 키워드로 선언합니다. 자바스크립트는 동적 타입 언어라서 +// 타입을 지정할 필요가 없습니다. 값을 할당할 때는 = 문자 하나를 사용합니다. +var someVar = 5 + +// var 키워드를 지정하지 않아도 오류는 발생하지 않습니다. +someOtherVar = 10 + +// 그렇지만 변수가 여러분이 정의한 유효범위가 아니라 +// 전역 유효범위에 생성됩니다. + +// 값을 할당하지 않은 채로 선언한 변수는 undefined로 설정됩니다. +var someThirdVar // = undefined + +// 변수에 수학 연산을 수행하는 축약형 표현은 다음과 같습니다. +someVar += 5 // someVar = someVar + 5;와 같음. 이제 someVar는 10. +someVar *= 10 // somVar는 100 + +// 1을 더하거나 빼는 훨씬 더 짧은 표현도 있습니다. +someVar++ // 이제 someVar는 101 +someVar-- // 다시 100으로 되돌아감 + +// 배열은 순차적인 임의 타입 값의 목록입니다. +var myArray = ["Hello", 45, true] + +// 배열의 멤버는 대괄호로 둘러싼 인덱스를 이용해 접근할 수 있습니다. +// 배열의 인덱스는 0부터 시작합니다. +myArray[1] // = 45 + +// 자바스크립트의 객체는 다른 언어의 '사전'이나 '맵'과 같습니다. +// 즉, 키-값 쌍으로 구성된 비순차 컬렉션입니다. +{key1: "Hello", key2: "World"} + +// 키는 문자열이지만 유효한 자바스크립트 식별자일 경우 +// 작은따옴표는 필요하지 않습니다. 값은 어떤 타입이든 사용할 수 있습니다. +var myObj = {myKey: "myValue", "my other key": 4} + +// 객체 속성에도 인덱스를 이용해 접근할 수 있습니다. +myObj["my other key"] // = 4 + +// 또는 키가 유효한 식별자일 경우 점 표기법을 이용해 접근할 수 있습니다. +myObj.myKey // = "myValue" + +// 객체는 변경 가능합니다. 즉, 값을 변경하거나 새 키를 추가할 수 있습니다. +myObj.myThirdKey = true + +// 설정되지 않은 값에 접근하려고 하면 undefined가 반환됩니다. +myObj.myFourthKey // = undefined + +/////////////////////////////////// +// 3. 로직과 제어 구조 + +// if 구조는 여러분이 예상한 대로 동작합니다. +var count = 1 +if (count == 3){ + // count가 3일 경우 평가됨 +} else if (count == 4) { + // count가 4일 경우 평가됨 +} else { + // count가 3이나 4가 아닌 경우에 평가됨 +} + +// while도 마찬가지입니다. +while (true) { + // 무한 루프! +} + +// do-while 문은 항상 최소 한 번은 실행된다는 점을 제외하면 +// while 문과 비슷합니다. +var input +do { + input = getInput() +} while (!isValid(input)) + +// for 문은 C와 자바의 for 문과 같습니다. +// 초기화식; 지속 조건; 증감식 +for (var i = 0; i < 5; i++){ + // 5번 실행됨 +} + +// &&는 논리 and이고 ||는 논리 or입니다. +if (house.size == "big" && house.colour == "blue"){ + house.contains = "bear" +} +if (colour == "red" || colour == "blue"){ + // 색은 빨강이거나 파랑 +} + +// &&와 ||은 "단축 평가"를 수행하는데, 기본값을 설정할 때 유용합니다. +var name = otherName || "default" + +/////////////////////////////////// +// 4. 함수, 유효범위, 클로저 + +// 자바스크립트 함수는 function 키워드로 선언합니다. +function myFunction(thing){ + return thing.toUpperCase() +} +myFunction("foo") // = "FOO" + +// 함수는 "익명"으로, 즉 이름 없이 정의할 수도 있습니다. +function(thing){ + return thing.toLowerCase() +} +// (함수를 가리키는 이름이 없기 때문에 함수를 호출할 수 없습니다) + +// 자바스크립트 함수는 일급 객체이므로 다른 변수에 재할당하고 +// 다른 함수에 인자로 전달할 수 있습니다. 가령, 이벤트 핸들러를 만들 경우 +function myFunction(){ + // 이 코드는 5초 내에 호출됨 +} +setTimeout(myFunction, 5000) + +// 다른 함수를 호출할 때 직접적으로 함수 구문을 작성할 수도 있습니다. + +setTimeout(function myFunction(){ + // 이 코드는 5초 내에 호출됨 +}, 5000) + +// 자바스크립트에는 함수 유효범위가 있습니다. +// 함수는 자체적인 유효범위를 가지지만 다른 블록은 유효범위를 가지지 않습니다. +if (true){ + var i = 5 +} +i // = 5 - 블록 유효범위를 지원하는 언어에서는 undefined가 아닙니다. + +// 이것은 "즉시 실행되는 익명 함수"라는 공통 패턴으로 이어지는데, +// 이 패턴은 임시 변수가 전역 유효범위로 유출되는 것을 방지합니다. +(function(){ + var temporary = 5 + // '전역 객체'에 할당하는 식으로 전역 유효범위에 접근할 수 있는데, + // 브라우저에서 전역 객체는 항상 'window'입니다. 전역 객체는 + // Node.js와 같은 브라우저가 아닌 환경에서는 다른 이름일 수도 있습니다. + window.permanent = 10 + // 또는 앞에서 언급했다시피 var 키워드를 뺄 수도 있습니다. + permanent2 = 15 +})() +temporary // ReferenceError 발생 +permanent // = 10 +permanent2 // = 15 + +// 자바스크립트의 강력한 기능 중 하나는 클로저(closure)입니다. +// 함수가 다른 함수 안에서 정의되면 안쪽에 정의된 함수는 바깥 함수의 +// 모든 변수에 접근할 수 있습니다. +function sayHelloInFiveSeconds(name){ + var prompt = "Hello, " + name + "!" + function inner(){ + alert(prompt) + } + setTimeout(inner, 5000) + // setTimeout은 비동기적으로 동작하므로 이 함수는 5초 동안 + // 기다리지 않고 실행을 마칩니다. 하지만 5초가 지나면 inner에서도 + // prompt의 값에 접근할 수 있습니다. +} +sayHelloInFiveSeconds("Adam") // 5초 내로 "Hello, Adam!"이라고 적힌 팝업이 표시됨 + +/////////////////////////////////// +// 5. 객체 심화; 생성자와 프로토타입 + +// 객체는 함수를 포함할 수 있습니다. +var myObj = { + myFunc: function(){ + return "Hello world!" + } +} +myObj.myFunc() // = "Hello world!" + +// 객체에 포함된 함수가 호출되면 함수에서는 this 키워드를 이용해 +// 해당 함수가 포함된 객체에 접근할 수 있습니다. +myObj = { + myString: "Hello world!", + myFunc: function(){ + return this.myString + } +} +myObj.myFunc() // = "Hello world!" + +// 여기서 설정한 것은 함수가 정의된 곳이 아닌 함수가 호출되는 +// 방식과 관련이 있습니다. 그래서 아래 함수는 객체 컨텍스트에서 +// 호출되지 않으면 동작하지 않습니다. +var myFunc = myObj.myFunc +myFunc() // = undefined + +// 반대로 함수는 객체에 할당하고 this를 통해 해당 객체에 접근할 수 있습니다. +// 함수를 정의할 때 객체에 추가되지 않았더라도 마찬가지입니다. +var myOtherFunc = function(){ + return this.myString.toUpperCase() +} +myObj.myOtherFunc = myOtherFunc +myObj.myOtherFunc() // = "HELLO WORLD!" + +// new 키워드로 함수를 호출하면 새로운 객체가 생성되고 this를 통해 +// 함수에서 사용할 수 있게 됩니다. 이런 식으로 설계된 함수를 생성자라 합니다. + +var MyConstructor = function(){ + this.myNumber = 5 +} +myNewObj = new MyConstructor() // = {myNumber: 5} +myNewObj.myNumber // = 5 + +// 모든 자바스크립트 객체는 'prototype'을 가지고 있습니다. 어떤 객체에 대해 +// 실제 객체에는 존재하지 않는 프로퍼티에 접근하면 인터프리터는 프로로타입에서 +// 해당 프로퍼티를 찾습니다. + +// 일부 자바스크립트 구현체에서는 __proto__라는 마법의 프로퍼티로 +// 객체의 프로토타입에 접근하는 것을 허용하기도 합니다. 프로토타입을 +// 설명하기에는 이런 내용도 도움되겠지만 __proto__는 표준에 포함돼 +// 있지 않습니다. 나중에 프로토타입을 사용하는 표준 방법을 살펴보겠습니다. +var myObj = { + myString: "Hello world!", +} +var myPrototype = { + meaningOfLife: 42, + myFunc: function(){ + return this.myString.toLowerCase() + } +} +myObj.__proto__ = myPrototype +myObj.meaningOfLife // = 42 + +// 이 방법은 함수에도 통합니다. +myObj.myFunc() // = "hello world!" + +// 물론 프로퍼티가 프로토타입에 존재하지 않으면 +// 프로토타입의 프로토타입을 찾는 식으로 진행됩니다. +myPrototype.__proto__ = { + myBoolean: true +} +myObj.myBoolean // = true + +// 여기서 복사는 일어나지 않습니다. 각 객체에는 프로토타입에 대한 +// 참조가 보관돼 있습니다. 이는 프로토타입을 변경하면 변경사항이 +// 모든 곳에 반영된다는 의미입니다. +myPrototype.meaningOfLife = 43 +myObj.meaningOfLife // = 43 + +// 앞에서 __proto__가 표준에 포함돼 있지 않다고 이야기했는데, +// 기존 객체의 프로토타입을 변경하는 표준 방법은 없습니다. +// 하지만 특정 프로토타입을 가지고 새로운 객체를 생성하는 두 가지 +// 방법이 있습니다. + +// 첫 번째 방법은 Object.create를 이용하는 것인데, +// Object.create는 최근에 자바스크립트에 추가된 것이라서 아직까지 +// 모든 구현체에서 이용할 수 있는 것은 아닙니다. +var myObj = Object.create(myPrototype) +myObj.meaningOfLife // = 43 + +// 두 번째 방법은 어디서나 통하는 방법인데, 생성자와 관련이 있습니다. +// 생성자에는 prototype이라는 프로퍼티가 있습니다. 이 프로퍼티는 +// 생성자 함수 자체의 프로토타입이 *아니고* 생성자와 new 키워드를 이용해 +// 객체가 생성될 때 새로운 객체가 받는 프로토타입입니다. +myConstructor.prototype = { + getMyNumber: function(){ + return this.myNumber + } +} +var myNewObj2 = new myConstructor() +myNewObj2.getMyNumber() // = 5 + +// 문자열과 숫자와 같은 내장 타입에도 동등한 래퍼 객체를 +// 생성하는 생성자가 있습니다. +var myNumber = 12 +var myNumberObj = new Number(12) +myNumber == myNumberObj // = true + +// 하지만 정확히 같지는 않습니다. +typeof myNumber // = 'number' +typeof myNumberObj // = 'object' +myNumber === myNumberObj // = false +if (0){ + // 0은 거짓이라서 이 코드는 실행되지 않습니다. +} + +// 하지만 래퍼 객체와 일반 내장 함수는 프로토타입을 공유하기 때문에 +// 가령 문자열에 실제로 기능을 추가할 수 있습니다. +String.prototype.firstCharacter = function(){ + return this.charAt(0) +} +"abc".firstCharacter() // = "a" + +// 이러한 사실은 기존 자바스크립트 버전에서 자바스크립트의 +// 새로운 기능을 구현하는 "폴리필(polyfilling)"에 자주 이용되므로 +// 오래된 버전의 브라우저와 같이 기존 환경에서 사용될 수 있습니다. + +// 예를 들어, Object.create가 모든 구현체에서 사용 가능한 것은 아니라고 +// 했지만 아래의 폴리필을 이용해 Object.create를 여전히 사용할 수 있습니다. +if (Object.create === undefined){ // 이미 존재하면 덮어쓰지 않음 + Object.create = function(proto){ + // 올바른 프로토타입을 가지고 임시 생성자를 만듬 + var Constructor = function(){} + Constructor.prototype = proto + // 그런 다음 임시 생성자를 이용해 새로운 적절한 프로토타입을 + // 포함한 객체를 생성 + return new Constructor() + } +} +``` + +## 기타 참고 자료 + +[모질라 개발자 네트워크](https://developer.mozilla.org/en-US/docs/Web/JavaScript)에서는 +자바스크립트에 대한 훌륭한 문서를 제공합니다. 더불어 위키 형식이라서 좀 더 많은 사항을 +배우게 되면 여러분만의 지식을 공유함으로써 다른 사람들에게 도움을 줄 수도 있습니다. + +MDN의 ['자바스크립트 재입문'](https://developer.mozilla.org/ko/docs/A_re-introduction_to_JavaScript)에서는 +여기서 다룬 개념의 상당수를 더욱 자세히 다루고 있습니다. 이 자료에서는 자바스크립트 언어 자체에 +대해서만 상당히 신중하게 다뤘습니다. 웹 페이지에서 자바스크립트를 사용하는 방법을 배우고 싶다면 +[문서 객체 모델(Document Object Model)](https://developer.mozilla.org/en-US/docs/Using_the_W3C_DOM_Level_1_Core)에 +관해 배우는 것으로 시작하길 바랍니다. + +[자바스크립트 가든](http://bonsaiden.github.io/JavaScript-Garden/)에서는 자바스크립트 언어에서 +직관에 어긋나는 모든 부분들을 심도 있게 다룹니다. + +더불어 이 글에 직접적으로 기여한 분들로, 내용 중 일부는 이 사이트에 있는 +루이 딘(Louie Dihn)의 파이썬 튜토리얼과 모질라 개발자 네트워크에 있는 +[자바스크립트 튜토리얼](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript)을 참고했습니다. diff --git a/ko-kr/lua-kr.html.markdown b/ko-kr/lua-kr.html.markdown new file mode 100644 index 00000000..b4a018ef --- /dev/null +++ b/ko-kr/lua-kr.html.markdown @@ -0,0 +1,422 @@ +--- +language: Lua +category: language +contributors: + - ["Tyler Neylon", "http://tylerneylon.com/"] +translators: + - ["wikibook", "http://wikibook.co.kr"] +lang: ko-kr +filename: learnlua-kr.lua +--- + +```lua +-- 대시 두 개는 한 줄짜리 주석을 의미합니다. + +--[[ + [와 ]를 두 개씩 추가하면 여러 줄 주석이 됩니다. +--]] + +---------------------------------------------------- +-- 1. 변수와 흐름 제어 +---------------------------------------------------- + +num = 42 -- 모든 숫자는 double입니다. +-- 놀랄 필요는 없습니다. 64비트 double은 +-- 정확한 int 값을 저장하기 위해 52비트로 구성돼 +-- 있습니다. 52비트 이하의 int 값에 대해서는 +-- 장비 정밀도와 관련된 문제가 생기지 않습니다. + +s = 'walternate' -- 파이썬과 같은 불변 문자열 +t = "큰따옴표를 써도 됩니다" +u = [[ 이중 대괄호는 + 여러 줄 문자열을 + 나타냅니다.]] +t = nil -- 미정의 t. 루아는 가비지 컬렉션을 지원합니다. + +-- 블록은 do/end와 같은 키워드로 나타냅니다: +while num < 50 do + num = num + 1 -- ++나 += 유형의 연산자는 쓸 수 없습니다. +end + +-- If 절: +if num > 40 then + print('40 이상') +elseif s ~= 'walternate' then -- ~=은 '같지 않다'입니다. + -- 동일성 검사는 파이썬과 마찬가지로 ==입니다. + -- 문자열에도 쓸 수 있습니다. + io.write('not over 40\n') -- 기본적으로 stdout에 씁니다. +else + -- 변수는 기본적으로 전역 변수입니다. + thisIsGlobal = 5 -- 낙타 표기법이 일반적입니다. + + -- 변수를 지역 변수로 만드는 방법은 다음과 같습니다: + local line = io.read() -- 다음 stdin 줄을 읽습니다 + + -- 문자열 연결에는 .. 연산자를 씁니다: + print('겨울이 오고 있습니다, ' .. line) +end + +-- 미정의 변수는 nil을 반환합니다. +-- 다음 코드를 실행해도 오류가 나지 않습니다: +foo = anUnknownVariable -- 이제 foo는 nil입니다. + +aBoolValue = false + +-- nil과 false만이 거짓값입니다; 0과 ''은 참입니다! +if not aBoolValue then print('twas false') end + +-- 'or'와 'and'는 단축 평가(short-circuit)됩니다. +-- 다음 코드는 C/자바스크립트의 a?b:c 연산자와 비슷합니다: +ans = aBoolValue and 'yes' or 'no' --> 'no' + +karlSum = 0 +for i = 1, 100 do -- 범위에는 마지막 요소도 포함됩니다. + karlSum = karlSum + i +end + +-- 카운트 다운을 할 때는 "100, 1, -1"을 범위로 씁니다. +fredSum = 0 +for j = 100, 1, -1 do fredSum = fredSum + j end + +-- 일반적으로 범위는 begin, end[, step]입니다. + +-- 또 다른 반복문 구문은 다음과 같습니다: +repeat + print('미래의 방식') + num = num - 1 +until num == 0 + + +---------------------------------------------------- +-- 2. 함수 +---------------------------------------------------- + +function fib(n) + if n < 2 then return n end + return fib(n - 2) + fib(n - 1) +end + +-- 클로저와 익명 함수도 사용할 수 있습니다: +function adder(x) + -- 반환된 함수는 adder가 호출될 때 생성되고 x의 + -- 값이 유지됩니다: + return function (y) return x + y end +end +a1 = adder(9) +a2 = adder(36) +print(a1(16)) --> 25 +print(a2(64)) --> 100 + +-- 반환문, 함수 호출, 할당문은 길이가 다른 +-- 값의 리스트에 대해서도 모두 동작합니다. +-- 리스트에 값이 더 적을 때는 nil이 할당/반환되고 +-- 리스트에 값이 더 많을 때는 나머지 값은 버려집니다. + +x, y, z = 1, 2, 3, 4 +-- 이제 x = 1, y = 2, z = 3이고 4는 버려집니다. + +function bar(a, b, c) + print(a, b, c) + return 4, 8, 15, 16, 23, 42 +end + +x, y = bar('zaphod') --> "zaphod nil nil"가 출력 +-- 이제 x = 4, y = 8이고 15~42의 값은 버려집니다. + +-- 함수는 일급 객체이고, 지역/전역 유효범위를 가질 +-- 수 있습니다. 아래의 두 함수는 같습니다: +function f(x) return x * x end +f = function (x) return x * x end + +-- 그리고 아래의 두 함수도 마찬가지입니다: +local function g(x) return math.sin(x) end +local g; g = function (x) return math.sin(x) end +-- 'local g'라고 선언하면 g를 지역 함수로 만듭니다. + +-- 그나저나 삼각 함수는 라디안 단위로 동작합니다. + +-- 함수를 호출할 때 문자열 매개변수를 하나만 전달한다면 +-- 괄호를 쓰지 않아도 됩니다: +print 'hello' -- 잘 동작합니다. + + +---------------------------------------------------- +-- 3. 테이블 +---------------------------------------------------- + +-- 테이블 = 루아의 유일한 복합 자료구조로서, 연관 배열입니다. +-- PHP의 배열이나 자바스크립트의 객체와 비슷하며, +-- 리스트로도 사용할 수 있는 해시 기반의 딕셔너리입니다. + +-- 테이블을 딕셔너리/맵으로 사용하기: + +-- 딕셔너리 리터럴은 기본적으로 문자열 키를 가집니다: +t = {key1 = 'value1', key2 = false} + +-- 문자열 키에는 자바스크립트와 유사한 점 표기법을 쓸 수 있습니다: +print(t.key1) -- 'value1'을 출력. +t.newKey = {} -- 새 키/값 쌍을 추가. +t.key2 = nil -- 테이블에서 key2를 제거. + +-- (nil이 아닌) 값을 키로 사용하는 리터럴 표기법: +u = {['@!#'] = 'qbert', [{}] = 1729, [6.28] = 'tau'} +print(u[6.28]) -- "tau"가 출력 + +-- 키 매칭은 기본적으로 숫자와 문자열에 대해서는 값으로 하지만 +-- 테이블에 대해서는 식별자로 합니다. +a = u['@!#'] -- Now a = 'qbert'. +b = u[{}] -- We might expect 1729, but it's nil: +a = u['@!#'] -- 이제 a는 'qbert'입니다. +b = u[{}] -- 1729를 예상했겠지만 nil입니다: +-- 탐색이 실패하기 때문에 b는 nil입니다. 탐색이 실패하는 이유는 +-- 사용된 키가 원본 값을 저장할 때 사용한 키와 동일한 객체가 아니기 +-- 때문입니다. 따라서 문자열 및 숫자가 좀 더 이식성 있는 키입니다. + +-- 테이블 하나를 매개변수로 취하는 함수를 호출할 때는 괄호가 필요하지 않습니다: +function h(x) print(x.key1) end +h{key1 = 'Sonmi~451'} -- 'Sonmi~451'를 출력. + +for key, val in pairs(u) do -- 테이블 순회 + print(key, val) +end + +-- _G는 모든 전역 멤버에 대한 특별한 테이블입니다. +print(_G['_G'] == _G) -- 'true'가 출력 + +-- 테이블을 리스트/배열로 사용하기: + +-- 리스트 리터럴은 암묵적으로 int 키로 설정됩니다: +v = {'value1', 'value2', 1.21, 'gigawatts'} +for i = 1, #v do -- #v는 리스트 v의 크기입니다. + print(v[i]) -- 인덱스가 1에서 시작합니다!! 제정신이 아닙니다! +end +-- 'list'는 실제 타입이 아닙니다. v는 연속된 정수형 키가 포함된 +-- 테이블이고 리스트로 취급될 뿐입니다. + +---------------------------------------------------- +-- 3.1 메타테이블과 메타메서드 +---------------------------------------------------- + +-- 테이블은 테이블에 연산자 오버로딩을 가능하게 하는 메타테이블을 +-- 가질 수 있습니다. 나중에 메타테이블이 어떻게 자바스크립트 +-- 프로토타입과 같은 행위를 지원하는지 살펴보겠습니다. + +f1 = {a = 1, b = 2} -- 분수 a/b를 표현 +f2 = {a = 2, b = 3} + +-- 다음 코드는 실패합니다: +-- s = f1 + f2 + +metafraction = {} +function metafraction.__add(f1, f2) + sum = {} + sum.b = f1.b * f2.b + sum.a = f1.a * f2.b + f2.a * f1.b + return sum +end + +setmetatable(f1, metafraction) +setmetatable(f2, metafraction) + +s = f1 + f2 -- f1의 메타테이블을 대상으로 __add(f1, f2)를 호출 + +-- f1과 f2는 자바스크립트의 프로토타입과 달리 각 메타테이블에 대한 +-- 키가 없어서 getmetatable(f1)과 같이 받아와야 합니다. +-- 메타테이블은 __add 같은 루아가 알고 있는 키가 지정된 일반 테이블입니다. + +-- 그렇지만 다음 줄은 s가 메타테이블을 가지고 있지 않기 때문에 실패합니다. +-- t = s + s +-- 아래와 같이 클래스와 유사한 패턴은 이러한 문제가 발생하지 않습니다. + +-- 메타테이블에 대한 __index는 점을 이용한 탐색을 오버로드합니다: +defaultFavs = {animal = 'gru', food = 'donuts'} +myFavs = {food = 'pizza'} +setmetatable(myFavs, {__index = defaultFavs}) +eatenBy = myFavs.animal -- 동작합니다! 고마워요, 메타테이블! + +-- 직접적인 메타테이블 탐색이 실패할 경우 메타테이블의 __index 값을 이용해 +-- 재시도하고, 이런 과정이 반복됩니다. + +-- __index 값은 좀 더 세분화된 탐색을 위해 function(tbl, key)가 +-- 될 수도 있습니다. + +-- __index, __add, ...의 값을 메타메서드라고 합니다. +-- 다음은 메타메서드를 가진 테이블의 전체 목록입니다. + +-- __add(a, b) for a + b +-- __sub(a, b) for a - b +-- __mul(a, b) for a * b +-- __div(a, b) for a / b +-- __mod(a, b) for a % b +-- __pow(a, b) for a ^ b +-- __unm(a) for -a +-- __concat(a, b) for a .. b +-- __len(a) for #a +-- __eq(a, b) for a == b +-- __lt(a, b) for a < b +-- __le(a, b) for a <= b +-- __index(a, b) <fn이나 테이블> for a.b +-- __newindex(a, b, c) for a.b = c +-- __call(a, ...) for a(...) + +---------------------------------------------------- +-- 3.2 클래스 형태의 테이블과 상속 +---------------------------------------------------- + +-- 루아에는 클래스가 내장돼 있지 않으며, 테이블과 메타테이블을 +-- 이용해 클래스를 만드는 다양한 방법이 있습니다. + +-- 다음 예제에 대한 설명은 하단을 참조합니다. + +Dog = {} -- 1. + +function Dog:new() -- 2. + newObj = {sound = 'woof'} -- 3. + self.__index = self -- 4. + return setmetatable(newObj, self) -- 5. +end + +function Dog:makeSound() -- 6. + print('I say ' .. self.sound) +end + +mrDog = Dog:new() -- 7. +mrDog:makeSound() -- 'I say woof' -- 8. + +-- 1. Dog는 클래스처럼 동작합니다. 실제로는 테이블입니다. +-- 2. function 테이블명:fn(...)은 +-- function 테이블명.fn(self, ...)과 같습니다. +-- :는 self라는 첫 번째 인자를 추가할 뿐입니다. +-- self가 값을 어떻게 얻는지 궁금하다면 아래의 7과 8을 읽어보세요. +-- 3. newObj는 Dog 클래스의 인스턴스가 됩니다. +-- 4. self = 인스턴스화되는 클래스. +-- 주로 self = Dog이지만 상속을 이용하면 이것을 바꿀 수 있습니다. +-- newObj의 메타테이블과 self의 __index를 모두 self에 설정하면 +-- newObj가 self의 함수를 갖게 됩니다. +-- 5. 참고: setmetatable은 첫 번째 인자를 반환합니다. +-- 6. :는 2에서 설명한 것과 같이 동작하지만 이번에는 self가 +-- 클래스가 아닌 인스턴스라고 예상할 수 있습니다. +-- 7. Dog.new(Dog)과 같으므로 new()에서는 self = Dog입니다. +-- 8. mrDog.makeSound(mrDog)과 같으므로 self = mrDog입니다. + +---------------------------------------------------- + +-- 상속 예제: + +LoudDog = Dog:new() -- 1. + +function LoudDog:makeSound() + s = self.sound .. ' ' -- 2. + print(s .. s .. s) +end + +seymour = LoudDog:new() -- 3. +seymour:makeSound() -- 'woof woof woof' -- 4. + +-- 1. LoudDog은 Dog의 메서드와 변수를 갖게 됩니다. +-- 2. self는 new()에서 'sound' 키를 가집니다. 3을 참고하세요. +-- 3. LoudDog.new(LoudDog)과 같고, LoudDog은 'new' 키가 없지만 +-- 메타테이블에서 __index = Dog이기 때문에 Dog.new(LoudDog)으로 +-- 변환됩니다. +-- 결과: seymour의 메타테이블은 LoudDog이고 LoudDog.__index는 +-- LoudDog입니다. 따라서 seymour.key는 seymour.key, +-- LoudDog.key, Dog.key와 같을 것이며, 지정한 키에 어떤 테이블이 +-- 오든 상관없을 것입니다. +-- 4. 'makeSound' 키는 LoudDog에서 발견할 수 있습니다. +-- 이것은 LoudDog.makeSound(seymour)와 같습니다. + +-- 필요할 경우, 하위 클래스의 new()는 기반 클래스의 new()와 유사합니다. +function LoudDog:new() + newObj = {} + -- newObj를 구성 + self.__index = self + return setmetatable(newObj, self) +end + +---------------------------------------------------- +-- 4. 모듈 +---------------------------------------------------- + + +--[[ 여기서 주석을 제거하면 이 스크립트의 나머지 부분은 +-- 실행 가능한 상태가 됩니다. +``` + +```lua +-- mod.lua 파일의 내용이 다음과 같다고 가정해 봅시다. +local M = {} + +local function sayMyName() + print('이소룡') +end + +function M.sayHello() + print('안녕하세요') + sayMyName() +end + +return M + +-- 또 다른 파일에서는 mod.lua의 기능을 이용할 수 있습니다. +local mod = require('mod') -- mod.lua 파일을 실행 + +-- require는 모듈을 포함시키는 표준화된 방법입니다. +-- require는 다음과 같이 동작합니다: (캐싱돼 있지 않을 경우. 하단 참조) +-- mod.lua가 함수의 본문처럼 되므로 mod.lua 안의 지역 멤버는 +-- 밖에서 볼 수 없습니다. + +-- 다음 코드가 동작하는 것은 mod가 mod.lua의 M과 같기 때문입니다. +mod.sayHello() -- 이소룡 씨에게 인사를 건넵니다. + +-- 다음 코드를 실행하면 오류가 발생합니다. +-- sayMyName는 mod.lua 안에서만 존재하기 때문입니다: +mod.sayMyName() -- 오류 + +-- require의 반환값은 캐싱되므로 require를 여러 번 실행해도 +-- 파일은 최대 한 번만 실행됩니다. + +-- mod2.lua에 "print('Hi')"가 들어 있다고 가정해 봅시다. +local a = require('mod2') -- Hi!를 출력 +local b = require('mod2') -- print를 실행하지 않음. a=b + +-- dofile은 require와 비슷하지만 캐싱을 하지 않습니다: +dofile('mod2') --> Hi! +dofile('mod2') --> Hi! (require와 달리 다시 한번 실행됨) + +-- loadfile은 루아 파일을 읽어들이지만 실행하지는 않습니다 +f = loadfile('mod2') -- f()를 호출해야 mod2.lua가 실행됩니다. + +-- loadstring은 문자열에 대한 loadfile입니다. +g = loadstring('print(343)') -- 함수를 반환합니다. +g() -- 343이 출력됩니다. 그전까지는 아무것도 출력되지 않습니다. + +--]] + +``` + +## 참고자료 + +루아를 배우는 일이 흥미진진했던 이유는 <a href="http://love2d.org/">Love 2D 게임 엔진</a>을 이용해 +게임을 만들 수 있었기 때문입니다. 이것이 제가 루아를 배운 이유입니다. + +저는 <a href="http://nova-fusion.com/2012/08/27/lua-for-programmers-part-1/">BlackBulletIV의 "프로그래머를 위한 루아"</a>로 +시작했습니다. 그다음으로 공식 <a href="http://www.lua.org/pil/contents.html">"프로그래밍 루아"</a> 책을 읽었습니다. +그렇게 루아를 배웠습니다. + +lua-users.org에 있는 <a href="http://lua-users.org/files/wiki_insecure/users/thomasl/luarefv51.pdf">짧은 루아 레퍼런스</a>를 +읽어두면 도움될지도 모르겠습니다. + +여기서는 표준 라이브러리에 관해서는 다루지 않았습니다. + +* <a href="http://lua-users.org/wiki/StringLibraryTutorial">string 라이브러리</a> +* <a href="http://lua-users.org/wiki/TableLibraryTutorial">table 라이브러리</a> +* <a href="http://lua-users.org/wiki/MathLibraryTutorial">math 라이브러리</a> +* <a href="http://lua-users.org/wiki/IoLibraryTutorial">io 라이브러리</a> +* <a href="http://lua-users.org/wiki/OsLibraryTutorial">os 라이브러리</a> + +그나저나 이 파일 전체는 유효한 루아 프로그램입니다. 이 파일을 +learn.lua로 저장한 후 "lua learn.lua"를 실행해 보세요! + +이 글은 tylerneylon.com에 처음으로 써본 글이며, +<a href="https://gist.github.com/tylerneylon/5853042">Github의 Gist</a>에서도 확인할 수 있습니다. +루아로 즐거운 시간을 보내세요! diff --git a/ko-kr/php-kr.html.markdown b/ko-kr/php-kr.html.markdown new file mode 100644 index 00000000..1f53221f --- /dev/null +++ b/ko-kr/php-kr.html.markdown @@ -0,0 +1,662 @@ +--- +language: PHP +category: language +contributors: + - ["Malcolm Fell", "http://emarref.net/"] + - ["Trismegiste", "https://github.com/Trismegiste"] +filename: learnphp-kr.php +translators: + - ["wikibook", "http://wikibook.co.kr"] +lang: ko-kr +--- + +이 문서에서는 PHP 5+를 설명합니다. + + +```php +<?php // PHP 코드는 반드시 <?php 태그로 감싸야 합니다. + +// php 파일에 PHP 코드만 들어 있다면 닫는 태그를 생략하는 것이 관례입니다. + +// 슬래시 두 개는 한 줄 주석을 의미합니다. + +# 해시(파운드 기호로도 알려진)도 같은 역할을 하지만 //이 더 일반적으로 쓰입니다. + +/* + 텍스트를 슬래시-별표와 별표-슬래시로 감싸면 + 여러 줄 주석이 만들어집니다. +*/ + +// 출력결과를 표시하려면 "echo"나 "print"를 사용합니다. +print('Hello '); // 줄바꿈 없이 "Hello "를 출력합니다. + +// ()는 print와 echo를 사용할 때 선택적으로 사용할 수 있습니다. +echo "World\n"; // "World"를 출력한 후 줄바꿈합니다. +// (모든 구문은 반드시 세미콜론으로 끝나야 합니다.) + +// <?php 태그 밖의 내용은 모두 자동으로 출력됩니다. +?> +Hello World Again! +<?php + + +/************************************ + * 타입과 변수 + */ + +// 변수명은 $ 기호로 시작합니다. +// 유효한 변수명은 문자나 밑줄(_)로 시작하고, +// 이어서 임의 개수의 숫자나 문자, 밑줄이 옵니다. + +// 불린값은 대소문자를 구분합니다. +$boolean = true; // 또는 TRUE나 True +$boolean = false; // 또는 FALSE나 False + +// Integer +$int1 = 12; // => 12 +$int2 = -12; // => -12 +$int3 = 012; // => 10 (a leading 0 denotes an octal number) +$int4 = 0x0F; // => 15 (a leading 0x denotes a hex literal) + +// Float (doubles로도 알려짐) +$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.' + +// 특수 문자는 큰따옴표에서만 이스케이프됩니다. +$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부터는 여러 줄 문자열을 생성하는 데 나우닥(nowdoc)을 사용할 수 있습니다. +$nowdoc = <<<'END' +Multi line +string +END; + +// 히어닥(heredoc)에서는 문자열 치환을 지원합니다. +$heredoc = <<<END +Multi line +$sgl_quotes +END; + +// 문자열을 연결할 때는 .을 이용합니다. +echo 'This string ' . 'is concatenated'; + + +/******************************** + * 상수 + */ + +// 상수는 define()을 이용해 정의되며, +// 런타임 동안 절대 변경될 수 없습니다! + +// 유효한 상수명은 문자나 밑줄로 시작하고, +// 이어서 임의 개수의 숫자나 문자, 밑줄이 옵니다. +define("FOO", "something"); + +// 상수명을 이용해 직접 상수에 접근할 수 있습니다. +echo 'This outputs '.FOO; + + +/******************************** + * 배열 + */ + +// PHP의 모든 배열은 연관 배열(associative array, 해시맵)입니다. + +// 일부 언어에서 해시맵으로도 알려진 연관 배열은 + +// 모든 PHP 버전에서 동작합니다. +$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!'); +// 표준출력(stdout)에 Hello World!를 출력합니다. +// 브라우저에서 실행할 경우 표준출력은 웹 페이지입니다. + +print('Hello World!'); // echo과 동일 + +// echo는 실제로 언어 구성물에 해당하므로, 괄호를 생략할 수 있습니다. +echo 'Hello World!'; +print 'Hello World!'; // 똑같이 출력됩니다. + +$paragraph = 'paragraph'; + +echo 100; // 스칼라 변수는 곧바로 출력합니다. +echo $paragraph; // 또는 변수의 값을 출력합니다. + +// 축약형 여는 태그를 설정하거나 PHP 버전이 5.4.0 이상이면 +// 축약된 echo 문법을 사용할 수 있습니다. +?> +<p><?= $paragraph ?></p> +<?php + +$x = 1; +$y = 2; +$x = $y; // 이제 $x의 값은 $y의 값과 같습니다. +$z = &$y; +// $z는 이제 $y에 대한 참조를 담고 있습니다. $z의 값을 변경하면 +// $y의 값도 함께 변경되며, 그 반대도 마찬가지입니다. +// $x는 $y의 원래 값을 그대로 유지합니다. + +echo $x; // => 2 +echo $z; // => 2 +$y = 0; +echo $x; // => 2 +echo $z; // => 0 + + +/******************************** + * 로직 + */ +$a = 0; +$b = '0'; +$c = '1'; +$d = '1'; + +// assert는 인자가 참이 아닌 경우 경고를 출력합니다. + +// 다음과 같은 비교는 항상 참이며, 타입이 같지 않더라도 마찬가지입니다. +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 (문자열이 강제로 정수로 변환됩니다) + +$string = 'one'; +echo $string + $string; // => 0 +// + 연산자는 'one'이라는 문자열을 숫자로 형변환할 수 없기 때문에 0이 출력됩니다. + +// 한 변수를 다른 타입으로 처리하는 데 형변환을 사용할 수 있습니다. + +$boolean = (boolean) 1; // => true + +$zero = 0; +$boolean = (boolean) $zero; // => false + +// 대다수의 타입을 형변환하는 데 사용하는 전용 함수도 있습니다. +$integer = 5; +$string = strval($integer); + +$var = null; // 널 타입 + + +/******************************** + * 제어 구조 + */ + +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; // break을 반드시 포함해야 하며, break를 생략하면 + // 'two'와 'three' 케이스로 넘어갑니다. + case 'two': + case 'three': + // 변수가 'two'나 'three'인 경우에 실행될 코드를 작성합니다. + break; + default: + // 기본값으로 실행될 코드를 작성 +} + +// while과 do...while, for 문이 아마 더 친숙할 것입니다. +$i = 0; +while ($i < 5) { + echo $i++; +}; // "01234"를 출력 + +echo "\n"; + +$i = 0; +do { + echo $i++; +} while ($i < 5); // "01234"를 출력 + +echo "\n"; + +for ($x = 0; $x < 10; $x++) { + echo $x; +} // "0123456789"를 출력 + +echo "\n"; + +$wheels = ['bicycle' => 2, 'car' => 4]; + +// foreach 문은 배영를 순회할 수 있습니다. +foreach ($wheels as $wheel_count) { + echo $wheel_count; +} // "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; // while 문을 빠져나옴 + } + echo $i++; +} // "012"를 출력 + +for ($i = 0; $i < 5; $i++) { + if ($i === 3) { + continue; // 이번 순회를 생략 + } + echo $i; +} // "0124"를 출력 + + +/******************************** + * 함수 + */ + +// "function"으로 함수를 정의합니다. +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'); // "A - B - C"를 출력 + +// 문자열을 이용해 이름이 지정된 함수를 호출할 수 있습니다. +$function_name = 'add'; +echo $function_name(1, 2); // => 3 +// 프로그램 방식으로 어느 함수를 실행할지 결정할 때 유용합니다. +// 아니면 call_user_func(callable $callback [, $parameter [, ... ]]);를 사용해도 됩니다. + +/******************************** + * 인클루드 + */ + +<?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'; +// require()는 include()와 같지만 파일을 인클루드할 수 없을 경우 +// 치명적인 오류가 발생한다는 점이 다릅니다. + +// my-include.php의 내용 +<?php + +return 'Anything you like.'; +// 파일의 끝 + +// include와 require는 값을 반환할 수도 있습니다. +$value = include 'my-include.php'; + +// 파일은 지정된 파일 경로를 토대로 인클루드되거나, 혹은 아무것도 명시하지 않은 경우 +// include_path라는 설정 지시지를 따릅니다. include_path에서 파일을 발견할 수 없으면 +// include는 마지막으로 실패하기 전에 호출 스크립트 자체의 디렉터리와 현재 작업 디렉터리를 확인합니다. +/* */ + +/******************************** + * 클래스 + */ + +// 클래스는 class라는 키워드로 정의합니다. + +class MyClass +{ + const MY_CONST = 'value'; // 상수 + + static $staticVar = 'static'; + + // 프로퍼티에는 반드시 가시성을 선언해야 합니다. + public $property = 'public'; + public $instanceProp; + protected $prot = 'protected'; // 이 클래스와 하위 클래스에서 접근할 수 있음 + private $priv = 'private'; // 이 클래스 내에서만 접근 가능 + + // __construct로 생성자를 만듭니다. + public function __construct($instanceProp) { + // $this로 인스턴스 변수에 접근합니다. + $this->instanceProp = $instanceProp; + } + + // 메서드는 클래스 안의 함수로서 선언됩니다. + 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; + } + + // 메서드 재정의 + 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 +{ +} + +// "마법 메서드(magic method)"로 설정자 메서드와 접근자 메서드를 만들 수 있습니다. +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 키워드를 사용해) +// 인터페이스를 구현할 수 있습니다(implments 키워드를 사용해). +// 인터페이스는 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'; + } +} + + +/******************************** + * 특성 + */ + +// 특성(trait)은 PHP 5.4.0부터 사용 가능하며, "trait"으로 선언합니다. + +trait MyTrait +{ + public function myTraitMethod() + { + print 'I have MyTrait'; + } +} + +class MyTraitfulClass +{ + use MyTrait; +} + +$cls = new MyTraitfulClass(); +$cls->myTraitMethod(); // "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 The Right Way](http://www.phptherightway.com/)를 참고하세요. + +PHP를 익히기 전에 다른 훌륭한 패키지 관리자를 지원하는 언어를 사용해본 적이 있다면 [컴포저(Composer)](http://getcomposer.org/)를 확인해 보세요. + +공통 표준이 궁금하다면 PHP 프레임워크 상호운용성 그룹의 [PSR 표준](https://github.com/php-fig/fig-standards)을 참고하세요. diff --git a/ko-kr/python-kr.html.markdown b/ko-kr/python-kr.html.markdown new file mode 100644 index 00000000..ed377a99 --- /dev/null +++ b/ko-kr/python-kr.html.markdown @@ -0,0 +1,484 @@ +--- +language: python +category: language +contributors: + - ["Louie Dinh", "http://ldinh.ca"] +filename: learnpython-ko.py +translators: + - ["wikibook", "http://wikibook.co.kr"] +lang: ko-kr +--- + +파이썬은 귀도 반 로섬이 90년대에 만들었습니다. 파이썬은 현존하는 널리 사용되는 언어 중 하나입니다. +저는 문법적 명료함에 반해 파이썬을 사랑하게 됐습니다. 파이썬은 기본적으로 실행 가능한 의사코드입니다. + +피드백 주시면 정말 감사하겠습니다! [@louiedinh](http://twitter.com/louiedinh)나 +louiedinh [at] [구글의 이메일 서비스]를 통해 저에게 연락하시면 됩니다. + +참고: 이 글은 구체적으로 파이썬 2.7에 해당하는 내용을 담고 있습니다만 +파이썬 2.x에도 적용할 수 있을 것입니다. 파이썬 3을 다룬 튜토리얼도 곧 나올 테니 기대하세요! + +```python +# 한 줄짜리 주석은 해시로 시작합니다. +""" 여러 줄 문자열은 "를 세 개 써서 시작할 수 있고, + 주석으로 자주 사용됩니다. +""" + +#################################################### +## 1. 기본 자료형과 연산자 +#################################################### + +# 숫자 +3 #=> 3 + +# 수학 연산은 예상하신 대로입니다. +1 + 1 #=> 2 +8 - 1 #=> 7 +10 * 2 #=> 20 +35 / 5 #=> 7 + +# 나눗셈은 약간 까다롭습니다. 정수로 나눈 다음 결과값을 자동으로 내림합니다. +5 / 2 #=> 2 + +# 나눗셈 문제를 해결하려면 float에 대해 알아야 합니다. +2.0 # 이것이 float입니다. +11.0 / 4.0 #=> 2.75 훨씬 낫네요 + +# 괄호를 이용해 연산자 우선순위를 지정합니다. +(1 + 3) * 2 #=> 8 + +# 불린(Boolean) 값은 기본형입니다. +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 # 이름 오류가 발생 + +# 표현식으로도 사용할 수 있습니다. +"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가 발생 + +# 슬라이스 문법을 통해 범위를 지정해서 값을 조회할 수 있습니다. +# (이 문법을 통해 간편하게 범위를 지정할 수 있습니다.) +li[1:3] #=> [2, 4] +# 앞부분을 생략합니다. +li[2:] #=> [4, 3] +# 끝부분을 생략합니다. +li[:3] #=> [1, 2, 4] + +# del로 임의의 요소를 제거할 수 있습니다. +del li[2] # li is now [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이고 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 메서드를 이용하면 KeyError가 발생하지 않습니다. +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]) # 이제 some_set는 set([1, 2, 3, 4])입니다. + +# 파이썬 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 문입니다. 파이썬에서는 들여쓰기가 대단히 중요합니다! +# 다음 코드를 실행하면 "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 루프는 조건이 더는 충족되지 않을 때까지 진행됩니다. +prints: + 0 + 1 + 2 + 3 +""" +x = 0 +while x < 4: + print x + x += 1 # x = x + 1의 축약형 + +# try/except 블록을 이용한 예외 처리 + +# 파이썬 2.6 및 상위 버전에서 동작하는 코드 +try: + # raise를 이용해 오류를 발생시킵니다 + raise IndexError("This is an index error") +except IndexError as e: + pass # pass는 단순 no-op 연산입니다. 보통 이곳에 복구 코드를 작성합니다. + + +#################################################### +## 4. 함수 +#################################################### + +# 새 함수를 만들 때 def를 사용합니다. +def add(x, y): + print "x is %s and y is %s" % (x, y) + return x + y # return 문을 이용해 값을 반환합니다. + +# 매개변수를 전달하면서 함수를 호출 +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)를 실행하면 다음과 같은 내용이 출력됩니다: + (1, 2) + {"a": 3, "b": 4} +""" + +# 함수를 호출할 때 varargs/kwargs와 반대되는 일을 할 수 있습니다! +# *를 이용해 튜플을 확장하고 **를 이용해 kwargs를 확장합니다. +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)와 같음 + +# 파이썬에는 일급 함수가 있습니다 +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 + +# 내장된 고차 함수(high order function)도 있습니다. +map(add_10, [1,2,3]) #=> [11, 12, 13] +filter(lambda x: x > 5, [3, 4, 5, 6, 7]) #=> [6, 7] + +# 맵과 필터에 리스트 조건 제시법(list comprehensions)을 사용할 수 있습니다. +[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. 클래스 +#################################################### + +# 클래스를 하나 만들기 위해 특정 객체의 하위 클래스를 만들 수 있습니다. +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="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 + +# 모듈의 모든 함수를 임포트할 수 있습니다. +# Warning: this is not recommended +from math import * + +# 모듈 이름을 축약해서 쓸 수 있습니다. +import math as m +math.sqrt(16) == m.sqrt(16) #=> True + +# 파이썬 모듈은 평범한 파이썬 파일에 불과합니다. +# 직접 모듈을 작성해서 그것들을 임포트할 수 있습니다. +# 모듈의 이름은 파일의 이름과 같습니다. + +# 다음과 같은 코드로 모듈을 구성하는 함수와 속성을 확인할 수 있습니다. +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) diff --git a/ko-kr/racket-kr.html.markdown b/ko-kr/racket-kr.html.markdown new file mode 100644 index 00000000..8d830279 --- /dev/null +++ b/ko-kr/racket-kr.html.markdown @@ -0,0 +1,640 @@ +--- + +language: racket +filename: learnracket-kr.rkt +contributors: + - ["th3rac25", "https://github.com/voila"] + - ["Eli Barzilay", "https://github.com/elibarzilay"] + - ["Gustavo Schmidt", "https://github.com/gustavoschmidt"] + - ["Duong H. Nguyen", "https://github.com/cmpitg"] +translators: + - ["KIM Taegyoon", "https://github.com/kimtg"] +lang: ko-kr +--- + +Racket 은 Lisp/Scheme 계열의 일반 목적의, 다중 패러다임 프로그래밍 언어이다. + +```racket +#lang racket ; 우리가 사용하는 언어를 정의한다. + +;;; 주석 + +;; 한 줄 주석은 세미콜론으로 시작한다. + +#| 블록 주석 + 은 여러 줄에 걸칠 수 있으며... + #| + 중첩될 수 있다! + |# +|# + +;; S-expression 주석은 아래 식을 버리므로, +;; 디버깅할 때 식을 주석화할 때 유용하다. +#; (이 식은 버려짐) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 1. 근본 자료형과 연산자 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; 숫자 +9999999999999999999999 ; 정수 +#b111 ; 이진수 => 7 +#o111 ; 팔진수 => 73 +#x111 ; 16진수 => 273 +3.14 ; 실수 +6.02e+23 +1/2 ; 분수 +1+2i ; 복소수 + +;; 함수 적용은 이렇게 쓴다: (f x y z ...) +;; 여기에서 f는 함수이고 x, y, z는 피연산자이다. +;; 글자 그대로의 데이터 리스트를 만들고 싶다면 평가를 막기 위해 '를 쓰시오. +'(+ 1 2) ; => (+ 1 2) +;; 이제, 산술 연산 몇 개 +(+ 1 1) ; => 2 +(- 8 1) ; => 7 +(* 10 2) ; => 20 +(expt 2 3) ; => 8 +(quotient 5 2) ; => 2 +(remainder 5 2) ; => 1 +(/ 35 5) ; => 7 +(/ 1 3) ; => 1/3 +(exact->inexact 1/3) ; => 0.3333333333333333 +(+ 1+2i 2-3i) ; => 3-1i + +;;; 불린 +#t ; 참 +#f ; 거짓 -- #f가 아닌 것은 참 +(not #t) ; => #f +(and 0 #f (error "doesn't get here")) ; => #f +(or #f 0 (error "doesn't get here")) ; => 0 + +;;; 문자 +#\A ; => #\A +#\λ ; => #\λ +#\u03BB ; => #\λ + +;;; 문자열은 고정 길이의 문자 배열이다. +"Hello, world!" +"Benjamin \"Bugsy\" Siegel" ; 백슬래시는 탈출 문자이다. +"Foo\tbar\41\x21\u0021\a\r\n" ; C 탈출 문자, 유니코드 포함 +"λx:(μα.α→α).xx" ; 유니코드 문자 포함 가능 + +;; 문자열은 붙여질 수 있다! +(string-append "Hello " "world!") ; => "Hello world!" + +;; 문자열은 문자의 리스트처럼 취급될 수 있다. +(string-ref "Apple" 0) ; => #\A + +;; format은 문자열을 형식화하기 위해 사용된다: +(format "~a can be ~a" "strings" "formatted") + +;; 인쇄는 쉽다. +(printf "I'm Racket. Nice to meet you!\n") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 2. 변수 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; define으로 변수를 만든다. +;; 변수명으로 다음 문자를 사용할 수 없다: ()[]{}",'`;#|\ +(define some-var 5) +some-var ; => 5 + +;; 유니코드 문자도 사용 가능하다. +(define ⊆ subset?) +(⊆ (set 3 2) (set 1 2 3)) ; => #t + +;; 앞에서 정의되지 않은 변수에 접근하면 예외가 발생한다. +; x ; => x: undefined ... + +;; 지역 변수: `me'는 (let ...) 안에서만 "Bob"이다. +(let ([me "Bob"]) + "Alice" + me) ; => "Bob" + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 3. 구조체(Struct)와 모음(Collection) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 구조체 +(struct dog (name breed age)) +(define my-pet + (dog "lassie" "collie" 5)) +my-pet ; => #<dog> +(dog? my-pet) ; => #t +(dog-name my-pet) ; => "lassie" + +;;; 쌍 (불변) +;; `cons'는 쌍을 만들고, `car'와 `cdr'는 첫번째와 +;; 두번째 원소를 추출한다. +(cons 1 2) ; => '(1 . 2) +(car (cons 1 2)) ; => 1 +(cdr (cons 1 2)) ; => 2 + +;;; 리스트 + +;; 리스트는 연결-리스트 데이터 구조이며, `cons' 쌍으로 만들어지며 +;; `null' (또는 '()) 로 리스트의 끝을 표시한다. +(cons 1 (cons 2 (cons 3 null))) ; => '(1 2 3) +;; `list'는 편리한 가변인자 리스트 생성자이다. +(list 1 2 3) ; => '(1 2 3) +;; 글자 그대로의 리스트 값에는 인용부호를 쓴다. +'(1 2 3) ; => '(1 2 3) + +;; 리스트의 앞에 항목을 추가하기 위하여 `cons'를 사용한다. +(cons 4 '(1 2 3)) ; => '(4 1 2 3) + +;; 리스트들을 붙이기 위해 `append'를 사용한다. +(append '(1 2) '(3 4)) ; => '(1 2 3 4) + +;; 리스트는 매우 기본적인 자료형이기 때문에, 리스트에 대해 적용되는 많은 기능들이 있다. +;; 예를 들어: +(map add1 '(1 2 3)) ; => '(2 3 4) +(map + '(1 2 3) '(10 20 30)) ; => '(11 22 33) +(filter even? '(1 2 3 4)) ; => '(2 4) +(count even? '(1 2 3 4)) ; => 2 +(take '(1 2 3 4) 2) ; => '(1 2) +(drop '(1 2 3 4) 2) ; => '(3 4) + +;;; 벡터 + +;; 벡터는 고정 길이의 배열이다. +#(1 2 3) ; => '#(1 2 3) + +;; `vector-append'를 사용하여 벡터들을 붙인다. +(vector-append #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6) + +;;; 집합 + +;; 리스트로부터 집합 만들기 +(list->set '(1 2 3 1 2 3 3 2 1 3 2 1)) ; => (set 1 2 3) + +;; 원소를 추가하려면 `set-add'를 사용한다. +;; (함수적: 확장된 집합을 반환하며, 원래의 입력을 변경하지 않는다.) +(set-add (set 1 2 3) 4) ; => (set 1 2 3 4) + +;; 원소를 삭제하려면 `set-remove' +(set-remove (set 1 2 3) 1) ; => (set 2 3) + +;; 존재 여부를 조사하려면 `set-member?' +(set-member? (set 1 2 3) 1) ; => #t +(set-member? (set 1 2 3) 4) ; => #f + +;;; 해시 + +;; 불변의 해시 테이블을 만든다. (가변 예제는 아래에) +(define m (hash 'a 1 'b 2 'c 3)) + +;; 값 꺼내기 +(hash-ref m 'a) ; => 1 + +;; 없는 값을 꺼내는 것은 예외를 발생시킨다. +; (hash-ref m 'd) => no value found + +;; 키가 없을 때 반환할 기본값을 지정할 수 있다. +(hash-ref m 'd 0) ; => 0 + +;; `hash-set'을 사용하여 불변의 해시 테이블을 확장 +;; (원래 것을 변경하지 않고 확장된 해시를 반환한다.) +(define m2 (hash-set m 'd 4)) +m2 ; => '#hash((b . 2) (a . 1) (d . 4) (c . 3)) + +;; 이 해시들은 불변이라는 점을 기억하시오! +m ; => '#hash((b . 2) (a . 1) (c . 3)) <-- no `d' + +;; `hash-remove'로 키를 삭제 (이것도 함수적) +(hash-remove m 'a) ; => '#hash((b . 2) (c . 3)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 3. 함수 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; `lambda'로 함수를 만든다. +;; 함수는 항상 마지막 식을 반환한다. +(lambda () "Hello World") ; => #<procedure> +;; 유니코드 `λ'도 사용 가능 +(λ () "Hello World") ; => same function + +;; 모든 함수를 호출할 때는 괄호를 쓴다, lambda 식도 포함하여. +((lambda () "Hello World")) ; => "Hello World" +((λ () "Hello World")) ; => "Hello World" + +;; 변수에 함수를 할당 +(define hello-world (lambda () "Hello World")) +(hello-world) ; => "Hello World" + +;; 문법적 설탕을 사용하여 함수 정의를 더 짧게할 수 있다: +(define (hello-world2) "Hello World") + +;; 위에서 ()는 함수의 인자 리스트이다. +(define hello + (lambda (name) + (string-append "Hello " name))) +(hello "Steve") ; => "Hello Steve" +;; ... 또는, 설탕 친 정의로: +(define (hello2 name) + (string-append "Hello " name)) + +;; 가변인자 함수에는 `case-lambda'를 사용한다. +(define hello3 + (case-lambda + [() "Hello World"] + [(name) (string-append "Hello " name)])) +(hello3 "Jake") ; => "Hello Jake" +(hello3) ; => "Hello World" +;; ... 또는 선택적 인자에 기본값 지정 +(define (hello4 [name "World"]) + (string-append "Hello " name)) + +;; 함수는 추가 인자를 리스트에 포장할 수 있다. +(define (count-args . args) + (format "You passed ~a args: ~a" (length args) args)) +(count-args 1 2 3) ; => "You passed 3 args: (1 2 3)" +;; ... 설탕 안 친 `lambda' 형식으로는: +(define count-args2 + (lambda args + (format "You passed ~a args: ~a" (length args) args))) + +;; 일반 인자와 포장된 인자를 섞을 수 있다. +(define (hello-count name . args) + (format "Hello ~a, you passed ~a extra args" name (length args))) +(hello-count "Finn" 1 2 3) +; => "Hello Finn, you passed 3 extra args" +;; ... 설탕 안 친 것: +(define hello-count2 + (lambda (name . args) + (format "Hello ~a, you passed ~a extra args" name (length args)))) + +;; 키워드 인자 +(define (hello-k #:name [name "World"] #:greeting [g "Hello"] . args) + (format "~a ~a, ~a extra args" g name (length args))) +(hello-k) ; => "Hello World, 0 extra args" +(hello-k 1 2 3) ; => "Hello World, 3 extra args" +(hello-k #:greeting "Hi") ; => "Hi World, 0 extra args" +(hello-k #:name "Finn" #:greeting "Hey") ; => "Hey Finn, 0 extra args" +(hello-k 1 2 3 #:greeting "Hi" #:name "Finn" 4 5 6) + ; => "Hi Finn, 6 extra args" + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 4. 동등성 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 숫자에는 `='를 사용하시오. +(= 3 3.0) ; => #t +(= 2 1) ; => #f + +;; 개체의 동등성에는 `eq?'를 사용하시오. +(eq? 3 3) ; => #t +(eq? 3 3.0) ; => #f +(eq? (list 3) (list 3)) ; => #f + +;; 모음에는 `equal?'을 사용하시오. +(equal? (list 'a 'b) (list 'a 'b)) ; => #t +(equal? (list 'a 'b) (list 'b 'a)) ; => #f + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 5. 흐름 제어하기 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; 조건 + +(if #t ; 조사 식 + "this is true" ; 그러면 식 + "this is false") ; 아니면 식 +; => "this is true" + +;; 조건에서는 #f가 아니면 참으로 취급된다. +(member 'Groucho '(Harpo Groucho Zeppo)) ; => '(Groucho Zeppo) +(if (member 'Groucho '(Harpo Groucho Zeppo)) + 'yep + 'nope) +; => 'yep + +;; `cond'는 연속하여 조사하여 값을 선택한다. +(cond [(> 2 2) (error "wrong!")] + [(< 2 2) (error "wrong again!")] + [else 'ok]) ; => 'ok + +;;; 양식 맞춤 + +(define (fizzbuzz? n) + (match (list (remainder n 3) (remainder n 5)) + [(list 0 0) 'fizzbuzz] + [(list 0 _) 'fizz] + [(list _ 0) 'buzz] + [_ #f])) + +(fizzbuzz? 15) ; => 'fizzbuzz +(fizzbuzz? 37) ; => #f + +;;; 반복 + +;; 반복은 (꼬리-) 재귀로 한다. +(define (loop i) + (when (< i 10) + (printf "i=~a\n" i) + (loop (add1 i)))) +(loop 5) ; => i=5, i=6, ... + +;; 이름 있는 let으로도... +(let loop ((i 0)) + (when (< i 10) + (printf "i=~a\n" i) + (loop (add1 i)))) ; => i=0, i=1, ... + +;; Racket은 매우 유연한 `for' 형식을 가지고 있다: +(for ([i 10]) + (printf "i=~a\n" i)) ; => i=0, i=1, ... +(for ([i (in-range 5 10)]) + (printf "i=~a\n" i)) ; => i=5, i=6, ... + +;;; 다른 Sequence들을 순회하는 반복 +;; `for'는 여러 가지의 sequence를 순회할 수 있다: +;; 리스트, 벡터, 문자열, 집합, 해시 테이블 등... + +(for ([i (in-list '(l i s t))]) + (displayln i)) + +(for ([i (in-vector #(v e c t o r))]) + (displayln i)) + +(for ([i (in-string "string")]) + (displayln i)) + +(for ([i (in-set (set 'x 'y 'z))]) + (displayln i)) + +(for ([(k v) (in-hash (hash 'a 1 'b 2 'c 3 ))]) + (printf "key:~a value:~a\n" k v)) + +;;; 더 복잡한 반복 + +;; 여러 sequence에 대한 병렬 순회 (가장 짧은 것 기준으로 중단) +(for ([i 10] [j '(x y z)]) (printf "~a:~a\n" i j)) +; => 0:x 1:y 2:z + +;; 중첩 반복 +(for* ([i 2] [j '(x y z)]) (printf "~a:~a\n" i j)) +; => 0:x, 0:y, 0:z, 1:x, 1:y, 1:z + +;; 조건 +(for ([i 1000] + #:when (> i 5) + #:unless (odd? i) + #:break (> i 10)) + (printf "i=~a\n" i)) +; => i=6, i=8, i=10 + +;;; 함축 +;; `for' 반복과 비슷하며, 결과만 수집한다. + +(for/list ([i '(1 2 3)]) + (add1 i)) ; => '(2 3 4) + +(for/list ([i '(1 2 3)] #:when (even? i)) + i) ; => '(2) + +(for/list ([i 10] [j '(x y z)]) + (list i j)) ; => '((0 x) (1 y) (2 z)) + +(for/list ([i 1000] #:when (> i 5) #:unless (odd? i) #:break (> i 10)) + i) ; => '(6 8 10) + +(for/hash ([i '(1 2 3)]) + (values i (number->string i))) +; => '#hash((1 . "1") (2 . "2") (3 . "3")) + +;; 반복의 값을 수집하는 여러 가지 방법이 있다: +(for/sum ([i 10]) (* i i)) ; => 285 +(for/product ([i (in-range 1 11)]) (* i i)) ; => 13168189440000 +(for/and ([i 10] [j (in-range 10 20)]) (< i j)) ; => #t +(for/or ([i 10] [j (in-range 0 20 2)]) (= i j)) ; => #t +;; 임의의 조합을 사용하려면 `for/fold'를 사용: +(for/fold ([sum 0]) ([i '(1 2 3 4)]) (+ sum i)) ; => 10 +;; (이것은 명령형 반복문을 대체하기도 한다.) + +;;; 예외 + +;; 예외를 잡으려면 `with-handlers' 형식을 사용 +(with-handlers ([exn:fail? (lambda (exn) 999)]) + (+ 1 "2")) ; => 999 +(with-handlers ([exn:break? (lambda (exn) "no time")]) + (sleep 3) + "phew") ; => "phew", but if you break it => "no time" + +;; 예외나 다른 값을 던지려면 `raise'를 사용 +(with-handlers ([number? ; catch numeric values raised + identity]) ; return them as plain values + (+ 1 (raise 2))) ; => 2 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 6. 변경 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 기존 변수에 새 값을 할당하려면 `set!'을 사용한다. +(define n 5) +(set! n (add1 n)) +n ; => 6 + +;; 명시적인 가변 값을 사용하려면 box 사용 (다른 언어의 포인터나 참조와 비슷함) +(define n* (box 5)) +(set-box! n* (add1 (unbox n*))) +(unbox n*) ; => 6 + +;; 많은 Racket 자료형은 불변이다 (쌍, 리스트 등). 그러나 어떤 것들은 +;; 가변과 불변형이 둘 다 있다. (string, vector, hash table 등) + +;; `vector'나 `make-vector'로 가변 벡터를 생성한다. +(define vec (vector 2 2 3 4)) +(define wall (make-vector 100 'bottle-of-beer)) +;; 칸을 변경하려면 vector-set!을 사용한다. +(vector-set! vec 0 1) +(vector-set! wall 99 'down) +vec ; => #(1 2 3 4) + +;; 비어 있는 가변 해시 테이블을 만들고 조작한다. +(define m3 (make-hash)) +(hash-set! m3 'a 1) +(hash-set! m3 'b 2) +(hash-set! m3 'c 3) +(hash-ref m3 'a) ; => 1 +(hash-ref m3 'd 0) ; => 0 +(hash-remove! m3 'a) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 7. 모듈 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 모듈은 코드를 여러 파일과 재사용 가능한 라이브러리로 조직하게 한다. +;; 여기서 우리는 서브-모듈을 사용한다. 이 글이 만드는 전체 모듈("lang" 줄 부터 시작)에 포함된 모듈이다. + +(module cake racket/base ; racket/base 기반의 `cake' 모듈 정의 + + (provide print-cake) ; 모듈이 노출(export)시키는 함수 + + (define (print-cake n) + (show " ~a " n #\.) + (show " .-~a-. " n #\|) + (show " | ~a | " n #\space) + (show "---~a---" n #\-)) + + (define (show fmt n ch) ; 내부 함수 + (printf fmt (make-string n ch)) + (newline))) + +;; `require'를 사용하여 모듈에서 모든 `provide'된 이름을 사용한다. +(require 'cake) ; '는 지역 지역 서브-모듈을 위한 것이다. +(print-cake 3) +; (show "~a" 1 #\A) ; => 에러, `show'가 export되지 않았음 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 8. 클래스와 개체 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 클래스 fish%를 생성한다. (-%는 클래스 정의에 쓰이는 관용구) +(define fish% + (class object% + (init size) ; 초기화 인자 + (super-new) ; 상위 클래스 초기화 + ;; 필드 + (define current-size size) + ;; 공용 메서드 + (define/public (get-size) + current-size) + (define/public (grow amt) + (set! current-size (+ amt current-size))) + (define/public (eat other-fish) + (grow (send other-fish get-size))))) + +;; fish%의 인스턴스를 생성한다. +(define charlie + (new fish% [size 10])) + +;; 개체의 메서드를 호출하기 위해 `send'를 사용한다. +(send charlie get-size) ; => 10 +(send charlie grow 6) +(send charlie get-size) ; => 16 + +;; `fish%'는 보통의 "일급" 값이며, mixin을 줄 수 있다. +(define (add-color c%) + (class c% + (init color) + (super-new) + (define my-color color) + (define/public (get-color) my-color))) +(define colored-fish% (add-color fish%)) +(define charlie2 (new colored-fish% [size 10] [color 'red])) +(send charlie2 get-color) +;; 또는, 이름 없이: +(send (new (add-color fish%) [size 10] [color 'red]) get-color) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 9. 매크로 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 매크로는 언어의 문법을 확장할 수 있게 한다. + +;; while 반복문을 추가하자. +(define-syntax-rule (while condition body ...) + (let loop () + (when condition + body ... + (loop)))) + +(let ([i 0]) + (while (< i 10) + (displayln i) + (set! i (add1 i)))) + +;; 매크로는 위생적이다. 즉, 기존 변수를 침범할 수 없다. +(define-syntax-rule (swap! x y) ; -!는 변경의 관용구 + (let ([tmp x]) + (set! x y) + (set! y tmp))) + +(define tmp 2) +(define other 3) +(swap! tmp other) +(printf "tmp = ~a; other = ~a\n" tmp other) +;; `tmp` 변수는 이름 충돌을 피하기 위해 `tmp_1`로 이름이 변경된다. +;; (let ([tmp_1 tmp]) +;; (set! tmp other) +;; (set! other tmp_1)) + +;; 하지만 그것들은 단지 코드 변형일 뿐이다. 예를 들어: +(define-syntax-rule (bad-while condition body ...) + (when condition + body ... + (bad-while condition body ...))) +;; 이 매크로는 엉터리다: 무한 코드를 생성하며, +;; 이것을 사용하려고 하면 컴파일러가 무한 반복에 빠진다. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 10. 계약(Contract) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 계약은 모듈에서 노출된 값에 대해 제약을 부여한다. + +(module bank-account racket + (provide (contract-out + [deposit (-> positive? any)] ; 값은 양수여야 함 + [balance (-> positive?)])) + + (define amount 0) + (define (deposit a) (set! amount (+ amount a))) + (define (balance) amount) + ) + +(require 'bank-account) +(deposit 5) + +(balance) ; => 5 + +;; 양수가 아닌 값을 예치하려고 하는 고객은 비난받는다. +;; (deposit -5) ; => deposit: contract violation +;; expected: positive? +;; given: -5 +;; more details.... + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 11. 입력과 출력 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Racket은 이 "port"라는 개념이 있다. 이것은 다른 언어의 +;; 파일 서술자 (file descriptor)와 매우 비슷하다. + +;; "/tmp/tmp.txt"를 열고 "Hello World"를 기록한다. +;; 그 파일이 이미 있다면 에러를 발생시킨다. +(define out-port (open-output-file "/tmp/tmp.txt")) +(displayln "Hello World" out-port) +(close-output-port out-port) + +;; "/tmp/tmp.txt"에 붙이기 +(define out-port (open-output-file "/tmp/tmp.txt" + #:exists 'append)) +(displayln "Hola mundo" out-port) +(close-output-port out-port) + +;; 파일에서 다시 읽기 +(define in-port (open-input-file "/tmp/tmp.txt")) +(displayln (read-line in-port)) +; => "Hello World" +(displayln (read-line in-port)) +; => "Hola mundo" +(close-input-port in-port) + +;; 다르게, call-with-output-file을 사용하면, 명시적으로 파일을 닫지 않아도 된다. +(call-with-output-file "/tmp/tmp.txt" + #:exists 'update ; 내용을 다시 쓴다. + (λ (out-port) + (displayln "World Hello!" out-port))) + +;; call-with-input-file은 입력에 대해 같은 방식으로 작동한다. +(call-with-input-file "/tmp/tmp.txt" + (λ (in-port) + (displayln (read-line in-port)))) +``` + +## 더 읽을거리 + +더 배우고 싶으면, [Getting Started with Racket](http://docs.racket-lang.org/getting-started/)도 보시오. |