3
.gitignore
vendored
@@ -8,4 +8,5 @@ _book
|
||||
.DS_Store
|
||||
.gitignore
|
||||
.vscode
|
||||
.git
|
||||
.git
|
||||
/fa/working
|
||||
@@ -10,6 +10,7 @@
|
||||
* [বাংলা](bn/preface.md)
|
||||
* [日本語](ja/preface.md)
|
||||
* [中文](zh/preface.md)
|
||||
* [پارسی](fa/preface.md)
|
||||
|
||||
# Donate
|
||||
|
||||
|
||||
24
fa/01.0.md
Normal 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
@@ -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">
|
||||
|
||||
اگر بر روی صفحه نمایش خود، پیغام زیر را مشاهده می کنید، یعنی همه چیز به درستی تنظیم شده است.
|
||||
|
||||

|
||||
|
||||
شکل ۱.۱ اطلاعات سیستم بعد از کامپایل سورس کد
|
||||
|
||||
اگر این اطلاعات را درباره 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
@@ -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
@@ -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)
|
||||
14
fa/code/src/apps/ch.1.2/main.go
Normal 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))
|
||||
}
|
||||
11
fa/code/src/apps/ch.2.1/main.go
Normal 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")
|
||||
}
|
||||
277
fa/code/src/apps/ch.2.2/main.go
Normal 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,g,len=4,cap=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 exist,ok is false,true 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()
|
||||
}
|
||||
8
fa/code/src/apps/ch.2.2/what_is_wrong_with_this/main.go
Normal 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
|
||||
}
|
||||
26
fa/code/src/apps/ch.2.3/basic_functions/main.go
Normal 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
|
||||
}
|
||||
14
fa/code/src/apps/ch.2.3/hidden_print_methods/main.go
Normal 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()
|
||||
}
|
||||
26
fa/code/src/apps/ch.2.3/import_packages/main.go
Normal 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))
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package only_call_init
|
||||
|
||||
import "fmt"
|
||||
|
||||
func init() {
|
||||
fmt.Println("only_call_init.init() was called.")
|
||||
}
|
||||
142
fa/code/src/apps/ch.2.3/main.go
Normal 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()
|
||||
}
|
||||
31
fa/code/src/apps/ch.2.3/panic_and_recover/main.go
Normal 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)
|
||||
}
|
||||
31
fa/code/src/apps/ch.2.3/pass_by_value_and_pointer/main.go
Normal 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()
|
||||
}
|
||||
44
fa/code/src/apps/ch.2.3/type_function/main.go
Normal 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)
|
||||
}
|
||||
20
fa/code/src/apps/ch.2.3/variadic_functions/main.go
Normal 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)
|
||||
}
|
||||
43
fa/code/src/apps/ch.2.4/compare_age/main.go
Normal 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)
|
||||
}
|
||||
39
fa/code/src/apps/ch.2.4/embedded_structs/main.go
Normal 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)
|
||||
}
|
||||
39
fa/code/src/apps/ch.2.4/embedded_structs2/main.go
Normal 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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
39
fa/code/src/apps/ch.2.4/main.go
Normal 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()
|
||||
}
|
||||
36
fa/code/src/apps/ch.2.5/attach_methods_to_struct/main.go
Normal 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())
|
||||
}
|
||||
73
fa/code/src/apps/ch.2.5/box_example/main.go
Normal 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())
|
||||
}
|
||||
31
fa/code/src/apps/ch.2.5/embedded_method/main.go
Normal 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()
|
||||
}
|
||||
36
fa/code/src/apps/ch.2.5/method_overload/main.go
Normal 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()
|
||||
}
|
||||
18
fa/code/src/apps/ch.2.5/pass_struct_to_method/main.go
Normal 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))
|
||||
}
|
||||
71
fa/code/src/apps/ch.2.6/interface/main.go
Normal 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()
|
||||
}
|
||||
}
|
||||
33
fa/code/src/apps/ch.2.6/reflection/main.go
Normal 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()
|
||||
}
|
||||
22
fa/code/src/apps/ch.2.6/stringer_interface/main.go
Normal 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)
|
||||
}
|
||||
38
fa/code/src/apps/ch.2.6/switch_type_check/main.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
37
fa/code/src/apps/ch.2.6/type_check/main.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
13
fa/code/src/apps/ch.2.7/buffered_channel/main.go
Normal 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)
|
||||
}
|
||||
20
fa/code/src/apps/ch.2.7/goroutine/main.go
Normal 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
|
||||
}
|
||||
24
fa/code/src/apps/ch.2.7/range_and_close_channel/main.go
Normal 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)
|
||||
}
|
||||
}
|
||||
30
fa/code/src/apps/ch.2.7/select_channel/main.go
Normal 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)
|
||||
}
|
||||
27
fa/code/src/apps/ch.2.7/timeout/main.go
Normal 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
|
||||
}
|
||||
24
fa/code/src/apps/ch.2.7/unbuffered_channel/main.go
Normal 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)
|
||||
}
|
||||
31
fa/code/src/apps/ch.3.2/main.go
Normal 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)
|
||||
}
|
||||
}
|
||||
30
fa/code/src/apps/ch.3.4/main.go
Normal 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)
|
||||
}
|
||||
12
fa/code/src/apps/ch.4.1/login.gtpl
Normal 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>
|
||||
48
fa/code/src/apps/ch.4.1/main.go
Normal 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)
|
||||
}
|
||||
}
|
||||
59
fa/code/src/apps/ch.4.2/main.go
Normal 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)
|
||||
}
|
||||
}
|
||||
89
fa/code/src/apps/ch.4.2/profile.gtpl
Normal 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}}
|
||||
16
fa/code/src/apps/ch.4.2/submission.gtpl
Normal 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}}
|
||||
175
fa/code/src/apps/ch.4.2/validator/main.go
Normal 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
|
||||
}
|
||||
28
fa/code/src/apps/ch.4.3/index.gtpl
Normal 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>
|
||||
39
fa/code/src/apps/ch.4.3/main.go
Normal 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)
|
||||
}
|
||||
54
fa/code/src/apps/ch.4.4/main.go
Normal 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)
|
||||
}
|
||||
}
|
||||
70
fa/code/src/apps/ch.4.4/nonce/main.go
Normal 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))
|
||||
}
|
||||
85
fa/code/src/apps/ch.4.4/profile.gtpl
Normal 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}}
|
||||
17
fa/code/src/apps/ch.4.4/submission.gtpl
Normal 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}}
|
||||
175
fa/code/src/apps/ch.4.4/validator/main.go
Normal 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
|
||||
}
|
||||
46
fa/code/src/apps/ch.4.5/client_upload/main.go
Normal 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)
|
||||
}
|
||||
15
fa/code/src/apps/ch.4.5/index.gtpl
Normal 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}}
|
||||
64
fa/code/src/apps/ch.4.5/main.go
Normal 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)
|
||||
}
|
||||
70
fa/code/src/apps/ch.4.5/nonce/main.go
Normal 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))
|
||||
}
|
||||
17
fa/code/src/apps/ch.4.5/upload.gtpl
Normal 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}}
|
||||
175
fa/code/src/apps/ch.4.5/validator/main.go
Normal 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
|
||||
}
|
||||
76
fa/code/src/apps/ch.5.2/main.go
Normal 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)
|
||||
}
|
||||
}
|
||||
12
fa/code/src/apps/ch.5.2/readme.md
Normal 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`
|
||||
7
fa/code/src/apps/ch.5.2/schema.sql
Normal 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`)
|
||||
);
|
||||
BIN
fa/code/src/apps/ch.5.3/foo.db
Normal file
72
fa/code/src/apps/ch.5.3/main.go
Normal 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)
|
||||
}
|
||||
}
|
||||
23
fa/code/src/apps/ch.5.3/readme.md
Normal 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`
|
||||
|
||||
6
fa/code/src/apps/ch.5.3/schema.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
CREATE TABLE `userinfo` (
|
||||
`uid` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`username` VARCHAR(64) NULL,
|
||||
`department` VARCHAR(64) NULL,
|
||||
`created` DATE NULL
|
||||
);
|
||||
78
fa/code/src/apps/ch.5.4/main.go
Normal 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)
|
||||
}
|
||||
}
|
||||
12
fa/code/src/apps/ch.5.4/readme.md
Normal 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`
|
||||
9
fa/code/src/apps/ch.5.4/schema.sql
Normal 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);
|
||||
170
fa/code/src/apps/ch.5.5/main.go
Normal 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)
|
||||
}
|
||||
23
fa/code/src/apps/ch.5.5/readme.md
Normal 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`
|
||||
|
||||
12
fa/code/src/apps/ch.5.5/schema.sql
Normal 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`)
|
||||
);
|
||||
58
fa/code/src/apps/ch.5.6/mongodb/main.go
Normal 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)
|
||||
}
|
||||
6
fa/code/src/apps/ch.5.6/mongodb/readme.md
Normal 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`
|
||||
60
fa/code/src/apps/ch.5.6/redis/main.go
Normal 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)
|
||||
}
|
||||
10
fa/code/src/apps/ch.5.6/redis/readme.md
Normal 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`
|
||||
12
fa/code/src/mymath/sqrt.go
Normal 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
|
After Width: | Height: | Size: 11 KiB |
BIN
fa/images/1.1.cmd.png~380a8ee74c41759d8189ad553423467994187253
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
fa/images/1.1.cmd.png~update the structure for gitbook
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
fa/images/1.1.linux.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
fa/images/1.1.linux.png~380a8ee74c41759d8189ad553423467994187253
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
fa/images/1.1.linux.png~update the structure for gitbook
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
fa/images/1.1.mac.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
fa/images/1.1.mac.png~380a8ee74c41759d8189ad553423467994187253
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
fa/images/1.1.mac.png~update the structure for gitbook
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
fa/images/1.3.go.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
fa/images/1.3.go.png~380a8ee74c41759d8189ad553423467994187253
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
fa/images/1.3.go.png~update the structure for gitbook
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
fa/images/1.4.eclipse1.png
Normal file
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 92 KiB |
BIN
fa/images/1.4.eclipse1.png~update the structure for gitbook
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
fa/images/1.4.eclipse2.png
Normal file
|
After Width: | Height: | Size: 213 KiB |
|
After Width: | Height: | Size: 213 KiB |
BIN
fa/images/1.4.eclipse2.png~update the structure for gitbook
Normal file
|
After Width: | Height: | Size: 213 KiB |
BIN
fa/images/1.4.eclipse3.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 51 KiB |