Некоторое время назад столкнулся с очень интересным языком программирования, носящим гордое название Go)
Оказывается, он существует уже достаточно давно и количество проектов в code.google, написанных на этом языке уже не так мало (http://code.google.com/hosting/search?q=label:Go). Для справки, wikipedia сообщает, что
"На данный момент его поддержка осуществляется для операционных систем FreeBSD, Linux, Mac OS X и частично Windows" (линуксоиды, радуемся!)).Насколько я понял, причиной создания Go явилась Идея - попытка сделать нечто такое, что работало бы чрезвычайно быстро, но при этом радовало простотой разработки. Т.е. совместить C/C++ и python)
Т.к. язык разрабатывается компанией Google и поддерживает много интересные вещей (например, сборку мусора или обобщенного программирования), то я просто не мог обойти его своим вниманием.
Пару слов об установке на linux
- для установки потребуются следующие пакеты:
$ sudo apt-get install python-setuptools python-dev mercurial bison gcc libc6-dev ed make - добавить переменные окружения (директории, конечно, можете выбрать любые)
export GOROOT=$HOME/go export GOARCH=386 export GOOS=linux export GOBIN=$HOME/bin export PATH=$GOBIN:$PATH - затем добавить эти строки в .bashr и не забыть создать нужные директории
$ mkdir ~/bin$ chmod 755 ~/bin - далее надо клонировать репозиторий Go
и начать установку, выполнив скрипт .all.bash$ hg clone -r release https://go.googlecode.com/hg/ $GOROOT$ cd $GOROOT/src$ ./all.bash
Для разработки можно использовать Go перспективу для eclipse (хотя она мне почему-то не впечатлила), либо взять плагин для gedit (http://go-lang.cat-v.org/text-editors/gedit/) или другого удобного редактора.
Начинаем кодить
Ну теперь стоит прикоснуться к Go и что-нибудь написать) Hello World никому не интересны, поэтому я решил поглядеть на пример написания простенького веб-приложения, которое будет отображать wiki страницу. Итак...
Для начала создадим файл wiki.go, который будет содержать код приложения, и постепенно наполним его смыслом)
Для начала создадим файл wiki.go, который будет содержать код приложения, и постепенно наполним его смыслом)
package main
import (
"http"
"io/ioutil"
"os"
"regexp"
"template"
)
Конечно, package) здесь говорим, что создаем пакет main и импортируем другие необходимые для работы пакеты.
- regexp - для работы с регулярными выражениями
- template - для работы с шаблонами (далее скажу подробнее)
- os - для работы со стандартными потоками Stdin,Stdout и ошибками
type Page struct {
Title string
Body []byte
} Создаем структуру данных, которая будет описывать веб страницу. Скажу сразу, в Go редко используются точки с запятой, поэтому нужно отбросить внезапно появившееся желание перевести строку следующим образом
func someFunc() { }ибо это вызвет негодования компилятора. Как точку с запятой Go трактует конец не пустой строки (при определенных условиях). Ну и скорее всего такой способ объявления не порадует C-программистов - создатели Go решили сделать объявление переменных более приближенным к человеческому языку, и теперь это выглядит так: "var A int", т.е. переменная такая-то такого-то типа. Но можно и не заморачитаться с объявлением, написав нечто подобное "p, err := loadPage(title)". Здесь loadPage возвращает два значения, которые принимают переменные p и err.Что можно сделать со страницей? Правильно, сохранить в виде файла либо загрузить) Причем сохранение мы описываем прямо на типе Page, указывая перед функцией receiver - (p *Page). Ключевое слово class в Go отсутствует, вместо этого для любого именнованого типа (включая структуры и базовые типы вроде int) можно определить методы работы с ним. Это, конечно, может показаться неожиданным - да что там, это чертовски непривычно и любопытно) Именно поэтому в слайдах документации перед описанием объектно-ориентированности в Go появляется призыв отбросить предубеждения) Для полноты описания, скажу что loadPage возвращает два значения - os.Error отвечает за ошибки, которые могли произойти в процессе загрузки файла. Дальше начинается самое интересное - обработка запросов, приходящих от клиента. Все обработчики будут строиться по определенному принципуfunc (p *Page) save() os.Error { filename := p.Title + ".txt" return ioutil.WriteFile(filename, p.Body, 0600) } func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } return &Page{Title: title, Body: body}, nil }На вход, естесственно, принимается writer для ответа, сам http запрос и название запрошенной страницы. Затем нужная страница загружается по названию и происходит проверка выполнения загрузки. Отображением занимается функция renderTemplate, которая отображает шаблон страницы, заполненный нужными данными.func someHandler(w http.ResponseWriter, r *http.Request, title string) { p, err := loadPage(title) if err != nil { //some error handler return } renderTemplate(w, "someTemplate", p) }Т.к. это все-таки wiki, страницу можно просмотреть, отредактировать и сохранить измененный вариант. Здесь также присутствуют вызовы методов из пакета http - http.Error (отправляет клиенту сообщение об ошибке) и http.Redirect, которая запрашивает сохраненную страницу на просмотр и приводит к выполнению обработчика viewHandler. Теперь настало время renderTemplate)func viewHandler(w http.ResponseWriter, r *http.Request, title string) { p, err := loadPage(title) if err != nil { http.Redirect(w, r, "/edit/"+title, http.StatusFound) return } renderTemplate(w, "view", p) } func editHandler(w http.ResponseWriter, r *http.Request, title string) { p, err := loadPage(title) if err != nil { p = &Page{Title: title} } renderTemplate(w, "edit", p) } func saveHandler(w http.ResponseWriter, r *http.Request, title string) { body := r.FormValue("body") p := &Page{Title: title, Body: []byte(body)} err := p.save() if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) return } http.Redirect(w, r, "/view/"+title, http.StatusFound) }а шаблон выглядит примерно так://создаем список, содержащий *Template, ассоциируемый с ключами типа string //make - аналог new в cpp, но совершающий еще некоторые действия, помимо выделения памяти var templates = make(map[string]*template.Template) func init() { //инициализируем список двумя значениями for _, tmpl := range []string{"edit", "view"} { templates[tmpl] = template.MustParseFile(tmpl+".html", nil) } } func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { //шаблон заполняется нужными значениями из p и передается в ResponseWriter err := templates[tmpl].Execute(w, p) if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) } }Т.е. просто туда, где надо, подставляем значения, которые будут получены из объекта Page в будущем. Теперь немного валидации. Все, что передал пользовател, надо проверять - это аксиома)<h1>Editing {Title}</h1> <form action="/save/{Title}" method="POST"> <div><textarea name="body" rows="20" cols="80">{Body|html}</textarea></div> <div><input type="submit" value="Save"></div> </form>На счет регулярок здесь все просто, а вот функция makeHandler требует пристального внимания. Она будет использоваться для создания обработчиков (возвращает http.HandlerFunc) и принимает на вход переменную типа функции с нужными параметрами. По сути, это обертка для наших обработчиков, которая помимо основных действий (представленных вызовом fn(w,r,title)) еще и выполняет проверку запрошенного пользователем заголовка. Ну и, наконец, добрались до финалаconst lenPath = len("/view/") var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$") func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] if !titleValidator.MatchString(title) { http.NotFound(w, r) return } fn(w, r, title) } }Здесь мы просто указываем, какой обработчик будет отвечать за ту или иную страницу. Затем начинаем слушать 8080 порт на localhost'е. Теперь надо все это безобразие собрать и запуститьfunc main() { http.HandleFunc("/view/", makeHandler(viewHandler)) http.HandleFunc("/edit/", makeHandler(editHandler)) http.HandleFunc("/save/", makeHandler(saveHandler)) http.ListenAndServe(":8080", nil) }Отмечу, что компилятор 8g (для архитектуры 386) в использовании во многом напоминает обычный gcc. Ну вот и все, мой рассказ окончен. Боюсь, что получилось несколько сумбурно, но я старался заинтересовать) Вот несколько полезных ссылок:$ 8g wiki.go $ 8l -o wiki wiki.8 $ ./wiki
- http://golang.org (пример кода взят здесь http://golang.org/doc/codelab/wiki/)
- http://go-lang.cat-v.org/
![]() |

0коммент.:
Отправить комментарий