Merge pull request #999 from behzadim/master

Persian Translation
This commit is contained in:
astaxie
2018-07-08 16:08:20 +08:00
committed by GitHub
376 changed files with 4488 additions and 1 deletions

3
.gitignore vendored
View File

@@ -8,4 +8,5 @@ _book
.DS_Store
.gitignore
.vscode
.git
.git
/fa/working

View File

@@ -8,3 +8,4 @@
* [বাংলা](bn/)
* [日本語](ja/)
* [中文](zh/)
* [پارسی](fa/)

View File

@@ -10,6 +10,7 @@
* [বাংলা](bn/preface.md)
* [日本語](ja/preface.md)
* [中文](zh/preface.md)
* [پارسی](fa/preface.md)
# Donate

24
fa/01.0.md Normal file
View File

@@ -0,0 +1,24 @@
<div dir="rtl">
# ۱- پیکربندی محیط Go
به دنیای Go خوش آمدید. وقت آن است که در این دنیای جدید کمی به گشت و گذار بپردازیم!
Go یکی از زبان های برنامه نویسی رایج می باشد که از قابلیت کامپایل سریع، سیستم های همزمان، و گاربیج کالکتور برخوردار است و همچنین دارای مزایای زیر می باشد:
- یک پروژه بزرگ را تنها در چند ثانیه کامپایل می کند.
- یک مدل توسعه ی نرم افزاری فراهم می کند که استدلال در آن آسان است و بدین ترتیب از مشکلاتی که در هدر فایل های سبک C وجود داشت، جلوگیری می کند.
- یک زبان ایستا می باشد که در سیستم خود از داشتن سطوح مختلف خودداری کرده است، بنابراین نیازی نیست که کاربران زمان خود را برای درک ارتباط بین نوع ها سپری کنند. این زبان بیشتر شبیه یک زبان شیءگرای سبک می باشد.
- این زبان مجهز به GC یا گاربیج کالکتور می باشد و از ویژگی های همزمانی و ارتباط برخوردار می باشد.
- این زبان برای کامپیوترهایی که به چند هسته مجهز هستند، طراحی شده است.
Go یک زبان برنامه نویسی کامپایلری است. در این زبان کارایی زبان های پویا یا مفسری در کنار امنیت زبان های ایستا هر دو با هم وجود دارند. این زبان برای کامپیوترهای مدرن و مجهز به چند هسته طراحی شده است که در شبکه هم کاربرد دارد. برای رسیدن به این اهداف، یک سری مسائل هستند که ذاتا باید در سطح انتخاب زبان برنامه نویسی حل شوند؛ برای مثال، یک سیستم سبک وزن کاملا رسا، یک مدل همروندی بومی، و یک گاربیج کالکتوری که به شدت تنظیم شده باشد. برای مدتی طولانی، هیچ بسته یا ابزاری برای رفع همه ی این مسائل معرفی نشد، تا زمانی که انگیزه ای برای توسعه ی زبان Go پدید آمد.
در این فصل، نحوه نصب و پیکربندی محیط توسعه ی Go را بیان خواهم کرد.
## لینک ها
- [فهرست مطالب](preface.md)
- بخش بعدی: [نصب](01.1.md)
</div>

199
fa/01.1.md Normal file
View File

@@ -0,0 +1,199 @@
<div dir="rtl">
# ۱-۱ نصب
## سه روش برای نصب Go
راه های زیادی برای تنظیم محیز توسعه ی Go بر روی کامپیوتر وجود دارند، و شما می توانید از هر یک از این روش ها به دلخواه خود استفاده کنید. به طور کلی سه روش زیر، به عنوان رایج ترین روش ها شناخته می شوند:
- نصب پکیج های رسمی.
- تیم توسعه ی Go پکیج های جامعی را برای ویندوز، لینوکس، مک و سایر سیستم عامل ها فراهم کرده است. این روش نصب، شاید ساده ترین روش ممکن برای شروع باشد. شما می توانید به [صفحه ی دانلود Golang](https://golang.org/dl/) مراجعه کرده و فایل نصبی مورد نظر خود را دانلود کنید.
- نصب Go از طریق کد منبع.
- این روش بین توسعه دهندگان سیستم های شبه یونیکس مرسوم و شناخته شده است.
- استفاده از ابزارهای شخص سوم (third-party)
- ابزارها و پکیج های زیادی برای نصب Go وجود دارند، که شما می توانید از آن ها استفاده کنید. برای مثال apt-get در اوبونتو و homebrew در مک.
اگر به هر دلیلی احتیاح دارید بیشتر از یک نسخه از Go را بر روی یک کامپیوتر داشته باشید، کافیست نگاهی به ابزار [GVM](https://github.com/moovweb/gvm) داشته باشید، که یکی از بهترین ابزارهای موجود برای این منظور می باشد. در غیر این صورت همیشه می توانید این کار را به صورت دستی هم انجام دهید.
## نصب از طریق کد منبع
برای کامپایل Go 1.5 به بالا، کافیست فقط یکی از ورژن های قبلی Go را بر روی سیستم خود داشته باشید، چرا که Go از ویژگی بوت استرپ پشتیبانی می کند. یعنی برای کامپایل Go، به خود Go احتیاج دارید.
برای کامپایل Go 1.4 به پایین، شما به یک کامپایلر C بر روی سیستم خود احتیاج دارید. چراکه هنوز بخش هایی از Go به زبان C و همچنین اسمبلر AT&T نوشته شده است.
اگر از سیستم عامل مک استفاده می کنید و Xcode بر روی سیستم شما نصب است، شما کامپایلر مورد نیاز خود را دارید.
بر روی سیستم های شبه یونیکس، باید gcc یا کامپایلر مشابه نصب باشد. برای مثال، با استفاده از مدیر بسته apt-get (که در اوبونتو استفاده می شود)، کامپایلرهای مورد نیاز خود را به صورت زیر می توانید نصب کنید.
</div>
```sh
sudo apt-get install gcc libc6-dev
```
<div dir="rtl">
اگر از سیستم عامل ویندوز استفاده می کنید، برای نصب gcc ابتدا باید MinGW را نصب کنید. همچنین به خاطر بسپارید که بعد از اتمام مراحل نصب، محیط متغیرها را تنظیم کنید.( ***اگر از نسخه ۶۴ بیتی ویندوز استفاده می کنید، ورژن ۶۴ بیتی MinGW را نصب کنید.*** )
در این مرحله، دستورات زیر را اجرا کنید تا از کد منبع Go یک کلون گرفته و آن را کامپایل نمایید.( ***با این دستور، سورس کد مورد نیاز در دایرکتوری جاری شما کلون می شود. قبل از اینکه ادامه دهید، مسیر کاری خود را تغییر دهید. این امر ممکن است کمی زمان ببرد.*** )
</div>
git clone https://go.googlesource.com/go
cd go/src
./all.bash
<div dir="rtl">
اگر مراحل نصب با موفقیت انجام شده باشد، با پیغام "ALL TESTS PASSED." مواجه خواهید شد که به معنای موفق بودن تست ها می باشد.
بر روی ویندوز، همین کار را می توان با اجرای `all.bat` انجام داد.
اگر از ویندوز استفاده می کنید، پکیج های نصب به صورت خودکار تنظیمات لازم در محیط متغیرهای شما را اعمال می کنند. در سیستم های شبه یونیکس، احتیاج است که این متغیرها به صورت دستی تنظیم شوند که در ادامه نحوه تنظیم آن ها را مشاهده خواهید کرد. ( ***اگر ورژن Go شما بیشتر از ۱.۰ باشد، احتیاجی به تنظیم متغیر $GOBIN نمی باشد، و در واقع این متغیر به صورت خودکار به مسیر $GOROOT/bin مرتبط می شود. در فصل بعد بیشتر به این موضوع می پردازیم.*** )
</div>
export GOROOT=$HOME/go
export GOBIN=$GOROOT/bin
export PATH=$PATH:$GOROOT/bin
<div dir="rtl">
اگر بر روی صفحه نمایش خود، پیغام زیر را مشاهده می کنید، یعنی همه چیز به درستی تنظیم شده است.
![](images/1.1.mac.png?raw=true)
شکل ۱.۱ اطلاعات سیستم بعد از کامپایل سورس کد
اگر این اطلاعات را درباره Go مشاهده کردید، بدین معناست که شما موفق شده اید Go را به درستی بر روی کامپیوتر خود نصب کنید. اگر پیغام "no such command" یا به عبارتی "چنین دستوری وجود ندارد" را دریافت کردید، متغیر $PATH خود را بررسی کنید و مطمئن شوید که مسیر نصبی Go را در بر دارد.
## استفاده از بسته های نصبی استاندارد
Go برای همه سیستم عامل هایی که از آن پشتیبانی می کنند، بسته هایی ارائه داده است که صرفا با یک کلیک نصب می شوند. این بسته ها به صورت پیش فرص در مسیر `/usr/local/go` (در ویندوز `c:\Go`) نصب می شوند. قطعا این مسیرها قابل تغییر است، اما توجه کنید که با تغییر مسیر، تغییرات لازم را در متغیرهای محیطی نیز به صورت دستی اعمال کنید.
### چگونه مطمئن شوید که سیستم عامل شما ۳۲ بیتی است یا ۶۴ بیتی؟
گام بعدی ما بسیار وابسته به نوع سیستم عامل شما دارد، بنابراین قبل از اینکه بسته های نصبی استاندارد را دانلود کنیم، باید آن را بررسی نماییم.
اگر از ویندوز استفاده می کنید، کلیدهای `Win+R` را فشار داده و ابزار دستوری را اجرا کنید. دستور `systeminfo` را تایپ کنید تا به شما اطلاعات لازم را درباره سیستم نمایش دهد. سپس خطی را پیدا کنید که در آن اطلاعات مربوط به نوع سیستم یا "system type" نمایش داده شده است. اگر عبارت "x64-based PC" را مشاهده کردید یعنی سیستم عامل شما ۶۴ بیتی، و در غیر این صورت ۳۲ بیتی می باشد.
اگر کاربر مک هستید، به شما پیشنهاد می کنیم که از بسته ۶۴ بیتی استفاده کنید، چراکه Go پشتیبانی از پردازنده های ۳۲ بیتی بر روی مک را متوقف کرده است.
کاربران لینوکس کافیست دستور `uname -a` را در ترمینال وارد کرده و اطلاعات مربوط به سیستم خود را مشاهده کنند. یک سیستم عامل ۶۴ بیتی اطلاعاتی مشابه با متن زیر خواهد داشت:
</div>
<توضیحات> x86_64 x86_64 x86_64 GNU/Linux
// برخی سیستم ها مثلا اوبونتو ۱۰.۰۴ خروجی مشابه زیر خواهد داشت
x86_64 GNU/Linux
<div dir="rtl">
این اطلاعات برای سیستم عامل های ۳۲ بیتی مشابه زیر خواهد بود:
</div>
<توضیحات> i686 i686 i386 GNU/Linux
<div dir="rtl">
### مک
به [صفحه دانلود](https://golang.org/dl/) رفته، بسته `go1.4.2.darwin-386.pkg` را برای سیستم عامل ۳۲ بیتی (آخرین نسخه، بسته ای برای پردازنده ۳۲ بیتی ندارد) و بسته `go1.8.3.darwin-amd64.pkg` را برای سیستم های ۶۴ بیتی انتخاب کنید. سپس مراحل نصب را صرفا با زدن "next" تا انتها دنبال کنید. بعد از اینکه مراحل نصب با موفقیت به پایان رسید، دایرکتوری `~/go/bin` به متغیر $PATH سیستم شما افزوده خواهد شد. حال کافیست یک ترمینال باز کرده و عبارت `go` را وارد کنید. خروجی حاصل از اجرای این دستور، چیزی مشابه با شکل ۱.۱ خواهد بود.
### لینوکس
به [صفحه دانلود](https://golang.org/dl/) رفته، بسته `go1.8.3.linux-386.tar.gz` را برای سیستم های ۳۲ بیتی و بسته `go1.8.3.linux-amd64.tar.gz` را برای سیستم های ۶۴ بیتی انتخاب و دانلود کنید. با فرض اینکه دایرکتوری مورد نظر شما برای نصب Go، مسیر `$GO_INSTALL_DIR` باشد، بسته دانلودی خود را در این مسیر با استفاده از دستور `tar zxvf go1.8.3.linux-amd64.tar.gz -C $GO_INSTALL_DIR`، از حالت فشرده خارج کنید. سپس $PATH خود را با استفاده از دستور `export PATH=$PATH:$GO_INSTALL_DIR/go/bin` تنظیم کنید. حال کافیست ترمینال خود را باز کرده و عبارت `go` را تایپ کنید. خروجی شما چیزی مشابه با شکل ۱.۱ خواهد بود.
### ویندوز
به [صفحه دانلود](https://golang.org/dl/) رفته، بسته `go1.8.3.windows-386.msi` را برای سیستم های ۳۲ بیتی و `go1.8.3.windows-amd64.msi` را برای سیستم های ۶۴ بیتی انتخاب و دانلود کنید. مراحل نصب را صرفا با کلیک بر روی "next" تا انتها ادامه دهید. بعد از اینکه نصب با موفقیت انجام شد، `c:/go/bin` به `path` افزوده می شود. حال کافیست یک پنجره دستور خطی باز کرده و عبارت `go` را تایپ کنید. خروجی شما چیزی مشابه با شکل ۱.۱ خواهد بود.
## استفاده از ابزارهای سوم شخص (third-party)
### GVM
GVM یک ابزار کنترل ورژن برای Go محسوب می شود که با استفاده از ابزارهای سوم شخص توسعه یافته است (مثل rvm برای ruby). استفاده از این ابزار بسیار آسان است. کافیست با استفاده از دستور زیر در ترمینال، ابتدا gvm را نصب کنید:
</div>
bash < <(curl -s -S -L https://raw.github.com/moovweb/gvm/master/binscripts/gvm-installer)
<div dir="rtl">
سپس با اجرای دستورات زیر، Go را نصب کنید:
</div>
gvm install go1.8.3
gvm use go1.8.3
<div dir="rtl">
بعد از اینکه فرآیند نصب کامل شد، همه چیز برای استفاده آماده و مهیاست.
### apt-get
اوبونتو یکی از مشهورترین توزیع های لینوکسی محسوب می شود که برای دسکتاپ و سرور ارائه شده است. در این توزیع، از ابزار `apt-get` برای مدیریت بسته ها استفاده می شود، بنابراین با استفاده از دستورات زیر به راحتی می توان Go را بر روی اوبونتو نصب نمود.
</div>
sudo add-apt-repository ppa:gophers/go
sudo apt-get update
sudo apt-get install golang-go
<div dir="rtl">
### wget
</div>
```sh
wget https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz
sudo tar -xzf go1.8.3.linux-amd64.tar.gz -C /usr/local
# Go environment
export GOROOT=/usr/local/go
export GOBIN=$GOROOT/bin
export PATH=$PATH:$GOBIN
export GOPATH=$HOME/gopath
```
<div dir="rtl">
از ورژن ۱.۸ به بعد، برای متغیر محیطی GOPATH یک مقدار پیش فرض در نظر گرفته شده است. اگر از سیستم های شبه یونیکس استفاده می کنید این متغیر مقدار `$HOME/go` و اگر کاربر ویندوز هستید مقدار `%USERPROFILE%/go` را در بر خواهد داشت.
### Homebrew
Homebrew ابزاری برای مدیریت نرم افزار می باشد که در مک به شکل رایج جهت مدیریت بسته ها مورد استفاده قرار می گیرد. برای نصب Go کافیست دستورات زیر را وارد کنید.
1. نصب Homebrew
</div>
```sh
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```
<div dir="rtl">
2. نصب Go
</div>
```sh
brew update && brew upgrade
brew install go
```
<div dir="rtl">
## لینک‌ها
- [فهرست مطالب](preface.md)
- بخش قبلی: [پیکربندی محیط Go](01.0.md)
- بخش بعدی: [$GOPATH و فضای کاری](01.2.md)
</div>

57
fa/README.md Normal file
View File

@@ -0,0 +1,57 @@
<div dir="rtl">
***ساخت وب اپلیکیشن با استفاده از Golang***
======================================
### اهداف
از آن جایی که من به توسعه اپلیکیشن در زمینه وب علاقمندم، این کتاب را در وقت آزادم به عنوان یک نسخه متن باز و رایگان تدارک دیدم. این امر الزاما به این معنا نیست که من در ساخت اپلیکیشن های وب مهارت خیلی خوبی دارم. صرفا علاقه داشتم که تجربیات خودم را در ساخت اپلیکیشن وب با استفاده از Go به اشتراک بگذارم.
- اگر در حال حاضر برای ساخت اپلیکیشن وب از زبان هایی مانند PHP/Python/Ruby استفاده می کنید، در این کتاب شما نحوه استفاده از زبان Go را خواهید آموخت.
- اگر شما برنامه نویسی هستید که با زبان هایی مثل C/C++ کار می کنید، در این کتاب نحوه ی عملکرد وب را فرا خواهید گرفت.
اعتقاد من بر این است که هدف از مطالعه، اشتراک اطلاعات با دیگران است. در زندگی شخصی هر چقدر چیزی را با افراد بیشتری به اشتراک بگذارم، باعث خرسندی بیشتر من خواهد بود.
# دونیت
</div>
AliPay: <img src="../zh/images/alipay.png" alt="alipay" width="100" height="100">
English Donate:[donate](http://beego.me/donate)
<div dir="rtl">
## جامعه
</div>
QQ群386056972
BBS[http://gocn.io/](http://gocn.io/)
<div dir="rtl">
### تقدیر و تشکر
</div>
- [四月份平民 April Citizen](https://plus.google.com/110445767383269817959) (review code)
- [洪瑞琦 Hong Ruiqi](https://github.com/hongruiqi) (review code)
- [边 疆 BianJiang](https://github.com/border) (write the configurations about Vim and Emacs for Go development)
- [欧林猫 Oling Cat](https://github.com/OlingCat)(review code)
- [吴文磊 Wenlei Wu](mailto:spadesacn@gmail.com)(provide some pictures)
- [北极星 Polaris](https://github.com/polaris1119)(review whole book)
- [雨 痕 Rain Trail](https://github.com/qyuhen)(review chapter 2 and 3)
<div dir="rtl">
### مجوز
لازم است بدانید که این کتاب تحت مجوز [CC BY-SA 3.0 License](http://creativecommons.org/licenses/by-sa/3.0/) قرار دارد،
و همچنین کدهای استفاده شده در این کتاب تحت مجوز [BSD 3-Clause License](<https://github.com/astaxie/build-web-application-with-golang/blob/master/LICENSE.md>) می باشند، مگر در مواردی که مجوز آن ذکر شده است.
### شروع کنید
[فهرست مطالب](./preface.md)
</div>

7
fa/code/readme.md Normal file
View File

@@ -0,0 +1,7 @@
## Workspace setup.
To avoid workspace issues and be able to develop from any folder within this path,
set the environment variable `GOPATH` to the path of this directory.
More info:
- [GOPATH documentation](http://golang.org/doc/code.html#GOPATH)

View File

@@ -0,0 +1,14 @@
// Example code for Chapter 1.2 from "Build Web Application with Golang"
// Purpose: Run this file to check if your workspace is setup correctly.
// To run, navigate to the current directory in a console and type `go run main.go`
// If the text "Hello World" isn't shown, then setup your workspace again.
package main
import (
"fmt"
"mymath"
)
func main() {
fmt.Printf("Hello, world. Sqrt(2) = %v\n", mymath.Sqrt(2))
}

View File

@@ -0,0 +1,11 @@
// Example code for Chapter ? from "Build Web Application with Golang"
// Purpose: Hello world example demonstrating UTF-8 support.
// To run in the console, type `go run main.go`
// You're missing language fonts, if you're seeing squares or question marks.
package main
import "fmt"
func main() {
fmt.Printf("Hello, world or 你好,世界 or καλημ ́ρα κóσμ or こんにちは世界\n")
}

View File

@@ -0,0 +1,277 @@
// Example code for Chapter 2.2 from "Build Web Application with Golang"
// Purpose: Goes over the assignment and manipulation of basic data types.
package main
import (
"errors"
"fmt"
)
// constants
const Pi = 3.1415926
// booleans default to `false`
var isActive bool // global variable
var enabled, disabled = true, false // omit type of variables
// grouped definitions
const (
i = 1e4
MaxThread = 10
prefix = "astaxie_"
)
var (
frenchHello string // basic form to define string
emptyString string = "" // define a string with empty string
)
func show_multiple_assignments() {
fmt.Println("show_multiple_assignments()")
var v1 int = 42
// Define three variables with type "int", and initialize their values.
// vname1 is v1, vname2 is v2, vname3 is v3
var v2, v3 int = 2, 3
// `:=` only works in functions
// `:=` is the short way of declaring variables without
// specifying the type and using the keyboard `var`.
vname1, vname2, vname3 := v1, v2, v3
// `_` disregards the returned value.
_, b := 34, 35
fmt.Printf("vname1 = %v, vname2 = %v, vname3 = %v\n", vname1, vname2, vname3)
fmt.Printf("v1 = %v, v2 = %v, v3 = %v\n", v1, v2, v3)
fmt.Println("b =", b)
}
func show_bool() {
fmt.Println("show_bool()")
var available bool // local variable
valid := false // Shorthand assignment
available = true // assign value to variable
fmt.Printf("valid = %v, !valid = %v\n", valid, !valid)
fmt.Printf("available = %v\n", available)
}
func show_different_types() {
fmt.Println("show_different_types()")
var (
unicodeChar rune
a int8
b int16
c int32
d int64
e byte
f uint8
g int16
h uint32
i uint64
)
var cmplx complex64 = 5 + 5i
fmt.Println("Default values for int types")
fmt.Println(unicodeChar, a, b, c, d, e, f, g, h, i)
fmt.Printf("Value is: %v\n", cmplx)
}
func show_strings() {
fmt.Println("show_strings()")
no, yes, maybe := "no", "yes", "maybe" // brief statement
japaneseHello := "Ohaiyou"
frenchHello = "Bonjour" // basic form of assign values
fmt.Println("Random strings")
fmt.Println(frenchHello, japaneseHello, no, yes, maybe)
// The backtick, `, will not escape any character in a string
fmt.Println(`This
is on
multiple lines`)
}
func show_string_manipulation() {
fmt.Println("show_string_manipulation()")
var s string = "hello"
//You can't do this with strings
//s[0] = 'c'
s = "hello"
c := []byte(s) // convert string to []byte type
c[0] = 'c'
s2 := string(c) // convert back to string type
m := " world"
a := s + m
d := "c" + s[1:] // you cannot change string values by index, but you can get values instead.
fmt.Printf("%s\n", d)
fmt.Printf("s = %s, c = %v\n", s, c)
fmt.Printf("s2 = %s\n", s2)
fmt.Printf("combined strings\na = %s, d = %s\n", a, d)
}
func show_errors() {
fmt.Println("show_errors()")
err := errors.New("Example error message\n")
if err != nil {
fmt.Print(err)
}
}
func show_iota() {
fmt.Println("show_iota()")
const (
x = iota // x == 0
y = iota // y == 1
z = iota // z == 2
w // If there is no expression after constants name,
// it uses the last expression, so here is saying w = iota implicitly.
// Therefore w == 3, and y and x both can omit "= iota" as well.
)
const v = iota // once iota meets keyword `const`, it resets to `0`, so v = 0.
const (
e, f, g = iota, iota, iota // e=0,f=0,g=0 values of iota are same in one line.
)
fmt.Printf("x = %v, y = %v, z = %v, w = %v\n", x, y, z, w)
fmt.Printf("v = %v\n", v)
fmt.Printf("e = %v, f = %v, g = %v\n", e, f, g)
}
// Functions and variables starting with a capital letter are public to other packages.
// Everything else is private.
func This_is_public() {}
func this_is_private() {}
func set_default_values() {
// default values for the types.
const (
a int = 0
b int8 = 0
c int32 = 0
d int64 = 0
e uint = 0x0
f rune = 0 // the actual type of rune is int32
g byte = 0x0 // the actual type of byte is uint8
h float32 = 0 // length is 4 byte
i float64 = 0 //length is 8 byte
j bool = false
k string = ""
)
}
func show_arrays() {
fmt.Println("show_arrays()")
var arr [10]int // an array of type int
arr[0] = 42 // array is 0-based
arr[1] = 13 // assign value to element
a := [3]int{1, 2, 3} // define a int array with 3 elements
b := [10]int{1, 2, 3}
// define a int array with 10 elements,
// and first three are assigned, rest of them use default value 0.
c := [...]int{4, 5, 6} // use `…` replace with number of length, Go will calculate it for you.
// define a two-dimensional array with 2 elements, and each element has 4 elements.
doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}}
// You can write about declaration in a shorter way.
easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}
fmt.Println("arr =", arr)
fmt.Printf("The first element is %d\n", arr[0]) // get element value, it returns 42
fmt.Printf("The last element is %d\n", arr[9])
//it returns default value of 10th element in this array, which is 0 in this case.
fmt.Println("array a =", a)
fmt.Println("array b =", b)
fmt.Println("array c =", c)
fmt.Println("array doubleArray =", doubleArray)
fmt.Println("array easyArray =", easyArray)
}
func show_slices() {
fmt.Println("show_slices()")
// define a slice with 10 elements which types are byte
var ar = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
// define two slices with type []byte
var a, b []byte
// a points to elements from 3rd to 5th in array ar.
a = ar[2:5]
// now a has elements ar[2]、ar[3] and ar[4]
// b is another slice of array ar
b = ar[3:5]
// now b has elements ar[3] and ar[4]
// define an array
var array = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
// define two slices
var aSlice, bSlice []byte
// some convenient operations
aSlice = array[:3] // equals to aSlice = array[0:3] aSlice has elements a,b,c
aSlice = array[5:] // equals to aSlice = array[5:10] aSlice has elements f,g,h,i,j
aSlice = array[:] // equals to aSlice = array[0:10] aSlice has all elements
// slice from slice
aSlice = array[3:7] // aSlice has elements d,e,f,glen=4cap=7
bSlice = aSlice[1:3] // bSlice contains aSlice[1], aSlice[2], so it has elements e,f
bSlice = aSlice[:3] // bSlice contains aSlice[0], aSlice[1], aSlice[2], so it has d,e,f
bSlice = aSlice[0:5] // slcie could be expanded in range of cap, now bSlice contains d,e,f,g,h
bSlice = aSlice[:] // bSlice has same elements as aSlice does, which are d,e,f,g
fmt.Println("slice ar =", ar)
fmt.Println("slice a =", a)
fmt.Println("slice b =", b)
fmt.Println("array =", array)
fmt.Println("slice aSlice =", aSlice)
fmt.Println("slice bSlice =", bSlice)
fmt.Println("len(bSlice) =", len(bSlice))
}
func show_map() {
fmt.Println("show_map()")
// use string as key type, int as value type, and you have to use `make` initialize it.
var numbers map[string]int
// another way to define map
numbers = make(map[string]int)
numbers["one"] = 1 // assign value by key
numbers["ten"] = 10
numbers["three"] = 3
// Initialize a map
rating := map[string]float32{"C": 5, "Go": 4.5, "Python": 4.5, "C++": 2}
fmt.Println("map numbers =", numbers)
fmt.Println("The third number is: ", numbers["three"]) // get values
// It prints: The third number is: 3
// map has two return values. For second value, if the key doesn't existok is falsetrue otherwise.
csharpRating, ok := rating["C#"]
if ok {
fmt.Println("C# is in the map and its rating is ", csharpRating)
} else {
fmt.Println("We have no rating associated with C# in the map")
}
delete(rating, "C") // delete element with key "c"
fmt.Printf("map rating = %#v\n", rating)
}
func main() {
show_multiple_assignments()
show_bool()
show_different_types()
show_strings()
show_string_manipulation()
show_errors()
show_iota()
set_default_values()
show_arrays()
show_slices()
show_map()
}

View File

@@ -0,0 +1,8 @@
// Example code for Chapter 2.2 from "Build Web Application with Golang"
// Purpose: Try to fix this program.
// From the console, type `go run main.go`
package main
func main() {
var i int
}

View File

@@ -0,0 +1,26 @@
// Example code for Chapter 2.3 from "Build Web Application with Golang"
// Purpose: Creating a basic function
package main
import "fmt"
// return greater value between a and b
func max(a, b int) int {
if a > b {
return a
}
return b
}
func main() {
x := 3
y := 4
z := 5
max_xy := max(x, y) // call function max(x, y)
max_xz := max(x, z) // call function max(x, z)
fmt.Printf("max(%d, %d) = %d\n", x, y, max_xy)
fmt.Printf("max(%d, %d) = %d\n", x, z, max_xz)
fmt.Printf("max(%d, %d) = %d\n", y, z, max(y, z)) // call function here
}

View File

@@ -0,0 +1,14 @@
// As of Google go 1.1.2, `println()` and `print()` are hidden functions included from the runtime package.
// However it's encouraged to use the print functions from the `fmt` package.
package main
import "fmt"
func f() {
fmt.Println("First")
print("Second ")
println(" Third")
}
func main() {
f()
}

View File

@@ -0,0 +1,26 @@
// Example code for Chapter 2.3 from "Build Web Application with Golang"
// Purpose: Shows different ways of importing a package.
// Note: For the package `only_call_init`, we reference the path from the
// base directory of `$GOPATH/src`. The reason being Golang discourage
// the use of relative paths when import packages.
// BAD: "./only_call_init"
// GOOD: "apps/ch.2.3/import_packages/only_call_init"
package main
import (
// `_` will only call init() inside the package only_call_init
_ "apps/ch.2.3/import_packages/only_call_init"
f "fmt" // import the package as `f`
. "math" // makes the public methods and constants global
"mymath" // custom package located at $GOPATH/src/
"os" // normal import of a standard package
"text/template" // the package takes the name of last folder path, `template`
)
func main() {
f.Println("mymath.Sqrt(4) =", mymath.Sqrt(4))
f.Println("E =", E) // references math.E
t, _ := template.New("test").Parse("Pi^2 = {{.}}")
t.Execute(os.Stdout, Pow(Pi, 2))
}

View File

@@ -0,0 +1,7 @@
package only_call_init
import "fmt"
func init() {
fmt.Println("only_call_init.init() was called.")
}

View File

@@ -0,0 +1,142 @@
// Example code for Chapter 2.3 from "Build Web Application with Golang"
// Purpose: Goes over if, else, switch conditions, loops and defer.
package main
import "fmt"
func computedValue() int {
return 1
}
func show_if() {
fmt.Println("\n#show_if()")
x := computedValue()
integer := 23
fmt.Println("x =", x)
fmt.Println("integer =", integer)
if x > 10 {
fmt.Println("x is greater than 10")
} else {
fmt.Println("x is less than 10")
}
if integer == 3 {
fmt.Println("The integer is equal to 3")
} else if integer < 3 {
fmt.Println("The integer is less than 3")
} else {
fmt.Println("The integer is greater than 3")
}
}
func show_if_var() {
fmt.Println("\n#show_if_var()")
// initialize x, then check if x greater than
if x := computedValue(); x > 10 {
fmt.Println("x is greater than 10")
} else {
fmt.Println("x is less than 10")
}
// the following code will not compile, since `x` is only accessible with the if/else block
// fmt.Println(x)
}
func show_goto() {
fmt.Println("\n#show_goto()")
// The call to the label switches the goroutine it seems.
i := 0
Here: // label ends with ":"
fmt.Println(i)
i++
if i < 10 {
goto Here // jump to label "Here"
}
}
func show_for_loop() {
fmt.Println("\n#show_for_loop()")
sum := 0
for index := 0; index < 10; index++ {
sum += index
}
fmt.Println("part 1, sum is equal to ", sum)
sum = 1
// The compiler will remove the `;` from the line below.
// for ; sum < 1000 ; {
for sum < 1000 {
sum += sum
}
fmt.Println("part 2, sum is equal to ", sum)
for index := 10; 0 < index; index-- {
if index == 5 {
break // or continue
}
fmt.Println(index)
}
}
func show_loop_through_map() {
fmt.Println("\n#show_loop_through_map()")
m := map[string]int{
"one": 1,
"two": 2,
"three": 3,
}
fmt.Println("map value = ", m)
for k, v := range m {
fmt.Println("map's key: ", k)
fmt.Println("map's value: ", v)
}
}
func show_switch() {
fmt.Println("\n#show_switch()")
i := 10
switch i {
case 1:
fmt.Println("i is equal to 1")
case 2, 3, 4:
fmt.Println("i is equal to 2, 3 or 4")
case 10:
fmt.Println("i is equal to 10")
default:
fmt.Println("All I know is that i is an integer")
}
integer := 6
fmt.Println("integer =", integer)
switch integer {
case 4:
fmt.Println("integer == 4")
fallthrough
case 5:
fmt.Println("integer <= 5")
fallthrough
case 6:
fmt.Println("integer <= 6")
fallthrough
case 7:
fmt.Println("integer <= 7")
fallthrough
case 8:
fmt.Println("integer <= 8")
fallthrough
default:
fmt.Println("default case")
}
}
func show_defer() {
fmt.Println("\nshow_defer()")
defer fmt.Println("(last defer)")
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
}
func main() {
show_if()
show_if_var()
show_goto()
show_for_loop()
show_loop_through_map()
show_switch()
show_defer()
}

View File

@@ -0,0 +1,31 @@
// Example code for Chapter 2.3 from "Build Web Application with Golang"
// Purpose: Showing how to use `panic()` and `recover()`
package main
import (
"fmt"
"os"
)
var user = os.Getenv("USER")
func check_user() {
if user == "" {
panic("no value for $USER")
}
fmt.Println("Environment Variable `USER` =", user)
}
func throwsPanic(f func()) (b bool) {
defer func() {
if x := recover(); x != nil {
fmt.Println("Panic message =", x);
b = true
}
}()
f() // if f causes panic, it will recover
return
}
func main(){
didPanic := throwsPanic(check_user)
fmt.Println("didPanic =", didPanic)
}

View File

@@ -0,0 +1,31 @@
// Example code for Chapter 2.3 from "Build Web Application with Golang"
// Purpose: Shows passing a variable by value and reference
package main
import "fmt"
func add_by_value(a int) int {
a = a + 1
return a
}
func add_by_reference(a *int) int {
*a = *a + 1
return *a
}
func show_add_by_value() {
x := 3
fmt.Println("x = ", x)
fmt.Println("add_by_value(x) =", add_by_value(x) )
fmt.Println("x = ", x)
}
func show_add_by_reference() {
x := 3
fmt.Println("x = ", x)
// &x pass memory address of x
fmt.Println("add_by_reference(&x) =", add_by_reference(&x) )
fmt.Println("x = ", x)
}
func main() {
show_add_by_value()
show_add_by_reference()
}

View File

@@ -0,0 +1,44 @@
// Example code for Chapter 2.3 from "Build Web Application with Golang"
// Purpose: Shows how to define a function type
package main
import "fmt"
type testInt func(int) bool // define a function type of variable
func isOdd(integer int) bool {
if integer%2 == 0 {
return false
}
return true
}
func isEven(integer int) bool {
if integer%2 == 0 {
return true
}
return false
}
// pass the function `f` as an argument to another function
func filter(slice []int, f testInt) []int {
var result []int
for _, value := range slice {
if f(value) {
result = append(result, value)
}
}
return result
}
func init() {
fmt.Println("\n#init() was called.")
}
func main() {
slice := []int{1, 2, 3, 4, 5, 7}
fmt.Println("slice = ", slice)
odd := filter(slice, isOdd) // use function as values
fmt.Println("Odd elements of slice are: ", odd)
even := filter(slice, isEven)
fmt.Println("Even elements of slice are: ", even)
}

View File

@@ -0,0 +1,20 @@
// Example code for Chapter 2.3 from "Build Web Application with Golang"
// Purpose: Shows how to return multiple values from a function
package main
import "fmt"
// return results of A + B and A * B
func SumAndProduct(A, B int) (int, int) {
return A + B, A * B
}
func main() {
x := 3
y := 4
xPLUSy, xTIMESy := SumAndProduct(x, y)
fmt.Printf("%d + %d = %d\n", x, y, xPLUSy)
fmt.Printf("%d * %d = %d\n", x, y, xTIMESy)
}

View File

@@ -0,0 +1,43 @@
// Example code for Chapter 2.4 from "Build Web Application with Golang"
// Purpose: Shows you how to pass and use structs.
package main
import "fmt"
// define a new type
type person struct {
name string
age int
}
// compare age of two people, return the older person and differences of age
// struct is passed by value
func Older(p1, p2 person) (person, int) {
if p1.age > p2.age {
return p1, p1.age - p2.age
}
return p2, p2.age - p1.age
}
func main() {
var tom person
// initialization
tom.name, tom.age = "Tom", 18
// initialize two values by format "field:value"
bob := person{age: 25, name: "Bob"}
// initialize two values with order
paul := person{"Paul", 43}
tb_Older, tb_diff := Older(tom, bob)
tp_Older, tp_diff := Older(tom, paul)
bp_Older, bp_diff := Older(bob, paul)
fmt.Printf("Of %s and %s, %s is older by %d years\n", tom.name, bob.name, tb_Older.name, tb_diff)
fmt.Printf("Of %s and %s, %s is older by %d years\n", tom.name, paul.name, tp_Older.name, tp_diff)
fmt.Printf("Of %s and %s, %s is older by %d years\n", bob.name, paul.name, bp_Older.name, bp_diff)
}

View File

@@ -0,0 +1,39 @@
// Example code for Chapter 2.4 from "Build Web Application with Golang"
// Purpose: Example of embedded fields
package main
import "fmt"
type Human struct {
name string
age int
weight int
}
type Student struct {
Human // anonymous field, it means Student struct includes all fields that Human has.
speciality string
}
func main() {
// initialize a student
mark := Student{Human{"Mark", 25, 120}, "Computer Science"}
// access fields
fmt.Println("His name is ", mark.name)
fmt.Println("His age is ", mark.age)
fmt.Println("His weight is ", mark.weight)
fmt.Println("His speciality is ", mark.speciality)
// modify notes
mark.speciality = "AI"
fmt.Println("Mark changed his speciality")
fmt.Println("His speciality is ", mark.speciality)
// modify age
fmt.Println("Mark become old")
mark.age = 46
fmt.Println("His age is", mark.age)
// modify weight
fmt.Println("Mark is not an athlete any more")
mark.weight += 60
fmt.Println("His weight is", mark.weight)
}

View File

@@ -0,0 +1,39 @@
// Example code for Chapter 2.4 from "Build Web Application with Golang"
// Purpose: Another example of embedded fields
package main
import "fmt"
type Skills []string
type Human struct {
name string
age int
weight int
}
type Student struct {
Human // struct as embedded field
Skills // string slice as embedded field
int // built-in type as embedded field
speciality string
}
func main() {
// initialize Student Jane
jane := Student{Human: Human{"Jane", 35, 100}, speciality: "Biology"}
// access fields
fmt.Println("Her name is ", jane.name)
fmt.Println("Her age is ", jane.age)
fmt.Println("Her weight is ", jane.weight)
fmt.Println("Her speciality is ", jane.speciality)
// modify value of skill field
jane.Skills = []string{"anatomy"}
fmt.Println("Her skills are ", jane.Skills)
fmt.Println("She acquired two new ones ")
jane.Skills = append(jane.Skills, "physics", "golang")
fmt.Println("Her skills now are ", jane.Skills)
// modify embedded field
jane.int = 3
fmt.Println("Her preferred number is", jane.int)
}

View File

@@ -0,0 +1,24 @@
// Example code for Chapter 2.4 from "Build Web Application with Golang"
// Purpose: Shows a name conflict with a embedded field
package main
import "fmt"
type Human struct {
name string
age int
phone string // Human has phone field
}
type Employee struct {
Human // embedded field Human
speciality string
phone string // phone in employee
}
func main() {
Bob := Employee{Human{"Bob", 34, "777-444-XXXX"}, "Designer", "333-222"}
fmt.Println("Bob's work phone is:", Bob.phone)
// access phone field in Human
fmt.Println("Bob's personal phone is:", Bob.Human.phone)
}

View File

@@ -0,0 +1,39 @@
// Example code for Chapter 2.4 from "Build Web Application with Golang"
// Purpose: Shows different ways of creating a struct
package main
import "fmt"
func show_basic_struct() {
fmt.Println("\nshow_basic_struct()")
type person struct {
name string
age int
}
var P person // p is person type
P.name = "Astaxie" // assign "Astaxie" to the filed 'name' of p
P.age = 25 // assign 25 to field 'age' of p
fmt.Printf("The person's name is %s\n", P.name) // access field 'name' of p
tom := person{"Tom", 25}
bob := person{age: 24, name: "Bob"}
fmt.Printf("tom = %+v\n", tom)
fmt.Printf("bob = %#v\n", bob)
}
func show_anonymous_struct() {
fmt.Println("\nshow_anonymous_struct()")
fmt.Printf("Anonymous struct = %#v\n", struct {
name string
count int
}{
"counter", 1,
})
}
func main() {
show_basic_struct()
show_anonymous_struct()
}

View File

@@ -0,0 +1,36 @@
// Example code from Chapter 2.5
// Attach method to struct.
package main
import (
"fmt"
"math"
)
type Rectangle struct {
width, height float64
}
type Circle struct {
radius float64
}
func (r Rectangle) area() float64 {
return r.width * r.height
}
func (c Circle) area() float64 {
return c.radius * c.radius * math.Pi
}
func main() {
r1 := Rectangle{12, 2}
r2 := Rectangle{9, 4}
c1 := Circle{10}
c2 := Circle{25}
fmt.Println("Area of r1 is: ", r1.area())
fmt.Println("Area of r2 is: ", r2.area())
fmt.Println("Area of c1 is: ", c1.area())
fmt.Println("Area of c2 is: ", c2.area())
}

View File

@@ -0,0 +1,73 @@
package main
import "fmt"
const (
WHITE = iota
BLACK
BLUE
RED
YELLOW
)
type Color byte
type Box struct {
width, height, depth float64
color Color
}
type BoxList []Box //a slice of boxes
func (b Box) Volume() float64 {
return b.width * b.height * b.depth
}
func (b *Box) SetColor(c Color) {
b.color = c
}
func (bl BoxList) BiggestsColor() Color {
v := 0.00
k := Color(WHITE)
for _, b := range bl {
if b.Volume() > v {
v = b.Volume()
k = b.color
}
}
return k
}
func (bl BoxList) PaintItBlack() {
for i, _ := range bl {
bl[i].SetColor(BLACK)
}
}
func (c Color) String() string {
strings := []string{"WHITE", "BLACK", "BLUE", "RED", "YELLOW"}
return strings[c]
}
func main() {
boxes := BoxList{
Box{4, 4, 4, RED},
Box{10, 10, 1, YELLOW},
Box{1, 1, 20, BLACK},
Box{10, 10, 1, BLUE},
Box{10, 30, 1, WHITE},
Box{20, 20, 20, YELLOW},
}
fmt.Printf("We have %d boxes in our set\n", len(boxes))
fmt.Println("The volume of the first one is", boxes[0].Volume(), "cm³")
fmt.Println("The color of the last one is", boxes[len(boxes)-1].color.String())
fmt.Println("The biggest one is", boxes.BiggestsColor().String())
fmt.Println("Let's paint them all black")
boxes.PaintItBlack()
fmt.Println("The color of the second one is", boxes[1].color.String())
fmt.Println("Obviously, now, the biggest one is", boxes.BiggestsColor().String())
}

View File

@@ -0,0 +1,31 @@
package main
import "fmt"
type Human struct {
name string
age int
phone string
}
type Student struct {
Human // anonymous field
school string
}
type Employee struct {
Human
company string
}
// define a method in Human
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func main() {
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
mark.SayHi()
sam.SayHi()
}

View File

@@ -0,0 +1,36 @@
package main
import "fmt"
type Human struct {
name string
age int
phone string
}
type Student struct {
Human
school string
}
type Employee struct {
Human
company string
}
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func (e *Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone) //Yes you can split into 2 lines here.
}
func main() {
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
mark.SayHi()
sam.SayHi()
}

View File

@@ -0,0 +1,18 @@
package main
import "fmt"
type Rectangle struct {
width, height float64
}
func area(r Rectangle) float64 {
return r.width * r.height
}
func main() {
r1 := Rectangle{12, 2}
r2 := Rectangle{9, 4}
fmt.Println("Area of r1 is: ", area(r1))
fmt.Println("Area of r2 is: ", area(r2))
}

View File

@@ -0,0 +1,71 @@
package main
import "fmt"
type Human struct {
name string
age int
phone string
}
type Student struct {
Human
school string
loan float32
}
type Employee struct {
Human
company string
money float32
}
func (h Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func (h Human) Sing(lyrics string) {
fmt.Println("La la la la...", lyrics)
}
func (e Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone) //Yes you can split into 2 lines here.
}
// Interface Men implemented by Human, Student and Employee
type Men interface {
SayHi()
Sing(lyrics string)
}
func main() {
mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}
paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100}
sam := Employee{Human{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}
Tom := Employee{Human{"Sam", 36, "444-222-XXX"}, "Things Ltd.", 5000}
// define interface i
var i Men
//i can store Student
i = mike
fmt.Println("This is Mike, a Student:")
i.SayHi()
i.Sing("November rain")
//i can store Employee
i = Tom
fmt.Println("This is Tom, an Employee:")
i.SayHi()
i.Sing("Born to be wild")
// slice of Men
fmt.Println("Let's use a slice of Men and see what happens")
x := make([]Men, 3)
// these three elements are different types but they all implemented interface Men
x[0], x[1], x[2] = paul, sam, mike
for _, value := range x{
value.SayHi()
}
}

View File

@@ -0,0 +1,33 @@
package main
import (
"fmt"
"reflect"
)
func show_interface_none() {
fmt.Println("\nshow_interface_none()")
var a interface{}
a = "string"
a = 1
a = false
fmt.Println("a =", a)
}
func show_reflection() {
fmt.Println("\nshow_reflection()")
var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("type:", v.Type())
fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
fmt.Println("value:", v.Float())
p := reflect.ValueOf(&x)
newX := p.Elem()
newX.SetFloat(7.1)
fmt.Println("newX =", newX)
fmt.Println("newX float64() value:", newX.Float())
}
func main() {
show_interface_none()
show_reflection()
}

View File

@@ -0,0 +1,22 @@
package main
import (
"fmt"
"strconv"
)
type Human struct {
name string
age int
phone string
}
// Human implemented fmt.Stringer
func (h Human) String() string {
return "Name:" + h.name + ", Age:" + strconv.Itoa(h.age) + " years, Contact:" + h.phone
}
func main() {
Bob := Human{"Bob", 39, "000-7777-XXX"}
fmt.Println("This Human is : ", Bob)
}

View File

@@ -0,0 +1,38 @@
package main
import (
"fmt"
"strconv"
)
type Element interface{}
type List []Element
type Person struct {
name string
age int
}
func (p Person) String() string {
return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
}
func main() {
list := make(List, 3)
list[0] = 1 //an int
list[1] = "Hello" //a string
list[2] = Person{"Dennis", 70}
for index, element := range list {
switch value := element.(type) {
case int:
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
case string:
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
case Person:
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
default:
fmt.Println("list[%d] is of a different type", index)
}
}
}

View File

@@ -0,0 +1,37 @@
package main
import (
"fmt"
"strconv"
)
type Element interface{}
type List []Element
type Person struct {
name string
age int
}
func (p Person) String() string {
return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
}
func main() {
list := make(List, 3)
list[0] = 1 // an int
list[1] = "Hello" // a string
list[2] = Person{"Dennis", 70}
for index, element := range list {
if value, ok := element.(int); ok {
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
} else if value, ok := element.(string); ok {
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
} else if value, ok := element.(Person); ok {
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
} else {
fmt.Println("list[%d] is of a different type", index)
}
}
}

View File

@@ -0,0 +1,13 @@
// Example code for Chapter 2.7 from "Build Web Application with Golang"
// Purpose: Shows how to use a buffered channel
package main
import "fmt"
func main() {
c := make(chan int, 2) // change 2 to 1 will have runtime error, but 3 is fine
c <- 1
c <- 2
fmt.Println(<-c)
fmt.Println(<-c)
}

View File

@@ -0,0 +1,20 @@
// Example code for Chapter 2.7 from "Build Web Application with Golang"
// Purpose: Shows how to launch a simple gorountine
package main
import (
"fmt"
"runtime"
)
func say(s string) {
for i := 0; i < 5; i++ {
runtime.Gosched()
fmt.Println(s)
}
}
func main() {
go say("world") // create a new goroutine
say("hello") // current goroutine
}

View File

@@ -0,0 +1,24 @@
// Example code for Chapter 2.7 from "Build Web Application with Golang"
// Purpose: Shows how to close and interate through a channel
package main
import (
"fmt"
)
func fibonacci(n int, c chan int) {
x, y := 1, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c)
}
func main() {
c := make(chan int, 10)
go fibonacci(cap(c), c)
for i := range c {
fmt.Println(i)
}
}

View File

@@ -0,0 +1,30 @@
// Example code for Chapter 2.7 from "Build Web Application with Golang"
// Purpose: Shows how to use `select`
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 1, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}

View File

@@ -0,0 +1,27 @@
// Example code for Chapter 2.7 from "Build Web Application with Golang"
// Purpose: Shows how to create and use a timeout
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan int)
o := make(chan bool)
go func() {
for {
select {
case v := <-c:
fmt.Println(v)
case <-time.After(5 * time.Second):
fmt.Println("timeout")
o <- true
break
}
}
}()
<-o
}

View File

@@ -0,0 +1,24 @@
// Example code for Chapter 2.7 from "Build Web Application with Golang"
// Purpose: Shows how to create and use a unbuffered channel
package main
import "fmt"
func sum(a []int, c chan int) {
total := 0
for _, v := range a {
total += v
}
c <- total // send total to c
}
func main() {
a := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(a[:len(a)/2], c)
go sum(a[len(a)/2:], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
}

View File

@@ -0,0 +1,31 @@
// Example code for Chapter 3.2 from "Build Web Application with Golang"
// Purpose: Shows how to acces the form values from the request
package main
import (
"fmt"
"log"
"net/http"
"strings"
)
func sayhelloName(w http.ResponseWriter, r *http.Request) {
r.ParseForm() // parse arguments, you have to call this by yourself
fmt.Println(r.Form) // print form information in server side
fmt.Println("path", r.URL.Path)
fmt.Println("scheme", r.URL.Scheme)
fmt.Println(r.Form["url_long"])
for k, v := range r.Form {
fmt.Println("key:", k)
fmt.Println("val:", strings.Join(v, ""))
}
fmt.Fprintf(w, "Hello astaxie!") // send data to client side
}
func main() {
http.HandleFunc("/", sayhelloName) // set router
err := http.ListenAndServe(":9090", nil) // set listen port
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}

View File

@@ -0,0 +1,30 @@
// Example code for Chapter 3.4 from "Build Web Application with Golang"
// Purpose: Shows how to create a handler for `http.ListenAndServe()`
// Run `go run main.go` then access `http://localhost:9090`
package main
import (
"fmt"
"net/http"
)
type MyMux struct {
}
func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
sayhelloName(w, r)
return
}
http.NotFound(w, r)
return
}
func sayhelloName(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello myroute!")
}
func main() {
mux := &MyMux{}
http.ListenAndServe(":9090", mux)
}

View File

@@ -0,0 +1,12 @@
<html>
<head>
<title></title>
</head>
<body>
<form action="/login" method="post">
Username:<input type="text" name="username">
Password:<input type="password" name="password">
<input type="submit" value="Login">
</form>
</body>
</html>

View File

@@ -0,0 +1,48 @@
// Example code for Chapter 4.1 from "Build Web Application with Golang"
// Purpose: Shows how to create a simple login using a template
// Run: `go run main.go`, then access `http://localhost:9090` and `http://localhost:9090/login`
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"strings"
)
func sayhelloName(w http.ResponseWriter, r *http.Request) {
r.ParseForm() //Parse url parameters passed, then parse the response packet for the POST body (request body)
// attention: If you do not call ParseForm method, the following data can not be obtained form
fmt.Println(r.Form) // print information on server side.
fmt.Println("path", r.URL.Path)
fmt.Println("scheme", r.URL.Scheme)
fmt.Println(r.Form["url_long"])
for k, v := range r.Form {
fmt.Println("key:", k)
fmt.Println("val:", strings.Join(v, ""))
}
fmt.Fprintf(w, "Hello astaxie!") // write data to response
}
func login(w http.ResponseWriter, r *http.Request) {
fmt.Println("method:", r.Method) //get request method
if r.Method == "GET" {
t, _ := template.ParseFiles("login.gtpl")
t.Execute(w, nil)
} else {
r.ParseForm()
// logic part of log in
fmt.Println("username:", r.Form["username"])
fmt.Println("password:", r.Form["password"])
}
}
func main() {
http.HandleFunc("/", sayhelloName) // setting router rule
http.HandleFunc("/login", login)
err := http.ListenAndServe(":9090", nil) // setting listening port
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}

View File

@@ -0,0 +1,59 @@
// Example code for Chapter 4.2 from "Build Web Application with Golang"
// Purpose: Shows how to perform server-side validation of user input from a form.
// Also shows to use multiple template files with predefined template names.
// Run `go run main.go` and then access http://localhost:9090
package main
import (
"apps/ch.4.2/validator"
"html/template"
"log"
"net/http"
)
const (
PORT = "9090"
HOST_URL = "http://localhost:" + PORT
)
var t *template.Template
type Links struct {
BadLinks [][2]string
}
// invalid links to display for testing.
var links Links
func index(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, HOST_URL+"/profile", http.StatusTemporaryRedirect)
}
func profileHandler(w http.ResponseWriter, r *http.Request) {
t.ExecuteTemplate(w, "profile", links)
}
func checkProfile(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
p := validator.ProfilePage{&r.Form}
t.ExecuteTemplate(w, "submission", p.GetErrors())
}
// This function is called before main()
func init() {
// Note: we can reference the loaded templates by their defined name inside the template files.
t = template.Must(template.ParseFiles("profile.gtpl", "submission.gtpl"))
list := make([][2]string, 2)
list[0] = [2]string{HOST_URL + "/checkprofile", "No data"}
list[1] = [2]string{HOST_URL + "/checkprofile?age=1&gender=guy&shirtsize=big", "Invalid options"}
links = Links{list}
}
func main() {
http.HandleFunc("/", index)
http.HandleFunc("/profile", profileHandler)
http.HandleFunc("/checkprofile", checkProfile)
err := http.ListenAndServe(":"+PORT, nil) // setting listening port
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}

View File

@@ -0,0 +1,89 @@
{{define "profile"}}<!DOCTYPE html>
<html>
<style>
.row{
display: table-row;
}
.cell{
display: table-cell;
}
.required{
color: red
}
</style>
<body>
<h2>Profile Setup:</h2>
<form action="/checkprofile">
<div class="row">
<div class="cell"><span class="required">*</span>User Name:</div>
<div class="cell"><input type="text" name="username" id="username" required/></div>
</div>
<div class="row">
<div class="cell"><span class="required">*</span>Age:</div>
<div class="cell"><input type="number" min="13" max="130" name="age" id="age" size="3" required/></div>
</div>
<div class="row">
<div class="cell"><span class="required">*</span>Email:</div>
<div class="cell"><input type="email" name="email" id="email" placeholder="john@example.com" required/></div>
</div>
<div class="row">
<div class="cell"><span class="required">*</span>Birth day:</div>
<div class="cell">
<input type="date" name="birthday" id="birthday" placeholder="MM/DD/YYYY" required/>
</div>
</div>
<div class="row">
<div class="cell">Gender:</div>
<div class="cell">
<label for="gender_male">
Male: <input type="radio" name="gender" value="m" id="gender_male"/>
</label>
<label for="gender_female">
Female: <input type="radio" name="gender" value="f" id="gender_female"/>
</label>
<label for="gender_na">
N/A: <input type="radio" name="gender" value="na" id="gender_na"/>
</label>
</div>
</div>
<div class="row">
<div class="cell">Siblings:</div>
<div class="cell">
<label for="sibling_male">
Brother: <input type="checkbox" name="sibling" value="m" id="sibling_male"/>
</label>
<label for="sibling_female">
Sister: <input type="checkbox" name="sibling" value="f" id="sibling_female"/>
</label>
</div>
</div>
<div class="row">
<div class="cell">Shirt Size:</div>
<div class="cell">
<select id="shirt_size" >
<option></option>
<option value="s">Small</option>
<option value="m">Medium</option>
<option value="l">Large</option>
<option value="xl">X-Large</option>
<option value="xxl">XX-Large</option>
</select>
</div>
</div>
<div class="row">
<div class="cell">Chinese Name:</div>
<div class="cell"><input type="text" name="chineseName" id="chineseName"/></div>
</div>
<br/>
<span class="required">*</span>Required
<br/>
<input type="submit" value="Submit" id="submitBtn"/>
</form>
<h2>Invalid submissions</h2>
<ol>{{range .BadLinks}}
<li><a href="{{index . 0}}">{{index . 1}}</a></li>
{{end}}
</ol>
</body>
</html>
{{end}}

View File

@@ -0,0 +1,16 @@
{{define "submission"}}<!DOCTYPE html>
<html>
<body>
{{if .Errors}}
<h2>Errors:</h2>
<ol>
{{range .Errors}}
<li>{{.}}</li>
{{end}}
</ol>
{{else}}
Profile successfully submitted.
{{end}}
</body>
</html>
{{end}}

View File

@@ -0,0 +1,175 @@
// This file contains all the validators to validate the profile page.
package validator
import (
"errors"
"fmt"
"net/url"
"regexp"
"strconv"
"strings"
"time"
)
type ProfilePage struct {
Form *url.Values
}
type Errors struct {
Errors []error
}
// Goes through the form object and validates each element.
// Attachs an error to the output if validation fails.
func (p *ProfilePage) GetErrors() Errors {
errs := make([]error, 0, 10)
if *p.Form == nil || len(*p.Form) < 1 {
errs = append(errs, errors.New("No data was received. Please submit from the profile page."))
}
for name, val := range *p.Form {
if fn, ok := stringValidator[name]; ok {
if err := fn(strings.Join(val, "")); err != nil {
errs = append(errs, err)
}
} else {
if fn, ok := stringsValidator[name]; ok {
if err := fn(val); err != nil {
errs = append(errs, err)
}
}
}
}
return Errors{errs}
}
const (
// Used for parsing the time
mmddyyyyForm = "01/02/2006" // we want the date sent in this format
yyyymmddForm = "2006-01-02" // However, HTML5 pages send the date in this format
)
var stringValidator map[string]func(string) error = map[string]func(string) error{
// parameter name : validator reference
"age": checkAge,
"birthday": checkDate,
"chineseName": checkChineseName,
"email": checkEmail,
"gender": checkGender,
"shirtsize": checkShirtSize,
"username": checkUsername,
}
var stringsValidator map[string]func([]string) error = map[string]func([]string) error{
// parameter name : validator reference
"sibling": checkSibling,
}
// Returns true if slices have a common element
func doSlicesIntersect(s1, s2 []string) bool {
if s1 == nil || s2 == nil {
return false
}
for _, str := range s1 {
if isElementInSlice(str, s2) {
return true
}
}
return false
}
func isElementInSlice(str string, sl []string) bool {
if sl == nil || str == "" {
return false
}
for _, v := range sl {
if v == str {
return true
}
}
return false
}
// Checks if all the characters are chinese characters. Won't check if empty.'
func checkChineseName(str string) error {
if str != "" {
if m, _ := regexp.MatchString("^[\\x{4e00}-\\x{9fa5}]+$", strings.Trim(str, " ")); !m {
return errors.New("Please make sure that the chinese name only contains chinese characters.")
}
}
return nil
}
// Checks if a user name exist.
func checkUsername(str string) error {
if strings.Trim(str, " ") == "" {
return errors.New("Please enter a username.")
}
return nil
}
// Check if age is a number and between 13 and 130
func checkAge(str string) error {
age, err := strconv.Atoi(str)
if str == "" || err != nil {
return errors.New("Please enter a valid age.")
}
if age < 13 {
return errors.New("You must be at least 13 years of age to submit.")
}
if age > 130 {
return errors.New("You're too old to register, grandpa.")
}
return nil
}
func checkEmail(str string) error {
if m, err := regexp.MatchString(`^[^@]+@[^@]+$`, str); !m {
fmt.Println("err = ", err)
return errors.New("Please enter a valid email address.")
}
return nil
}
// Checks if a valid date was passed.
func checkDate(str string) error {
_, err := time.Parse(mmddyyyyForm, str)
if err != nil {
_, err = time.Parse(yyyymmddForm, str)
}
if str == "" || err != nil {
return errors.New("Please enter a valid Date.")
}
return nil
}
// Checks if the passed input is a known gender option
func checkGender(str string) error {
if str == "" {
return nil
}
siblings := []string{"m", "f", "na"}
if !isElementInSlice(str, siblings) {
return errors.New("Please select a valid gender.")
}
return nil
}
// Check if all the values are known options.
func checkSibling(strs []string) error {
if strs == nil || len(strs) < 1 {
return nil
}
siblings := []string{"m", "f"}
if siblings != nil && !doSlicesIntersect(siblings, strs) {
return errors.New("Please select a valid sibling")
}
return nil
}
// Checks if the shirt size is a known option.
func checkShirtSize(str string) error {
if str == "" {
return nil
}
shirts := []string{"s", "m", "l", "xl", "xxl"}
if !isElementInSlice(str, shirts) {
return errors.New("Please select a valid shirt size")
}
return nil
}

View File

@@ -0,0 +1,28 @@
<!doctype html>
<html>
<body>
<h2>Cross Site Scripting Attack Test</h2>
{{if .}}
Previous User Input: <br/>
<code><pre>{{.}}</pre></code>
{{end}}
<form action="/">
<label>
User Input:
<input type="text" size=50 name="userinput" id="userinput"/>
</label>
<br/>
<label>
Escape Input:
<input type="checkbox" value="1" name="escape" id="escape"/>
</label>
<br/>
<input type="submit" id="submitBtn" value="Submit"/>
</form>
<script type="text/javascript">
var s = "<scri"+"pt>alert('pOwned by XSS.')</scri"+"pt>"
document.getElementById("userinput").value = s;
</script>
</body>
</html>

View File

@@ -0,0 +1,39 @@
// Example code for Chapter 4.3 from "Build Web Application with Golang"
// Purpose: Shows how to properly escape input
package main
import (
"html/template"
"net/http"
textTemplate "text/template"
)
var t *template.Template = template.Must(template.ParseFiles("index.gtpl"))
func index(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
userInput := r.Form.Get("userinput")
if 0 < len(r.Form.Get("escape")) {
t.Execute(w, template.HTMLEscapeString(userInput))
} else {
// Variables with type `template.HTML` are not escaped when passed to `.Execute()`
t.Execute(w, template.HTML(userInput))
}
}
func templateHandler(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
userInput := r.Form.Get("userinput")
if 0 < len(r.Form.Get("escape")) {
// `html/template.Execute()` escapes input
t.Execute(w, userInput)
} else {
tt := textTemplate.Must(textTemplate.ParseFiles("index.gtpl"))
// `text/template.Execute()` doesn't escape input
tt.Execute(w, userInput)
}
}
func main() {
http.HandleFunc("/", index)
http.HandleFunc("/template", templateHandler)
http.ListenAndServe(":9090", nil)
}

View File

@@ -0,0 +1,54 @@
// Example code for Chapter 3.2 from "Build Web Application with Golang"
// Purpose: Shows how to prevent duplicate submissions by using tokens
// Example code for Chapter 4.4 based off the code from Chapter 4.2
// Run `go run main.go` then access http://localhost:9090
package main
import (
"apps/ch.4.4/nonce"
"apps/ch.4.4/validator"
"html/template"
"log"
"net/http"
)
const (
PORT = "9090"
HOST_URL = "http://localhost:" + PORT
)
var submissions nonce.Nonces
var t *template.Template
func index(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, HOST_URL+"/profile", http.StatusTemporaryRedirect)
}
func profileHandler(w http.ResponseWriter, r *http.Request) {
t.ExecuteTemplate(w, "profile", submissions.NewNonce())
}
func checkProfile(w http.ResponseWriter, r *http.Request) {
var errs validator.Errors
r.ParseForm()
token := r.Form.Get("token")
if err := submissions.CheckThenMarkToken(token); err != nil {
errs = validator.Errors{[]error{err}}
} else {
p := validator.ProfilePage{&r.Form}
errs = p.GetErrors()
}
t.ExecuteTemplate(w, "submission", errs)
}
func init() {
submissions = nonce.New()
t = template.Must(template.ParseFiles("profile.gtpl", "submission.gtpl"))
}
func main() {
http.HandleFunc("/", index)
http.HandleFunc("/profile", profileHandler)
http.HandleFunc("/checkprofile", checkProfile)
err := http.ListenAndServe(":"+PORT, nil) // setting listening port
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}

View File

@@ -0,0 +1,70 @@
// A nonce is a number or string used only once.
// This is useful for generating a unique token for login pages to prevent duplicate submissions.
package nonce
import (
"crypto/md5"
"errors"
"fmt"
"io"
"math/rand"
"strconv"
"time"
)
// Contains a unique token
type Nonce struct {
Token string
}
// Keeps track of marked/used tokens
type Nonces struct {
hashs map[string]bool
}
func New() Nonces {
return Nonces{make(map[string]bool)}
}
func (n *Nonces) NewNonce() Nonce {
return Nonce{n.NewToken()}
}
// Returns a new unique token
func (n *Nonces) NewToken() string {
t := createToken()
for n.HasToken(t) {
t = createToken()
}
return t
}
// Checks if token has been marked.
func (n *Nonces) HasToken(token string) bool {
return n.hashs[token] == true
}
func (n *Nonces) MarkToken(token string) {
n.hashs[token] = true
}
func (n *Nonces) CheckToken(token string) error {
if token == "" {
return errors.New("No token supplied")
}
if n.HasToken(token) {
return errors.New("Duplicate submission.")
}
return nil
}
func (n *Nonces) CheckThenMarkToken(token string) error {
defer n.MarkToken(token)
if err := n.CheckToken(token); err != nil {
return err
}
return nil
}
func createToken() string {
h := md5.New()
now := time.Now().Unix()
io.WriteString(h, strconv.FormatInt(now, 10))
io.WriteString(h, strconv.FormatInt(rand.Int63(), 10))
return fmt.Sprintf("%x", h.Sum(nil))
}

View File

@@ -0,0 +1,85 @@
{{define "profile"}}<!DOCTYPE html>
<html>
<style>
.row{
display: table-row;
}
.cell{
display: table-cell;
}
.required{
color: red
}
</style>
<body>
<h2>Profile Setup:</h2>
<form action="/checkprofile" method="POST">
<div class="row">
<div class="cell"><span class="required">*</span>User Name:</div>
<div class="cell"><input type="text" name="username" id="username" required/></div>
</div>
<div class="row">
<div class="cell"><span class="required">*</span>Age:</div>
<div class="cell"><input type="number" min="13" max="130" name="age" id="age" size="3" required/></div>
</div>
<div class="row">
<div class="cell"><span class="required">*</span>Email:</div>
<div class="cell"><input type="email" name="email" id="email" placeholder="john@example.com" required/></div>
</div>
<div class="row">
<div class="cell"><span class="required">*</span>Birth day:</div>
<div class="cell">
<input type="date" name="birthday" id="birthday" placeholder="MM/DD/YYYY" required/>
</div>
</div>
<div class="row">
<div class="cell">Gender:</div>
<div class="cell">
<label for="gender_male">
Male: <input type="radio" name="gender" value="m" id="gender_male"/>
</label>
<label for="gender_female">
Female: <input type="radio" name="gender" value="f" id="gender_female"/>
</label>
<label for="gender_na">
N/A: <input type="radio" name="gender" value="na" id="gender_na"/>
</label>
</div>
</div>
<div class="row">
<div class="cell">Siblings:</div>
<div class="cell">
<label for="sibling_male">
Brother: <input type="checkbox" name="sibling" value="m" id="sibling_male"/>
</label>
<label for="sibling_female">
Sister: <input type="checkbox" name="sibling" value="f" id="sibling_female"/>
</label>
</div>
</div>
<div class="row">
<div class="cell">Shirt Size:</div>
<div class="cell">
<select id="shirt_size" >
<option></option>
<option value="s">Small</option>
<option value="m">Medium</option>
<option value="l">Large</option>
<option value="xl">X-Large</option>
<option value="xxl">XX-Large</option>
</select>
</div>
</div>
<div class="row">
<div class="cell">Chinese Name:</div>
<div class="cell"><input type="text" name="chineseName" id="chineseName"/></div>
</div>
<br/>
<span class="required">*</span>Required
<br/>
<input type="hidden" name="token" value="{{.Token}}"/>
<input type="submit" value="Submit" id="submitBtn"/>
</form>
</body>
</html>
{{end}}

View File

@@ -0,0 +1,17 @@
{{define "submission"}}<!DOCTYPE html>
<html>
<body>
{{if .Errors}}
<h2>Errors:</h2>
<ol>
{{range .Errors}}
<li>{{.}}</li>
{{end}}
</ol>
{{else}}
Profile successfully submitted.<br/>
Note: Refreshing the page will produce a duplicate entry.
{{end}}
</body>
</html>
{{end}}

View File

@@ -0,0 +1,175 @@
// This file contains all the validators to validate the profile page.
package validator
import (
"errors"
"fmt"
"net/url"
"regexp"
"strconv"
"strings"
"time"
)
type ProfilePage struct {
Form *url.Values
}
type Errors struct {
Errors []error
}
// Goes through the form object and validates each element.
// Attachs an error to the output if validation fails.
func (p *ProfilePage) GetErrors() Errors {
errs := make([]error, 0, 10)
if *p.Form == nil || len(*p.Form) < 1 {
errs = append(errs, errors.New("No data was received. Please submit from the profile page."))
}
for name, val := range *p.Form {
if fn, ok := stringValidator[name]; ok {
if err := fn(strings.Join(val, "")); err != nil {
errs = append(errs, err)
}
} else {
if fn, ok := stringsValidator[name]; ok {
if err := fn(val); err != nil {
errs = append(errs, err)
}
}
}
}
return Errors{errs}
}
const (
// Used for parsing the time
mmddyyyyForm = "01/02/2006" // we want the date sent in this format
yyyymmddForm = "2006-01-02" // However, HTML5 pages send the date in this format
)
var stringValidator map[string]func(string) error = map[string]func(string) error{
// parameter name : validator reference
"age": checkAge,
"birthday": checkDate,
"chineseName": checkChineseName,
"email": checkEmail,
"gender": checkGender,
"shirtsize": checkShirtSize,
"username": checkUsername,
}
var stringsValidator map[string]func([]string) error = map[string]func([]string) error{
// parameter name : validator reference
"sibling": checkSibling,
}
// Returns true if slices have a common element
func doSlicesIntersect(s1, s2 []string) bool {
if s1 == nil || s2 == nil {
return false
}
for _, str := range s1 {
if isElementInSlice(str, s2) {
return true
}
}
return false
}
func isElementInSlice(str string, sl []string) bool {
if sl == nil || str == "" {
return false
}
for _, v := range sl {
if v == str {
return true
}
}
return false
}
// Checks if all the characters are chinese characters. Won't check if empty.'
func checkChineseName(str string) error {
if str != "" {
if m, _ := regexp.MatchString("^[\\x{4e00}-\\x{9fa5}]+$", strings.Trim(str, " ")); !m {
return errors.New("Please make sure that the chinese name only contains chinese characters.")
}
}
return nil
}
// Checks if a user name exist.
func checkUsername(str string) error {
if strings.Trim(str, " ") == "" {
return errors.New("Please enter a username.")
}
return nil
}
// Check if age is a number and between 13 and 130
func checkAge(str string) error {
age, err := strconv.Atoi(str)
if str == "" || err != nil {
return errors.New("Please enter a valid age.")
}
if age < 13 {
return errors.New("You must be at least 13 years of age to submit.")
}
if age > 130 {
return errors.New("You're too old to register, grandpa.")
}
return nil
}
func checkEmail(str string) error {
if m, err := regexp.MatchString(`^[^@]+@[^@]+$`, str); !m {
fmt.Println("err = ", err)
return errors.New("Please enter a valid email address.")
}
return nil
}
// Checks if a valid date was passed.
func checkDate(str string) error {
_, err := time.Parse(mmddyyyyForm, str)
if err != nil {
_, err = time.Parse(yyyymmddForm, str)
}
if str == "" || err != nil {
return errors.New("Please enter a valid Date.")
}
return nil
}
// Checks if the passed input is a known gender option
func checkGender(str string) error {
if str == "" {
return nil
}
siblings := []string{"m", "f", "na"}
if !isElementInSlice(str, siblings) {
return errors.New("Please select a valid gender.")
}
return nil
}
// Check if all the values are known options.
func checkSibling(strs []string) error {
if strs == nil || len(strs) < 1 {
return nil
}
siblings := []string{"m", "f"}
if siblings != nil && !doSlicesIntersect(siblings, strs) {
return errors.New("Please select a valid sibling")
}
return nil
}
// Checks if the shirt size is a known option.
func checkShirtSize(str string) error {
if str == "" {
return nil
}
shirts := []string{"s", "m", "l", "xl", "xxl"}
if !isElementInSlice(str, shirts) {
return errors.New("Please select a valid shirt size")
}
return nil
}

View File

@@ -0,0 +1,46 @@
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
)
func checkError(err error) {
if err != nil {
panic(err)
}
}
func postFile(filename string, targetUrl string) {
bodyBuf := &bytes.Buffer{}
bodyWriter := multipart.NewWriter(bodyBuf)
fileWriter, err := bodyWriter.CreateFormFile("uploadfile", filename)
checkError(err)
fh, err := os.Open(filename)
checkError(err)
_, err = io.Copy(fileWriter, fh)
checkError(err)
contentType := bodyWriter.FormDataContentType()
bodyWriter.Close()
resp, err := http.Post(targetUrl, contentType, bodyBuf)
checkError(err)
defer resp.Body.Close()
resp_body, err := ioutil.ReadAll(resp.Body)
checkError(err)
fmt.Println(resp.Status)
fmt.Println(string(resp_body))
}
func main() {
target_url := "http://localhost:9090/upload"
filename := "../file.txt"
postFile(filename, target_url)
}

View File

@@ -0,0 +1,15 @@
{{define "index"}}
<!doctype html>
<html>
<head>
<title>Upload file</title>
</head>
<body>
<form enctype="multipart/form-data" action="http://127.0.0.1:9090/upload" method="post">
<input type="file" name="uploadfile" />
<input type="hidden" name="token" value="{{.}}"/>
<input type="submit" value="upload" />
</form>
</body>
</html>
{{end}}

View File

@@ -0,0 +1,64 @@
// Example code for Chapter 4.5
// Purpose is to create a server to handle uploading files.
package main
import (
"apps/ch.4.4/nonce"
"apps/ch.4.4/validator"
"fmt"
"html/template"
"io"
"mime/multipart"
"net/http"
"os"
)
const MiB_UNIT = 1 << 20
var t *template.Template
var submissions nonce.Nonces = nonce.New()
func checkError(err error) {
if err != nil {
panic(err)
}
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
err := t.ExecuteTemplate(w, "index", submissions.NewToken())
checkError(err)
}
func uploadHandler(w http.ResponseWriter, r *http.Request) {
var errs validator.Errors
r.ParseMultipartForm(32 * MiB_UNIT)
token := r.Form.Get("token")
if err := submissions.CheckThenMarkToken(token); err != nil {
errs = validator.Errors{[]error{err}}
} else {
file, handler, err := r.FormFile("uploadfile")
checkError(err)
saveUpload(file, handler)
}
err := t.ExecuteTemplate(w, "upload", errs)
checkError(err)
}
func saveUpload(file multipart.File, handler *multipart.FileHeader) {
defer file.Close()
fmt.Printf("Uploaded file info: %#v", handler.Header)
localFilename := fmt.Sprintf("./uploads/%v.%v", handler.Filename, submissions.NewToken())
f, err := os.OpenFile(localFilename, os.O_WRONLY|os.O_CREATE, 0666)
checkError(err)
defer f.Close()
_, err = io.Copy(f, file)
checkError(err)
}
func init() {
var err error
t, err = template.ParseFiles("index.gtpl", "upload.gtpl")
checkError(err)
}
func main() {
http.HandleFunc("/", indexHandler)
http.HandleFunc("/upload", uploadHandler)
err := http.ListenAndServe(":9090", nil)
checkError(err)
}

View File

@@ -0,0 +1,70 @@
// A nonce is a number or string used only once.
// This is useful for generating a unique token for login pages to prevent duplicate submissions.
package nonce
import (
"crypto/md5"
"errors"
"fmt"
"io"
"math/rand"
"strconv"
"time"
)
// Contains a unique token
type Nonce struct {
Token string
}
// Keeps track of marked/used tokens
type Nonces struct {
hashs map[string]bool
}
func New() Nonces {
return Nonces{make(map[string]bool)}
}
func (n *Nonces) NewNonce() Nonce {
return Nonce{n.NewToken()}
}
// Returns a new unique token
func (n *Nonces) NewToken() string {
t := createToken()
for n.HasToken(t) {
t = createToken()
}
return t
}
// Checks if token has been marked.
func (n *Nonces) HasToken(token string) bool {
return n.hashs[token] == true
}
func (n *Nonces) MarkToken(token string) {
n.hashs[token] = true
}
func (n *Nonces) CheckToken(token string) error {
if token == "" {
return errors.New("No token supplied")
}
if n.HasToken(token) {
return errors.New("Duplicate submission.")
}
return nil
}
func (n *Nonces) CheckThenMarkToken(token string) error {
defer n.MarkToken(token)
if err := n.CheckToken(token); err != nil {
return err
}
return nil
}
func createToken() string {
h := md5.New()
now := time.Now().Unix()
io.WriteString(h, strconv.FormatInt(now, 10))
io.WriteString(h, strconv.FormatInt(rand.Int63(), 10))
return fmt.Sprintf("%x", h.Sum(nil))
}

View File

@@ -0,0 +1,17 @@
{{define "upload"}}<!DOCTYPE html>
<html>
<body>
{{if .Errors}}
<h2>Errors:</h2>
<ol>
{{range .Errors}}
<li>{{.}}</li>
{{end}}
</ol>
{{else}}
File uploaded successfully.<br/>
Note: Refreshing the page will produce a duplicate entry.
{{end}}
</body>
</html>
{{end}}

View File

@@ -0,0 +1,175 @@
// This file contains all the validators to validate the profile page.
package validator
import (
"errors"
"fmt"
"net/url"
"regexp"
"strconv"
"strings"
"time"
)
type ProfilePage struct {
Form *url.Values
}
type Errors struct {
Errors []error
}
// Goes through the form object and validates each element.
// Attachs an error to the output if validation fails.
func (p *ProfilePage) GetErrors() Errors {
errs := make([]error, 0, 10)
if *p.Form == nil || len(*p.Form) < 1 {
errs = append(errs, errors.New("No data was received. Please submit from the profile page."))
}
for name, val := range *p.Form {
if fn, ok := stringValidator[name]; ok {
if err := fn(strings.Join(val, "")); err != nil {
errs = append(errs, err)
}
} else {
if fn, ok := stringsValidator[name]; ok {
if err := fn(val); err != nil {
errs = append(errs, err)
}
}
}
}
return Errors{errs}
}
const (
// Used for parsing the time
mmddyyyyForm = "01/02/2006" // we want the date sent in this format
yyyymmddForm = "2006-01-02" // However, HTML5 pages send the date in this format
)
var stringValidator map[string]func(string) error = map[string]func(string) error{
// parameter name : validator reference
"age": checkAge,
"birthday": checkDate,
"chineseName": checkChineseName,
"email": checkEmail,
"gender": checkGender,
"shirtsize": checkShirtSize,
"username": checkUsername,
}
var stringsValidator map[string]func([]string) error = map[string]func([]string) error{
// parameter name : validator reference
"sibling": checkSibling,
}
// Returns true if slices have a common element
func doSlicesIntersect(s1, s2 []string) bool {
if s1 == nil || s2 == nil {
return false
}
for _, str := range s1 {
if isElementInSlice(str, s2) {
return true
}
}
return false
}
func isElementInSlice(str string, sl []string) bool {
if sl == nil || str == "" {
return false
}
for _, v := range sl {
if v == str {
return true
}
}
return false
}
// Checks if all the characters are chinese characters. Won't check if empty.'
func checkChineseName(str string) error {
if str != "" {
if m, _ := regexp.MatchString("^[\\x{4e00}-\\x{9fa5}]+$", strings.Trim(str, " ")); !m {
return errors.New("Please make sure that the chinese name only contains chinese characters.")
}
}
return nil
}
// Checks if a user name exist.
func checkUsername(str string) error {
if strings.Trim(str, " ") == "" {
return errors.New("Please enter a username.")
}
return nil
}
// Check if age is a number and between 13 and 130
func checkAge(str string) error {
age, err := strconv.Atoi(str)
if str == "" || err != nil {
return errors.New("Please enter a valid age.")
}
if age < 13 {
return errors.New("You must be at least 13 years of age to submit.")
}
if age > 130 {
return errors.New("You're too old to register, grandpa.")
}
return nil
}
func checkEmail(str string) error {
if m, err := regexp.MatchString(`^[^@]+@[^@]+$`, str); !m {
fmt.Println("err = ", err)
return errors.New("Please enter a valid email address.")
}
return nil
}
// Checks if a valid date was passed.
func checkDate(str string) error {
_, err := time.Parse(mmddyyyyForm, str)
if err != nil {
_, err = time.Parse(yyyymmddForm, str)
}
if str == "" || err != nil {
return errors.New("Please enter a valid Date.")
}
return nil
}
// Checks if the passed input is a known gender option
func checkGender(str string) error {
if str == "" {
return nil
}
siblings := []string{"m", "f", "na"}
if !isElementInSlice(str, siblings) {
return errors.New("Please select a valid gender.")
}
return nil
}
// Check if all the values are known options.
func checkSibling(strs []string) error {
if strs == nil || len(strs) < 1 {
return nil
}
siblings := []string{"m", "f"}
if siblings != nil && !doSlicesIntersect(siblings, strs) {
return errors.New("Please select a valid sibling")
}
return nil
}
// Checks if the shirt size is a known option.
func checkShirtSize(str string) error {
if str == "" {
return nil
}
shirts := []string{"s", "m", "l", "xl", "xxl"}
if !isElementInSlice(str, shirts) {
return errors.New("Please select a valid shirt size")
}
return nil
}

View File

@@ -0,0 +1,76 @@
// Example code for Chapter 5.2 from "Build Web Application with Golang"
// Purpose: Use SQL driver to perform simple CRUD operations.
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
const (
DB_USER = "user"
DB_PASSWORD = ""
DB_NAME = "test"
)
func main() {
dbSouce := fmt.Sprintf("%v:%v@/%v?charset=utf8", DB_USER, DB_PASSWORD, DB_NAME)
db, err := sql.Open("mysql", dbSouce)
checkErr(err)
defer db.Close()
fmt.Println("Inserting")
stmt, err := db.Prepare("INSERT userinfo SET username=?,departname=?,created=?")
checkErr(err)
res, err := stmt.Exec("astaxie", "software developement", "2012-12-09")
checkErr(err)
id, err := res.LastInsertId()
checkErr(err)
fmt.Println("id of last inserted row =", id)
fmt.Println("Updating")
stmt, err = db.Prepare("update userinfo set username=? where uid=?")
checkErr(err)
res, err = stmt.Exec("astaxieupdate", id)
checkErr(err)
affect, err := res.RowsAffected()
checkErr(err)
fmt.Println(affect, "row(s) changed")
fmt.Println("Querying")
rows, err := db.Query("SELECT * FROM userinfo")
checkErr(err)
for rows.Next() {
var uid int
var username, department, created string
err = rows.Scan(&uid, &username, &department, &created)
checkErr(err)
fmt.Println("uid | username | department | created")
fmt.Printf("%3v | %6v | %6v | %6v\n", uid, username, department, created)
}
fmt.Println("Deleting")
stmt, err = db.Prepare("delete from userinfo where uid=?")
checkErr(err)
res, err = stmt.Exec(id)
checkErr(err)
affect, err = res.RowsAffected()
checkErr(err)
fmt.Println(affect, "row(s) changed")
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}

View File

@@ -0,0 +1,12 @@
## Setup for `ch.5.2`
- Step 1) Install and run MySql
- Step 2) Create a user and database according to the constants in `main.go`
DB_USER = "user"
DB_PASSWORD = ""
DB_NAME = "test"
- Step 3) Create table `userinfo` located at `schema.sql`
- Step 4) Run `go get` to download and install the remote packages.
- Step 5) Execute the program with `go run main.go`

View File

@@ -0,0 +1,7 @@
CREATE TABLE `userinfo` (
`uid` INT(10) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(64) NULL DEFAULT NULL,
`departname` VARCHAR(64) NULL DEFAULT NULL,
`created` DATE NULL DEFAULT NULL,
PRIMARY KEY (`uid`)
);

Binary file not shown.

View File

@@ -0,0 +1,72 @@
// Example code for Chapter 5.3 from "Build Web Application with Golang"
// Purpose: Shows how to run simple CRUD operations using a sqlite driver
package main
import (
"database/sql"
"fmt"
_ "github.com/mattn/go-sqlite3"
"time"
)
const DB_PATH = "./foo.db"
func main() {
db, err := sql.Open("sqlite3", DB_PATH)
checkErr(err)
defer db.Close()
fmt.Println("Inserting")
stmt, err := db.Prepare("INSERT INTO userinfo(username, department, created) values(?,?,?)")
checkErr(err)
res, err := stmt.Exec("astaxie", "software developement", time.Now().Format("2006-01-02"))
checkErr(err)
id, err := res.LastInsertId()
checkErr(err)
fmt.Println("id of last inserted row =", id)
fmt.Println("Updating")
stmt, err = db.Prepare("update userinfo set username=? where uid=?")
checkErr(err)
res, err = stmt.Exec("astaxieupdate", id)
checkErr(err)
affect, err := res.RowsAffected()
checkErr(err)
fmt.Println(affect, "row(s) changed")
fmt.Println("Querying")
rows, err := db.Query("SELECT * FROM userinfo")
checkErr(err)
for rows.Next() {
var uid int
var username, department, created string
err = rows.Scan(&uid, &username, &department, &created)
checkErr(err)
fmt.Println("uid | username | department | created")
fmt.Printf("%3v | %6v | %8v | %6v\n", uid, username, department, created)
}
fmt.Println("Deleting")
stmt, err = db.Prepare("delete from userinfo where uid=?")
checkErr(err)
res, err = stmt.Exec(id)
checkErr(err)
affect, err = res.RowsAffected()
checkErr(err)
fmt.Println(affect, "row(s) changed")
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}

View File

@@ -0,0 +1,23 @@
## Set up for `ch.5.3`
- Step 1) Download and install sqlite 3.
- Step 2) Run `sqlite3 foo.db` to create a databased called `foo`.
- Step 3) Create the `userinfo` table in sqlite using `schema.sql`.
Read and run sql statements
sqlite> .read schema.sql
Show tables
sqlite> .tables
userinfo
- Step 4) Exit sqlite.
sqlite> .exit
- Step 5) Run `go get` to download and install remote packages.
- Step 6) Run the program with `go run main.go`

View File

@@ -0,0 +1,6 @@
CREATE TABLE `userinfo` (
`uid` INTEGER PRIMARY KEY AUTOINCREMENT,
`username` VARCHAR(64) NULL,
`department` VARCHAR(64) NULL,
`created` DATE NULL
);

View File

@@ -0,0 +1,78 @@
// Example code for Chapter 5.4 from "Build Web Application with Golang"
// Purpose: Show how to perform CRUD operations using a postgres driver
package main
import (
"database/sql"
"fmt"
"time"
_ "github.com/lib/pq"
)
const (
DB_USER = "user"
DB_PASSWORD = ""
DB_NAME = "test"
)
func main() {
dbinfo := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable",
DB_USER, DB_PASSWORD, DB_NAME)
db, err := sql.Open("postgres", dbinfo)
checkErr(err)
defer db.Close()
fmt.Println("# Inserting values")
var lastInsertId int
err = db.QueryRow("INSERT INTO userinfo(username,departname,created) VALUES($1,$2,$3) returning uid;",
"astaxie", "software developement", "2012-12-09").Scan(&lastInsertId)
checkErr(err)
fmt.Println("id of last inserted row =", lastInsertId)
fmt.Println("# Updating")
stmt, err := db.Prepare("update userinfo set username=$1 where uid=$2")
checkErr(err)
res, err := stmt.Exec("astaxieupdate", lastInsertId)
checkErr(err)
affect, err := res.RowsAffected()
checkErr(err)
fmt.Println(affect, "row(s) changed")
fmt.Println("# Querying")
rows, err := db.Query("SELECT * FROM userinfo")
checkErr(err)
for rows.Next() {
var uid int
var username string
var department string
var created time.Time
err = rows.Scan(&uid, &username, &department, &created)
checkErr(err)
fmt.Println("uid | username | department | created ")
fmt.Printf("%3v | %8v | %6v | %6v\n", uid, username, department, created)
}
fmt.Println("# Deleting")
stmt, err = db.Prepare("delete from userinfo where uid=$1")
checkErr(err)
res, err = stmt.Exec(lastInsertId)
checkErr(err)
affect, err = res.RowsAffected()
checkErr(err)
fmt.Println(affect, "row(s) changed")
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}

View File

@@ -0,0 +1,12 @@
## Setup for ch.5.4
- Step 1) Install and run Postgres
- Step 2) Create a user and database according to the constants in `main.go`
DB_USER = "user"
DB_PASSWORD = ""
DB_NAME = "test"
- Step 3) Create table `userinfo` located at `schema.sql`
- Step 4) Run `go get` to download and install the remote packages.
- Step 5) Execute the program with `go run main.go`

View File

@@ -0,0 +1,9 @@
CREATE TABLE userinfo
(
uid serial NOT NULL,
username character varying(100) NOT NULL,
departname character varying(500) NOT NULL,
Created date,
CONSTRAINT userinfo_pkey PRIMARY KEY (uid)
)
WITH (OIDS=FALSE);

View File

@@ -0,0 +1,170 @@
// Example code for Chapter 5.5
// Purpose is to show to use BeeDB ORM for basic CRUD operations for sqlite3
package main
import (
"database/sql"
"fmt"
"github.com/astaxie/beedb"
_ "github.com/mattn/go-sqlite3"
"time"
)
var orm beedb.Model
type Userinfo struct {
Uid int `beedb:"PK"`
Username string
Department string
Created string
}
const DB_PATH = "./foo.db"
func checkError(err error) {
if err != nil {
panic(err)
}
}
func getTimeStamp() string {
return time.Now().Format("2006-01-02 15:04:05")
}
func insertUsingStruct() int64 {
fmt.Println("insertUsingStruct()")
var obj Userinfo
obj.Username = "Test Add User"
obj.Department = "Test Add Department"
obj.Created = getTimeStamp()
checkError(orm.Save(&obj))
fmt.Printf("%+v\n", obj)
return int64(obj.Uid)
}
func insertUsingMap() int64 {
fmt.Println("insertUsingMap()")
add := make(map[string]interface{})
add["username"] = "astaxie"
add["department"] = "cloud develop"
add["created"] = getTimeStamp()
id, err := orm.SetTable("userinfo").Insert(add)
checkError(err)
fmt.Println("Last row inserted id =", id)
return id
}
func getOneUserInfo(id int64) Userinfo {
fmt.Println("getOneUserInfo()")
var obj Userinfo
checkError(orm.Where("uid=?", id).Find(&obj))
return obj
}
func getAllUserInfo(id int64) []Userinfo {
fmt.Println("getAllUserInfo()")
var alluser []Userinfo
checkError(orm.Limit(10).Where("uid>?", id).FindAll(&alluser))
return alluser
}
func updateUserinfo(id int64) {
fmt.Println("updateUserinfo()")
var obj Userinfo
obj.Uid = int(id)
obj.Username = "Update Username"
obj.Department = "Update Department"
obj.Created = getTimeStamp()
checkError(orm.Save(&obj))
fmt.Printf("%+v\n", obj)
}
func updateUsingMap(id int64) {
fmt.Println("updateUsingMap()")
t := make(map[string]interface{})
t["username"] = "updateastaxie"
//update one
// id, err := orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t)
//update batch
lastId, err := orm.SetTable("userinfo").Where("uid>?", id).Update(t)
checkError(err)
fmt.Println("Last row updated id =", lastId)
}
func getMapsFromSelect(id int64) []map[string][]byte {
fmt.Println("getMapsFromSelect()")
//Original SQL Backinfo resultsSlice []map[string][]byte
//default PrimaryKey id
c, err := orm.SetTable("userinfo").SetPK("uid").Where(id).Select("uid,username").FindMap()
checkError(err)
fmt.Printf("%+v\n", c)
return c
}
func groupby() {
fmt.Println("groupby()")
//Original SQL Group By
b, err := orm.SetTable("userinfo").GroupBy("username").Having("username='updateastaxie'").FindMap()
checkError(err)
fmt.Printf("%+v\n", b)
}
func joinTables(id int64) {
fmt.Println("joinTables()")
//Original SQL Join Table
a, err := orm.SetTable("userinfo").Join("LEFT", "userdetail", "userinfo.uid=userdetail.uid").Where("userinfo.uid=?", id).Select("userinfo.uid,userinfo.username,userdetail.profile").FindMap()
checkError(err)
fmt.Printf("%+v\n", a)
}
func deleteWithUserinfo(id int64) {
fmt.Println("deleteWithUserinfo()")
obj := getOneUserInfo(id)
id, err := orm.Delete(&obj)
checkError(err)
fmt.Println("Last row deleted id =", id)
}
func deleteRows() {
fmt.Println("deleteRows()")
//original SQL delete
id, err := orm.SetTable("userinfo").Where("uid>?", 2).DeleteRow()
checkError(err)
fmt.Println("Last row updated id =", id)
}
func deleteAllUserinfo(id int64) {
fmt.Println("deleteAllUserinfo()")
//delete all data
alluser := getAllUserInfo(id)
id, err := orm.DeleteAll(&alluser)
checkError(err)
fmt.Println("Last row updated id =", id)
}
func main() {
db, err := sql.Open("sqlite3", DB_PATH)
checkError(err)
orm = beedb.New(db)
var lastIdInserted int64
fmt.Println("Inserting")
lastIdInserted = insertUsingStruct()
insertUsingMap()
a := getOneUserInfo(lastIdInserted)
fmt.Println(a)
b := getAllUserInfo(lastIdInserted)
fmt.Println(b)
fmt.Println("Updating")
updateUserinfo(lastIdInserted)
updateUsingMap(lastIdInserted)
fmt.Println("Querying")
getMapsFromSelect(lastIdInserted)
groupby()
joinTables(lastIdInserted)
fmt.Println("Deleting")
deleteWithUserinfo(lastIdInserted)
deleteRows()
deleteAllUserinfo(lastIdInserted)
}

View File

@@ -0,0 +1,23 @@
## Set up for `ch.5.5`
- Step 1) Download and install sqlite 3.
- Step 2) Run `sqlite3 foo.db` to create a databased called `foo`.
- Step 3) Create the tables found in `schema.sql` in sqlite.
Read and run sql statements
sqlite> .read schema.sql
Show tables
sqlite> .tables
userinfo
userdetail
- Step 4) Exit sqlite.
sqlite> .exit
- Step 5) Run `go get` to download and install remote packages.
- Step 6) Run the program with `go run main.go`

View File

@@ -0,0 +1,12 @@
CREATE TABLE `userinfo` (
`uid` INTEGER PRIMARY KEY AUTOINCREMENT,
`username` VARCHAR(64) NULL,
`department` VARCHAR(64) NULL,
`created` DATE NULL
);
CREATE TABLE `userdetail` (
`uid` INT(10) NULL,
`intro` TEXT NULL,
`profile` TEXT NULL,
PRIMARY KEY (`uid`)
);

View File

@@ -0,0 +1,58 @@
// Example code for Chapter 5.6 from "Build Web Application with Golang"
// Purpose: Shows you have to perform basic CRUD operations for a mongodb driver.
package main
import (
"fmt"
"labix.org/v2/mgo"
"labix.org/v2/mgo/bson"
)
type Person struct {
Name string
Phone string
}
func checkError(err error) {
if err != nil {
panic(err)
}
}
const (
DB_NAME = "test"
DB_COLLECTION = "people"
)
func main() {
session, err := mgo.Dial("localhost")
checkError(err)
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB(DB_NAME).C(DB_COLLECTION)
err = c.DropCollection()
checkError(err)
ale := Person{"Ale", "555-5555"}
cla := Person{"Cla", "555-1234"}
fmt.Println("Inserting")
err = c.Insert(&ale, &cla)
checkError(err)
fmt.Println("Updating")
ale.Phone = "555-0101"
err = c.Update(bson.M{"name": "Ale"}, &ale)
fmt.Println("Querying")
result := Person{}
err = c.Find(bson.M{"name": "Ale"}).One(&result)
checkError(err)
fmt.Println("Phone:", result.Phone)
fmt.Println("Deleting")
err = c.Remove(bson.M{"name": "Ale"})
checkError(err)
}

View File

@@ -0,0 +1,6 @@
## Setup for `ch.5.6` for MongoDB
- Step 1) Install and run MongoDB
- Step 2) Launch the MongoDB daemon (mongod) to start the server.
- Step 3) Run `go get` to download and install the remote packages.
- Step 4) Execute the program with `go run main.go`

View File

@@ -0,0 +1,60 @@
// Example code for Chapter 5.6 from "Build Web Application with Golang"
// Purpose: Shows you have to perform basic CRUD operations for a redis driver.
package main
import (
"fmt"
"github.com/astaxie/goredis"
)
func checkError(err error) {
if err != nil {
panic(err)
}
}
const (
DB_PORT = "9191"
DB_URL = "127.0.0.1"
)
func main() {
var client goredis.Client
// Set the default port in Redis
client.Addr = DB_URL + ":" + DB_PORT
// string manipulation
fmt.Println("Inserting")
err := client.Set("a", []byte("hello"))
checkError(err)
// list operation
vals := []string{"a", "b", "c", "d"}
for _, v := range vals {
err = client.Rpush("l", []byte(v))
checkError(err)
}
fmt.Println("Updating")
err = client.Set("a", []byte("a is for apple"))
checkError(err)
err = client.Rpush("l", []byte("e"))
checkError(err)
fmt.Println("Querying")
val, err := client.Get("a")
checkError(err)
fmt.Println(string(val))
dbvals, err := client.Lrange("l", 0, 4)
checkError(err)
for i, v := range dbvals {
println(i, ":", string(v))
}
fmt.Println("Deleting")
_, err = client.Del("l")
checkError(err)
_, err = client.Del("a")
checkError(err)
}

View File

@@ -0,0 +1,10 @@
## Setup for `ch.5.6` for Redis
- Step 1) Install and run Redis
- Step 2) Launch the Redis server matching the DB constants.
DB_PORT = "9191"
DB_URL = "127.0.0.1"
- Step 3) Run `go get` to download and install the remote packages.
- Step 4) Execute the program with `go run main.go`

View File

@@ -0,0 +1,12 @@
// Example code for Chapter 1.2 from "Build Web Application with Golang"
// Purpose: Shows how to create a simple package called `mymath`
// This package must be imported from another go file to run.
package mymath
func Sqrt(x float64) float64 {
z := 0.0
for i := 0; i < 1000; i++ {
z -= (z*z - x) / (2 * x)
}
return z
}

BIN
fa/images/1.1.cmd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
fa/images/1.1.linux.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
fa/images/1.1.mac.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
fa/images/1.3.go.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
fa/images/1.4.eclipse1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

BIN
fa/images/1.4.eclipse2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

BIN
fa/images/1.4.eclipse3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Some files were not shown because too many files have changed in this diff Show More