Replace the spellings of github/Github with GitHub
This commit is contained in:
@@ -92,13 +92,13 @@ Um die Anwendung zu kompilieren, müssen wir zurück in das Verzeichnis, in welc
|
||||
|
||||
## Installation von Paketen Dritter (Remote Packages)
|
||||
|
||||
Go umfasst ein Werkzeug zum Installieren von Remote Packages, also Paketen die von anderen Programmierern erstellt wurden. Mit dem Befehl `go get` kannst Du diese für die eigene Nutzung installieren. Es unterstützt die meisten Open Source Communities wie Github, Google Code, Bitbucket und Launchpad.
|
||||
Go umfasst ein Werkzeug zum Installieren von Remote Packages, also Paketen die von anderen Programmierern erstellt wurden. Mit dem Befehl `go get` kannst Du diese für die eigene Nutzung installieren. Es unterstützt die meisten Open Source Communities wie GitHub, Google Code, Bitbucket und Launchpad.
|
||||
|
||||
go get github.com/astaxie/beedb
|
||||
|
||||
Du kannst `go get -u …` nutzen, um ein Remote Package zu aktualisieren. Zugleich werden auch alle benötigten Abhängigkeiten mit installiert.
|
||||
|
||||
Dieser Befehl nutzt verschiedene Versionskontrollsysteme für die verschiedenen Open Source Plattformen. So wird beispielsweise `git` für Github und `hg` für Google Code verwendet. Daher musst Du zuerst die entsprechenden Versionskontrollsysteme installieren, ehe Du `go get` nutzen kannst.
|
||||
Dieser Befehl nutzt verschiedene Versionskontrollsysteme für die verschiedenen Open Source Plattformen. So wird beispielsweise `git` für GitHub und `hg` für Google Code verwendet. Daher musst Du zuerst die entsprechenden Versionskontrollsysteme installieren, ehe Du `go get` nutzen kannst.
|
||||
|
||||
Nach dem Ausführen der oben gezeigten Befehle, sollte die Orderstruktur etwa so aussehen.
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ Dieser Befehl löscht alle Dateien, die vom Kompiler generiert wurden, einschlie
|
||||
DIR.test(.exe) // Generiert von go test -c
|
||||
MAINFILE(.exe) // Generiert von go build MAINFILE.go
|
||||
|
||||
Überlicherweise nutze ich diese Befehle zum Säubern von Projekten, bevor ich diese auf Github hochlade. Sie sind nützlich für lokale Tests, aber nutzlos zur Versionskontrolle.
|
||||
Überlicherweise nutze ich diese Befehle zum Säubern von Projekten, bevor ich diese auf GitHub hochlade. Sie sind nützlich für lokale Tests, aber nutzlos zur Versionskontrolle.
|
||||
|
||||
## go fmt und gofmt
|
||||
|
||||
@@ -56,10 +56,10 @@ Wir nutzen üblicherweise `gofmt -w` statt `go fmt`. Somit wird Deine Quellcoded
|
||||
|
||||
## go get
|
||||
|
||||
Dieser Befehl ermöglicht es, Remote Packages herunterzuladen. Bisher untersützt es Bitbucket, Github, Google Code und Launchpad. Es geschehen zwei Dinge, nachdem wir den Befehl ausgeführt haben. Als erstes lädt Go den Quellcode herunter und führt danach `go install` aus. Bevor Du `go get` nutzt, solltest Du vorher die benötigten Versionskontrollsysteme herunterladen.
|
||||
Dieser Befehl ermöglicht es, Remote Packages herunterzuladen. Bisher untersützt es Bitbucket, GitHub, Google Code und Launchpad. Es geschehen zwei Dinge, nachdem wir den Befehl ausgeführt haben. Als erstes lädt Go den Quellcode herunter und führt danach `go install` aus. Bevor Du `go get` nutzt, solltest Du vorher die benötigten Versionskontrollsysteme herunterladen.
|
||||
|
||||
BitBucket (Mercurial und Git)
|
||||
Github (Git)
|
||||
GitHub (Git)
|
||||
Google Code (Git, Mercurial, Subversion)
|
||||
Launchpad (Bazaar)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ When our web application is finally production ready, what are the steps necessa
|
||||
|
||||
## Daemons
|
||||
|
||||
Currently, Go programs cannot cannot be run as daemon processes (for additional information, see the open issue on github [here](https://github.com/golang/go/issues/227)). It's difficult to fork existing threads in Go because there is no way of ensuring a consistent state in all threads that have been used.
|
||||
Currently, Go programs cannot cannot be run as daemon processes (for additional information, see the open issue on GitHub [here](https://github.com/golang/go/issues/227)). It's difficult to fork existing threads in Go because there is no way of ensuring a consistent state in all threads that have been used.
|
||||
|
||||
We can, however, see many attempts at implementing daemons online, such as in the two following ways;
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ OAuth and OAuth 2 are currently two of the most popular authentication methods.
|
||||
|
||||
github.com/bradrydzewski/go.auth
|
||||
|
||||
The code below demonstrates how to use this library to implement OAuth authentication in Beego using our Github credentials:
|
||||
The code below demonstrates how to use this library to implement OAuth authentication in Beego using our GitHub credentials:
|
||||
|
||||
1. Let's add some routes
|
||||
|
||||
@@ -147,7 +147,7 @@ After clicking "Authorize app", the following screen appears:
|
||||
|
||||

|
||||
|
||||
Figure 14.6 authorized Github information gets displayed after the login page
|
||||
Figure 14.6 authorized GitHub information gets displayed after the login page
|
||||
|
||||
## Custom authentication
|
||||
|
||||
|
||||
@@ -95,13 +95,13 @@ To compile this application, you need to switch to the application directory, wh
|
||||
|
||||
## Install remote packages
|
||||
|
||||
Go has a tool for installing remote packages, which is a command called `go get`. It supports most open source communities, including Github, Google Code, BitBucket, and Launchpad.
|
||||
Go has a tool for installing remote packages, which is a command called `go get`. It supports most open source communities, including GitHub, Google Code, BitBucket, and Launchpad.
|
||||
|
||||
go get github.com/astaxie/beedb
|
||||
|
||||
You can use `go get -u …` to update your remote packages and it will automatically install all the dependent packages as well.
|
||||
|
||||
This tool will use different version control tools for different open source platforms. For example, `git` for Github and `hg` for Google Code. Therefore, you have to install these version control tools before you use `go get`.
|
||||
This tool will use different version control tools for different open source platforms. For example, `git` for GitHub and `hg` for Google Code. Therefore, you have to install these version control tools before you use `go get`.
|
||||
|
||||
After executing the above commands, the directory structure should look like following.
|
||||
|
||||
|
||||
@@ -55,10 +55,10 @@ We usually use `gofmt -w` instead of `go fmt`. The latter will not rewrite your
|
||||
|
||||
## go get
|
||||
|
||||
This command is for getting remote packages. So far, it supports BitBucket, Github, Google Code and Launchpad. There are actually two things that happen after we execute this command. The first thing is that Go downloads the source code, then executes `go install`. Before you use this command, make sure you have installed all of the related tools.
|
||||
This command is for getting remote packages. So far, it supports BitBucket, GitHub, Google Code and Launchpad. There are actually two things that happen after we execute this command. The first thing is that Go downloads the source code, then executes `go install`. Before you use this command, make sure you have installed all of the related tools.
|
||||
|
||||
BitBucket (Mercurial Git)
|
||||
Github (git)
|
||||
GitHub (git)
|
||||
Google Code (Git, Mercurial, Subversion)
|
||||
Launchpad (Bazaar)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ To mitigate all the problems that Google faced with current tools, they wrote a
|
||||
|
||||
Go was designed with concurrency in mind, please note that parallelism != concurrency, there is an [amazing post](https://blog.golang.org/concurrency-is-not-parallelism) by Rob Pike on the [golang blog](https://blog.golang.org/), you will find it there, it is worth a read.
|
||||
|
||||
Another very important change that is the concept of `GOPATH`. Gone are the days when you had to create a folder called `code` and then create workspaces for eclipse and what not. Now you have to keep one folder tree for go code which will be updated by the package manager automatically. It is also recommended to create folders with either a custom domain or the github domain, for example I created a task manager using golang so I created a set of folders
|
||||
Another very important change that is the concept of `GOPATH`. Gone are the days when you had to create a folder called `code` and then create workspaces for eclipse and what not. Now you have to keep one folder tree for go code which will be updated by the package manager automatically. It is also recommended to create folders with either a custom domain or the GitHub domain, for example I created a task manager using golang so I created a set of folders
|
||||
`~/go/src/github.com/thewhitetulip/Tasks`
|
||||
|
||||
**Note:** In *nix systems `~` stands for home directory, which is the windows equivalent of `C:\\Users\\username`.
|
||||
|
||||
@@ -4,7 +4,7 @@ When our web application is finally production ready, what are the steps necessa
|
||||
|
||||
## Daemons
|
||||
|
||||
Currently, Go programs cannot be run as daemon processes (for additional information, see the open issue on github [here](https://github.com/golang/go/issues/227)). It's difficult to fork existing threads in Go because there is no way of ensuring a consistent state in all threads that have been used.
|
||||
Currently, Go programs cannot be run as daemon processes (for additional information, see the open issue on GitHub [here](https://github.com/golang/go/issues/227)). It's difficult to fork existing threads in Go because there is no way of ensuring a consistent state in all threads that have been used.
|
||||
|
||||
We can, however, see many attempts at implementing daemons online, such as in the two following ways;
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ OAuth and OAuth 2 are currently two of the most popular authentication methods.
|
||||
|
||||
github.com/bradrydzewski/go.auth
|
||||
|
||||
The code below demonstrates how to use this library to implement OAuth authentication in Beego using our Github credentials:
|
||||
The code below demonstrates how to use this library to implement OAuth authentication in Beego using our GitHub credentials:
|
||||
|
||||
1. Let's add some routes
|
||||
|
||||
@@ -147,7 +147,7 @@ After clicking "Authorize app", the following screen appears:
|
||||
|
||||

|
||||
|
||||
Figure 14.6 authorized Github information gets displayed after the login page
|
||||
Figure 14.6 authorized GitHub information gets displayed after the login page
|
||||
|
||||
## Custom authentication
|
||||
|
||||
|
||||
@@ -90,13 +90,13 @@ Para compilar esta aplicación necesitas cambiar al directorio de la aplicación
|
||||
```
|
||||
## Instala paquete remotos
|
||||
|
||||
Go tiene una herramienta para instalar paquetes remotos, es el comando llamado `go get`. Soporta la mayoría de comunidades de código libre, incluyendo Github, Google Code, BitBucket y Launchpad.
|
||||
Go tiene una herramienta para instalar paquetes remotos, es el comando llamado `go get`. Soporta la mayoría de comunidades de código libre, incluyendo GitHub, Google Code, BitBucket y Launchpad.
|
||||
```
|
||||
go get github.com/astaxie/beedb
|
||||
```
|
||||
Puedes usar `go get -u …` para actualizar tus paquetes remotos e incluso instalará todas sus dependencias.
|
||||
|
||||
Esta herramienta usará diferente herramientas de control de versiones para las diferentes plataformas de código libre. Por ejemplo, `git` para Github y `hg` para Google Code. Debido a esto, debes instalar estas herramientas de control de versiones antes de usar `go get`.
|
||||
Esta herramienta usará diferente herramientas de control de versiones para las diferentes plataformas de código libre. Por ejemplo, `git` para GitHub y `hg` para Google Code. Debido a esto, debes instalar estas herramientas de control de versiones antes de usar `go get`.
|
||||
|
||||
Después de ejecutar los comandos anteriormente descritos, la estructura de directorios debería verse de la siguiente forma:
|
||||
```
|
||||
|
||||
@@ -53,10 +53,10 @@ Usualmente usamos `gofmt -w` en vez de `go fmt`. El último, no rescribirá tus
|
||||
|
||||
## go get
|
||||
|
||||
Este comando es para obtener paquetes remotos. Hasta el momento soporta BitBucket, Github, Google Code y Launchpad. Actualmente existen dos cosas que suceden después de ejecutar este comando. La primera es que Go descarga el código fuente, luego ejecuta `go install`. Antes de que utilices este comando, asegúrate que tienes instaladas todas las herramientas relacionadas.
|
||||
Este comando es para obtener paquetes remotos. Hasta el momento soporta BitBucket, GitHub, Google Code y Launchpad. Actualmente existen dos cosas que suceden después de ejecutar este comando. La primera es que Go descarga el código fuente, luego ejecuta `go install`. Antes de que utilices este comando, asegúrate que tienes instaladas todas las herramientas relacionadas.
|
||||
```
|
||||
BitBucket (Mercurial Git)
|
||||
Github (git)
|
||||
GitHub (git)
|
||||
Google Code (Git, Mercurial, Subversion)
|
||||
Launchpad (Bazaar)
|
||||
```
|
||||
|
||||
@@ -23,7 +23,7 @@ Entonces para mitigar todos los problemas que Google enfrentó con las herramien
|
||||
|
||||
Go fue diseñado con la concurrencia en mente, por favor note que paralelismo != concurrencia. Hay un post maravilloso escrito por Bob Pike en el blog de Go, blog.golang.org, que usted encontraréa ahí y vale la pena leerlo.
|
||||
|
||||
Otro cambio muy importante que Go trajo a la programación y que yo personalmente amo, es le concepto de `GOPATH`, los tiempos donde tenías que crear una carpeta llamada code y entonces crear espacios de trabajo para eclipse y otros. Ahora usted puede tener un árbol de carpetas para el código en Go y se mantendrá actualizado automáticamente por el administrador de paquetes. También bajo el código que estamos recomendando crear carpetas con cada dominio específico o el dominio de github, por ejemplo yo creé un manejador de tareas usando Go, entonces creé un conjunto de carpetas
|
||||
Otro cambio muy importante que Go trajo a la programación y que yo personalmente amo, es le concepto de `GOPATH`, los tiempos donde tenías que crear una carpeta llamada code y entonces crear espacios de trabajo para eclipse y otros. Ahora usted puede tener un árbol de carpetas para el código en Go y se mantendrá actualizado automáticamente por el administrador de paquetes. También bajo el código que estamos recomendando crear carpetas con cada dominio específico o el dominio de GitHub, por ejemplo yo creé un manejador de tareas usando Go, entonces creé un conjunto de carpetas
|
||||
`~/go/src/github.com/thewhitetulip/Tasks` Nota: En sistemas * nix `~` se refiere al directorio del usuario, que en windows es equivalente a `C:\\Users\\username`
|
||||
Ahora el `~/go/` es el universo de código Go en su máquina, este es solo una significante mejora en comparación con otros lenguajes, entonces podemos almacenar código eficientemente sin molestias, esto puede parecer raro al comienzo pero tiene un montón de sentido a comparación de los nombres de paquete en otros lenguajes que usan sistemas como el del dominio inverso.
|
||||
|
||||
|
||||
@@ -95,13 +95,13 @@ func main() {
|
||||
|
||||
## نصب بستههای ریموت
|
||||
|
||||
Go has a tool for installing remote packages, which is a command called `go get`. It supports most open source communities, including Github, Google Code, BitBucket, and Launchpad.
|
||||
Go has a tool for installing remote packages, which is a command called `go get`. It supports most open source communities, including GitHub, Google Code, BitBucket, and Launchpad.
|
||||
|
||||
go get github.com/astaxie/beedb
|
||||
|
||||
You can use `go get -u …` to update your remote packages and it will automatically install all the dependent packages as well.
|
||||
|
||||
This tool will use different version control tools for different open source platforms. For example, `git` for Github and `hg` for Google Code. Therefore, you have to install these version control tools before you use `go get`.
|
||||
This tool will use different version control tools for different open source platforms. For example, `git` for GitHub and `hg` for Google Code. Therefore, you have to install these version control tools before you use `go get`.
|
||||
|
||||
After executing the above commands, the directory structure should look like following.
|
||||
|
||||
|
||||
@@ -55,10 +55,10 @@ We usually use `gofmt -w` instead of `go fmt`. The latter will not rewrite your
|
||||
|
||||
## go get
|
||||
|
||||
This command is for getting remote packages. So far, it supports BitBucket, Github, Google Code and Launchpad. There are actually two things that happen after we execute this command. The first thing is that Go downloads the source code, then executes `go install`. Before you use this command, make sure you have installed all of the related tools.
|
||||
This command is for getting remote packages. So far, it supports BitBucket, GitHub, Google Code and Launchpad. There are actually two things that happen after we execute this command. The first thing is that Go downloads the source code, then executes `go install`. Before you use this command, make sure you have installed all of the related tools.
|
||||
|
||||
BitBucket (Mercurial Git)
|
||||
Github (git)
|
||||
GitHub (git)
|
||||
Google Code (Git, Mercurial, Subversion)
|
||||
Launchpad (Bazaar)
|
||||
|
||||
|
||||
@@ -115,14 +115,14 @@ Vous devriez voir le contenu suivant dans votre temrinal:
|
||||
## Installer des paquets distants
|
||||
|
||||
Go a un outil pour installer des paquets distants, qui est l'outil `go get`.Il supporte la majorité des communautés libres, comme
|
||||
Github, Google Code, BitBucket, et Launchpad.
|
||||
GitHub, Google Code, BitBucket, et Launchpad.
|
||||
|
||||
go get github.com/astaxie/beedb
|
||||
|
||||
>Vous pouvez utiliser `go get -u` pour mettre à jour vos paquets distants, cela mettra aussi à jour les dépendances.
|
||||
|
||||
Vous obtiendrez le code source des paquets désirés grâce à cette commande, depuis différentes plate-formes, utilisant chacune leur système de gestion de version.
|
||||
Par exemple, `git` pour Github et `hg` pour Google Code. Ainsi vous devrez au préalable installer le client du système de gestion de version approprié
|
||||
Par exemple, `git` pour GitHub et `hg` pour Google Code. Ainsi vous devrez au préalable installer le client du système de gestion de version approprié
|
||||
avant d'utiliser`go get`.
|
||||
|
||||
Après avoir utilisé les commandes précédentes, votre structure de dossier devrait ressembler à celle-ci:
|
||||
|
||||
@@ -69,13 +69,13 @@ Ce dernier ne modifie pas vos fichiers source après formattage. `gofmt -w src`
|
||||
|
||||
## go get
|
||||
|
||||
Cette commande récupère des paquets distants. Sont supportés BitBucket, Github, Google Code et Launchpad.
|
||||
Cette commande récupère des paquets distants. Sont supportés BitBucket, GitHub, Google Code et Launchpad.
|
||||
Il se passe en fait deux choses à l'exécution de cette commande.
|
||||
En premier lieu, Go télécharge le code source, puis il exécute `go install`.
|
||||
Avant d'utiliser cette commande, assurez-vous d'installer les outils nécessaires.
|
||||
|
||||
BitBucket (Mercurial Git)
|
||||
Github (git)
|
||||
GitHub (git)
|
||||
Google Code (Git, Mercurial, Subversion)
|
||||
Launchpad (Bazaar)
|
||||
|
||||
|
||||
352
ja/01.2.md
352
ja/01.2.md
@@ -1,176 +1,176 @@
|
||||
# 1.2 GOPATHとワーキングディレクトリ
|
||||
|
||||
さきほどGoをインストールする際はGOPATH変数を設定する必要があるとご説明しました。Goはバージョン1.1から必ずこの変数を設定するようになっており、Goのインストールディレクトリと同じにはできません。このディレクトリは、GoのソースコードやGoの実行可能ファイル、並びにコンパイル済みのパッケージファイルを保存する為に使用します。そのためこのディレクトリには3つのサブディレクトリが存在します:src、bin、pkgです。
|
||||
|
||||
## GOPATH設定
|
||||
go コマンドは、ある重要な環境変数に依存しています:$GOPATH<sup>1</sup>
|
||||
|
||||
Windowsシステムにおいて環境変数の形式は`%GOPATH%`です。この本の中では主にUnix形式を使用します。Windowsユーザは適時置き換えてください。
|
||||
|
||||
*(注:これはGoのインストールディレクトリではありません。以下では筆者のワーキングディレクトリで説明します。もし異なるディレクトリを使用する場合はGOPATHをあなたのワーキングディレクトリに置き換えてください。)*
|
||||
|
||||
Unix に似た環境であれば大体以下のような設定になります:
|
||||
```sh
|
||||
export GOPATH=/home/apple/mygo
|
||||
```
|
||||
上のディレクトリを新たに作成し、上の一行を`.bashrc`または`.zshrc`もしくは自分の`sh`の設定ファイルに加えます。
|
||||
|
||||
Windows では以下のように設定します。新しくGOPATHと呼ばれる環境変数を作成します:
|
||||
```sh
|
||||
GOPATH=c:\mygo
|
||||
```
|
||||
GOPATHは複数のディレクトリを許容します。複数のディレクトリがある場合、デリミタに気をつけてください。複数のディレクトリがある場合Windowsはセミコロン、Linuxはコロンを使います。複数のGOPATHがある場合は、デフォルトでgo getの内容が第一ディレクトリとされます。
|
||||
|
||||
|
||||
上の $GOPATH ディレクトリには3つのディレクトリがあります:
|
||||
|
||||
- src にはソースコードを保存します(例えば:.go .c .h .s等)
|
||||
- pkg にはコンパイル後に生成されるファイル(例えば:.a)
|
||||
- bin にはコンパイル後に生成される実行可能ファイル(このまま $PATH 変数に加えてもかまいません。もしいくつもgopathがある場合は、`${GOPATH//://bin:}/bin`を使って全てのbinディレクトリを追加してください)
|
||||
|
||||
以降私はすべての例でmygoを私のgopathディレクトリとします。
|
||||
|
||||
## ソースコードディレクトリ構成
|
||||
GOPATH内のsrcディレクトリはこれから開発するプログラムにとってメインとなるディレクトリです。全てのソースコードはこのディレクトリに置くことになります。一般的な方法では一つのプロジェクトが一つのディレクトリが割り当てられます、例えば:$GOPATH/src/mymath はmymathというアプリケーションパッケージか実行アプリケーションになります。これはpackageがmainかそうでないかによって決定します。mainであれば実行可能アプリケーションで、そうでなければアプリケーションパッケージになります。これに関してはpackageを後ほどご紹介する予定です。
|
||||
|
||||
|
||||
新しくアプリケーションやソースパッケージを作成するときは、srcディレクトリの中にディレクトリを作るところから始めます。ディレクトリ名は一般的にソースパッケージ名になります。もちろんネストしたディレクトリも可能です。例えばsrcの中に$GOPATH/src/github.com/astaxie/beedbというディレクトリを作ったとすると、このパッケージパスは"github.com/astaxie/beedb"になり、パッケージ名は最後のディレクトリであるbeedbになります。
|
||||
|
||||
以下ではmymathを例にどのようにアプリケーションパッケージをコーディングするかご説明します。以下のコードを実行します。
|
||||
```sh
|
||||
cd $GOPATH/src
|
||||
mkdir mymath
|
||||
```
|
||||
sqrt.goというファイルを作成し、内容を以下のようにします。
|
||||
```go
|
||||
// $GOPATH/src/mymath/sqrt.goコードは以下の通り:
|
||||
package mymath
|
||||
|
||||
func Sqrt(x float64) float64 {
|
||||
z := 0.0
|
||||
for i := 0; i < 1000; i++ {
|
||||
z -= (z*z - x) / (2 * x)
|
||||
}
|
||||
return z
|
||||
}
|
||||
```
|
||||
このように私のアプリケーションパッケージディレクトリとコードが作成されました。注意:一般的にpackageの名前とディレクトリ名は一致させるべきです。
|
||||
|
||||
## コンパイルアプリケーション
|
||||
上のとおり、我々はすでに自分のアプリケーションパッケージを作成しましたが、どのようにコンパイル/インストールすべきでしょうか?2種類の方法が存在します。
|
||||
|
||||
1、対応するアプリケーションパッケージディレクトリに入り、`go install`を実行すればインストールできます。
|
||||
|
||||
2,任意のディレクトリで以下のコード`go install mymath`を実行します。
|
||||
|
||||
インストールが終われば、以下のディレクトリに入り
|
||||
```sh
|
||||
cd $GOPATH/pkg/${GOOS}_${GOARCH}
|
||||
//以下のファイルが現れるはずです。
|
||||
mymath.a
|
||||
```
|
||||
この.aファイルはアプリケーションパッケージです。ならば我々はどのように実行できるでしょうか?
|
||||
|
||||
次にアプリケーション・プログラムを作成してこのアプリケーションパッケージをコールします。
|
||||
|
||||
アプリケーションパッケージmathappを作ります。
|
||||
```sh
|
||||
cd $GOPATH/src
|
||||
mkdir mathapp
|
||||
cd mathapp
|
||||
vim main.go
|
||||
```
|
||||
|
||||
`$GOPATH/src/mathapp/main.go`コード:
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"mymath"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Hello, world. Sqrt(2) = %v\n", mymath.Sqrt(2))
|
||||
}
|
||||
```
|
||||
このパッケージは`main`であることが分かると思います。importにおいてコールするパッケージは`mymath`であり、これが`$GOPATH/src`のパスに対応します。もしネストしたディレクトリであれば、importの中でネストしたディレクトリをインポートします。例えばいくつものGOPATHがあった場合も同じで、Goは自動的に複数の`$GOPATH/src`の中から探し出します。
|
||||
|
||||
さて、どのようにプログラムをコンパイルするのでしょうか?このアプリケーションディレクトリに入り、`go build`を実行すれば、このディレクトリの下にmathappの実行可能ファイルが生成されます。
|
||||
```sh
|
||||
./mathapp
|
||||
```
|
||||
|
||||
以下のように出力されます。
|
||||
```sh
|
||||
Hello, world. Sqrt(2) = 1.414213562373095
|
||||
```
|
||||
|
||||
どのようにアプリケーションをインストールするのでしょうか。このディレクトリに入り、`go install`を実行すると、$GOPATH/bin/の下に実行可能ファイルmathappが作成されます。`$GOPATH/bin`が我々のPATHに追加されていることを思い出して下さい、コマンドラインから以下のように入力することで実行することができます。
|
||||
|
||||
```sh
|
||||
mathapp
|
||||
```
|
||||
|
||||
この場合も以下のように出力されます。
|
||||
|
||||
Hello, world. Sqrt(2) = 1.414213562373095
|
||||
|
||||
ここではどのように実行可能アプリケーションをコンパイル/インストールし、ディレクトリ構造を設計するかについてご紹介しました。
|
||||
|
||||
## リモートパッケージの取得
|
||||
go言語はリモートパッケージを取得するツール`go get`を持っています。現在go getは多数のオープンソースリポジトリをサポートしています(github、googlecode、bitbucket、Launchpad)
|
||||
|
||||
go get github.com/astaxie/beedb
|
||||
|
||||
>go get -u オプションはパッケージの自動更新を行います。また、go get時に自動的に当該のパッケージの依存する他のサードパーティパッケージを取得します。
|
||||
|
||||
このコマンドでふさわしいコードを取得し、対応するオープンソースプラットホームに対し異なるソースコントロールツールを利用します。例えばgithubではgit、googlecodeではhg。そのためこれらのコードを取得したい場合は、先に対応するソースコードコントロールツールをインストールしておく必要があります。
|
||||
|
||||
上述の方法で取得したコードはローカルの以下の場所に配置されます。
|
||||
|
||||
$GOPATH
|
||||
src
|
||||
|--github.com
|
||||
|-astaxie
|
||||
|-beedb
|
||||
pkg
|
||||
|--対応プラットフォーム
|
||||
|-github.com
|
||||
|--astaxie
|
||||
|beedb.a
|
||||
|
||||
go getは以下のような手順を踏みます。まずはじめにソースコードツールでコードをsrcの下にcloneします。その後`go install`を実行します。
|
||||
|
||||
コードの中でリモートパッケージが使用される場合、単純にローカルのパッケージと同じように頭のimportに対応するパスを添えるだけです。
|
||||
|
||||
import "github.com/astaxie/beedb"
|
||||
|
||||
## プログラムの全体構成
|
||||
上記で作成したローカルのmygoのディレクトリ構造は以下のようになっています。
|
||||
|
||||
bin/
|
||||
mathapp
|
||||
pkg/
|
||||
プラットフォーム名/ 例:darwin_amd64、linux_amd64
|
||||
mymath.a
|
||||
github.com/
|
||||
astaxie/
|
||||
beedb.a
|
||||
src/
|
||||
mathapp
|
||||
main.go
|
||||
mymath/
|
||||
sqrt.go
|
||||
github.com/
|
||||
astaxie/
|
||||
beedb/
|
||||
beedb.go
|
||||
util.go
|
||||
|
||||
上述の構成から明確に判断できるのは、binディレクトリの下にコンパイル後の実行可能ファイルが保存され、pkgの下に関数パッケージが保存され、srcの下にアプリケーションのソースコードが保存されているということです。
|
||||
|
||||
## links
|
||||
* [目次](<preface.md>)
|
||||
* 前へ: [GOのインストール](<01.1.md>)
|
||||
* 次へ: [GOのコマンド](<01.3.md>)
|
||||
# 1.2 GOPATHとワーキングディレクトリ
|
||||
|
||||
さきほどGoをインストールする際はGOPATH変数を設定する必要があるとご説明しました。Goはバージョン1.1から必ずこの変数を設定するようになっており、Goのインストールディレクトリと同じにはできません。このディレクトリは、GoのソースコードやGoの実行可能ファイル、並びにコンパイル済みのパッケージファイルを保存する為に使用します。そのためこのディレクトリには3つのサブディレクトリが存在します:src、bin、pkgです。
|
||||
|
||||
## GOPATH設定
|
||||
go コマンドは、ある重要な環境変数に依存しています:$GOPATH<sup>1</sup>
|
||||
|
||||
Windowsシステムにおいて環境変数の形式は`%GOPATH%`です。この本の中では主にUnix形式を使用します。Windowsユーザは適時置き換えてください。
|
||||
|
||||
*(注:これはGoのインストールディレクトリではありません。以下では筆者のワーキングディレクトリで説明します。もし異なるディレクトリを使用する場合はGOPATHをあなたのワーキングディレクトリに置き換えてください。)*
|
||||
|
||||
Unix に似た環境であれば大体以下のような設定になります:
|
||||
```sh
|
||||
export GOPATH=/home/apple/mygo
|
||||
```
|
||||
上のディレクトリを新たに作成し、上の一行を`.bashrc`または`.zshrc`もしくは自分の`sh`の設定ファイルに加えます。
|
||||
|
||||
Windows では以下のように設定します。新しくGOPATHと呼ばれる環境変数を作成します:
|
||||
```sh
|
||||
GOPATH=c:\mygo
|
||||
```
|
||||
GOPATHは複数のディレクトリを許容します。複数のディレクトリがある場合、デリミタに気をつけてください。複数のディレクトリがある場合Windowsはセミコロン、Linuxはコロンを使います。複数のGOPATHがある場合は、デフォルトでgo getの内容が第一ディレクトリとされます。
|
||||
|
||||
|
||||
上の $GOPATH ディレクトリには3つのディレクトリがあります:
|
||||
|
||||
- src にはソースコードを保存します(例えば:.go .c .h .s等)
|
||||
- pkg にはコンパイル後に生成されるファイル(例えば:.a)
|
||||
- bin にはコンパイル後に生成される実行可能ファイル(このまま $PATH 変数に加えてもかまいません。もしいくつもgopathがある場合は、`${GOPATH//://bin:}/bin`を使って全てのbinディレクトリを追加してください)
|
||||
|
||||
以降私はすべての例でmygoを私のgopathディレクトリとします。
|
||||
|
||||
## ソースコードディレクトリ構成
|
||||
GOPATH内のsrcディレクトリはこれから開発するプログラムにとってメインとなるディレクトリです。全てのソースコードはこのディレクトリに置くことになります。一般的な方法では一つのプロジェクトが一つのディレクトリが割り当てられます、例えば:$GOPATH/src/mymath はmymathというアプリケーションパッケージか実行アプリケーションになります。これはpackageがmainかそうでないかによって決定します。mainであれば実行可能アプリケーションで、そうでなければアプリケーションパッケージになります。これに関してはpackageを後ほどご紹介する予定です。
|
||||
|
||||
|
||||
新しくアプリケーションやソースパッケージを作成するときは、srcディレクトリの中にディレクトリを作るところから始めます。ディレクトリ名は一般的にソースパッケージ名になります。もちろんネストしたディレクトリも可能です。例えばsrcの中に$GOPATH/src/github.com/astaxie/beedbというディレクトリを作ったとすると、このパッケージパスは"github.com/astaxie/beedb"になり、パッケージ名は最後のディレクトリであるbeedbになります。
|
||||
|
||||
以下ではmymathを例にどのようにアプリケーションパッケージをコーディングするかご説明します。以下のコードを実行します。
|
||||
```sh
|
||||
cd $GOPATH/src
|
||||
mkdir mymath
|
||||
```
|
||||
sqrt.goというファイルを作成し、内容を以下のようにします。
|
||||
```go
|
||||
// $GOPATH/src/mymath/sqrt.goコードは以下の通り:
|
||||
package mymath
|
||||
|
||||
func Sqrt(x float64) float64 {
|
||||
z := 0.0
|
||||
for i := 0; i < 1000; i++ {
|
||||
z -= (z*z - x) / (2 * x)
|
||||
}
|
||||
return z
|
||||
}
|
||||
```
|
||||
このように私のアプリケーションパッケージディレクトリとコードが作成されました。注意:一般的にpackageの名前とディレクトリ名は一致させるべきです。
|
||||
|
||||
## コンパイルアプリケーション
|
||||
上のとおり、我々はすでに自分のアプリケーションパッケージを作成しましたが、どのようにコンパイル/インストールすべきでしょうか?2種類の方法が存在します。
|
||||
|
||||
1、対応するアプリケーションパッケージディレクトリに入り、`go install`を実行すればインストールできます。
|
||||
|
||||
2,任意のディレクトリで以下のコード`go install mymath`を実行します。
|
||||
|
||||
インストールが終われば、以下のディレクトリに入り
|
||||
```sh
|
||||
cd $GOPATH/pkg/${GOOS}_${GOARCH}
|
||||
//以下のファイルが現れるはずです。
|
||||
mymath.a
|
||||
```
|
||||
この.aファイルはアプリケーションパッケージです。ならば我々はどのように実行できるでしょうか?
|
||||
|
||||
次にアプリケーション・プログラムを作成してこのアプリケーションパッケージをコールします。
|
||||
|
||||
アプリケーションパッケージmathappを作ります。
|
||||
```sh
|
||||
cd $GOPATH/src
|
||||
mkdir mathapp
|
||||
cd mathapp
|
||||
vim main.go
|
||||
```
|
||||
|
||||
`$GOPATH/src/mathapp/main.go`コード:
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"mymath"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Hello, world. Sqrt(2) = %v\n", mymath.Sqrt(2))
|
||||
}
|
||||
```
|
||||
このパッケージは`main`であることが分かると思います。importにおいてコールするパッケージは`mymath`であり、これが`$GOPATH/src`のパスに対応します。もしネストしたディレクトリであれば、importの中でネストしたディレクトリをインポートします。例えばいくつものGOPATHがあった場合も同じで、Goは自動的に複数の`$GOPATH/src`の中から探し出します。
|
||||
|
||||
さて、どのようにプログラムをコンパイルするのでしょうか?このアプリケーションディレクトリに入り、`go build`を実行すれば、このディレクトリの下にmathappの実行可能ファイルが生成されます。
|
||||
```sh
|
||||
./mathapp
|
||||
```
|
||||
|
||||
以下のように出力されます。
|
||||
```sh
|
||||
Hello, world. Sqrt(2) = 1.414213562373095
|
||||
```
|
||||
|
||||
どのようにアプリケーションをインストールするのでしょうか。このディレクトリに入り、`go install`を実行すると、$GOPATH/bin/の下に実行可能ファイルmathappが作成されます。`$GOPATH/bin`が我々のPATHに追加されていることを思い出して下さい、コマンドラインから以下のように入力することで実行することができます。
|
||||
|
||||
```sh
|
||||
mathapp
|
||||
```
|
||||
|
||||
この場合も以下のように出力されます。
|
||||
|
||||
Hello, world. Sqrt(2) = 1.414213562373095
|
||||
|
||||
ここではどのように実行可能アプリケーションをコンパイル/インストールし、ディレクトリ構造を設計するかについてご紹介しました。
|
||||
|
||||
## リモートパッケージの取得
|
||||
go言語はリモートパッケージを取得するツール`go get`を持っています。現在go getは多数のオープンソースリポジトリをサポートしています(GitHub、googlecode、bitbucket、Launchpad)
|
||||
|
||||
go get github.com/astaxie/beedb
|
||||
|
||||
>go get -u オプションはパッケージの自動更新を行います。また、go get時に自動的に当該のパッケージの依存する他のサードパーティパッケージを取得します。
|
||||
|
||||
このコマンドでふさわしいコードを取得し、対応するオープンソースプラットホームに対し異なるソースコントロールツールを利用します。例えばGitHubではgit、googlecodeではhg。そのためこれらのコードを取得したい場合は、先に対応するソースコードコントロールツールをインストールしておく必要があります。
|
||||
|
||||
上述の方法で取得したコードはローカルの以下の場所に配置されます。
|
||||
|
||||
$GOPATH
|
||||
src
|
||||
|--github.com
|
||||
|-astaxie
|
||||
|-beedb
|
||||
pkg
|
||||
|--対応プラットフォーム
|
||||
|-github.com
|
||||
|--astaxie
|
||||
|beedb.a
|
||||
|
||||
go getは以下のような手順を踏みます。まずはじめにソースコードツールでコードをsrcの下にcloneします。その後`go install`を実行します。
|
||||
|
||||
コードの中でリモートパッケージが使用される場合、単純にローカルのパッケージと同じように頭のimportに対応するパスを添えるだけです。
|
||||
|
||||
import "github.com/astaxie/beedb"
|
||||
|
||||
## プログラムの全体構成
|
||||
上記で作成したローカルのmygoのディレクトリ構造は以下のようになっています。
|
||||
|
||||
bin/
|
||||
mathapp
|
||||
pkg/
|
||||
プラットフォーム名/ 例:darwin_amd64、linux_amd64
|
||||
mymath.a
|
||||
github.com/
|
||||
astaxie/
|
||||
beedb.a
|
||||
src/
|
||||
mathapp
|
||||
main.go
|
||||
mymath/
|
||||
sqrt.go
|
||||
github.com/
|
||||
astaxie/
|
||||
beedb/
|
||||
beedb.go
|
||||
util.go
|
||||
|
||||
上述の構成から明確に判断できるのは、binディレクトリの下にコンパイル後の実行可能ファイルが保存され、pkgの下に関数パッケージが保存され、srcの下にアプリケーションのソースコードが保存されているということです。
|
||||
|
||||
## links
|
||||
* [目次](<preface.md>)
|
||||
* 前へ: [GOのインストール](<01.1.md>)
|
||||
* 次へ: [GOのコマンド](<01.3.md>)
|
||||
|
||||
860
ja/01.4.md
860
ja/01.4.md
@@ -1,430 +1,430 @@
|
||||
# 1.4 Go開発ツール
|
||||
|
||||
本章ではいくつかの開発ツールをご紹介します。これらはすべて自動化を備えており、fmt機能を自動化します。なぜならこれらはすべてクロスプラットフォームであり、そのためインストール手順といったものはすべて同じものです。
|
||||
|
||||
## LiteIDE
|
||||
|
||||
LiteIDEはGo言語の開発に特化したクロスプラットフォームの軽量統合開発環境(IDE)です。visualfcで書かれています。
|
||||
|
||||

|
||||
|
||||
図1.4 LiteIDEのメイン画面
|
||||
|
||||
**LiteIDEの主な特徴:**
|
||||
|
||||
* 主なオペレーティングシステムのサポート
|
||||
* Windows
|
||||
* Linux
|
||||
* MacOS X
|
||||
* Goコンパイル環境の管理と切り替え
|
||||
* 複数のGoコンパイル環境の管理と切り替え
|
||||
* Go言語のクロスコンパイルのサポート
|
||||
* Go標準と同じ項目管理方式
|
||||
* GOPATHに基づいたパッケージブラウザ
|
||||
* GOPATHに基づいたコンパイルシステム
|
||||
* GOPATHに基づいたドキュメント検索
|
||||
* Go言語の編集サポート
|
||||
* クラスブラウザとアウトライン表示
|
||||
* Gocode(コード自動作成ツール)の完全なサポート
|
||||
* Go言語ドキュメントとApi高速検索
|
||||
* コード表現情報の表示`F1`
|
||||
* ソースコード定義とジャンプのサポート`F2`
|
||||
* Gdbブレークポイントとテストサポート
|
||||
* gofmt自動整形のサポート
|
||||
* その他の特徴
|
||||
* 多言語メニューのサポート
|
||||
* 完全にプラガブルな構成
|
||||
* エディタのカラーリングサポート
|
||||
* Kateに基づいた文法表示サポート
|
||||
* 全文に基づく単語の自動補完
|
||||
* キーボードショートカットのバインディングサポート
|
||||
* Markdownドキュメントの編集サポート
|
||||
* リアルタイムプレビューと表示の同期
|
||||
* カスタムCSS表示
|
||||
* HTML及びPDFドキュメントのエクスポート
|
||||
* HTML/PDFドキュメントへの変換とマージ
|
||||
|
||||
**LiteIDEインストール設定**
|
||||
|
||||
* LiteIDEインストール
|
||||
* ダウンロード http://sourceforge.net/projects/liteide/files/>
|
||||
* ソースコード <https://github.com/visualfc/liteide>
|
||||
|
||||
まずGo言語環境をインストールし、その後オペレーティングシステムにしたがってLiteIDEの対応圧縮ファイルを直接解凍すれば使用できます。
|
||||
|
||||
* コンパイル環境設定
|
||||
|
||||
自身のシステムの要求にしたがってLiteIDEが現在使用している環境変数を切り替えまたは設定します。
|
||||
|
||||
Windowsオペレーティングシステムの64bitGo言語の場合、
|
||||
ツール欄の環境設定のなかでwin64を選択し、`編集環境`をクリックしてLiteIDEからwin64.envファイルを編集します。
|
||||
|
||||
GOROOT=c:\go
|
||||
GOBIN=
|
||||
GOARCH=amd64
|
||||
GOOS=windows
|
||||
CGO_ENABLED=1
|
||||
|
||||
PATH=%GOBIN%;%GOROOT%\bin;%PATH%
|
||||
。。。
|
||||
|
||||
この中の`GOROOT=c:\go`を現在のGoのインストールパスに修正し、保存するだけです。もしMinGW64があれば、`c:\MinGW64\bin`をPATHの中に入れて、goによるgccのコールでCGOコンパイラのサポートを利用することができます。
|
||||
|
||||
Linuxオペレーティングシステムで64bitGo言語の場合、
|
||||
ツール欄の環境設定の中からlinux64を選び、`編集環境`をクリックし、LiteIDEからlinux64.envファイルを編集します。
|
||||
|
||||
GOROOT=$HOME/go
|
||||
GOBIN=
|
||||
GOARCH=amd64
|
||||
GOOS=linux
|
||||
CGO_ENABLED=1
|
||||
|
||||
PATH=$GOBIN:$GOROOT/bin:$PATH
|
||||
。。。
|
||||
|
||||
この中の`GOROOT=$HOME/go`を現在のGoのインストールパスに修正して保存します。
|
||||
|
||||
* GOPATH設定
|
||||
|
||||
Go言語のツールキーはGOPATH設定を使用します。Go言語開発のプロジェクトのパスリストです。コマンドライン(LiteIDEでは`Ctrl+,`を直接入力できます)で`go help gopath`を入力するとGOPATHドキュメントを素早く確認できます。
|
||||
|
||||
LiteIDEでは簡単に確認でき、GOPATHを設定することができます。`メニュー-確認-GOPATH`設定を通じて、システム中に存在するGOPATHリストを確認することができます。
|
||||
同時に必要な追加項目にそってカスタムのGOPATHリストに追加することができます。
|
||||
|
||||
## Sublime Text
|
||||
|
||||
ここではSublime Text 2(以下「Sublime」)+GoSublimeの組み合わせをご紹介します。なぜこの組み合わせなのでしょうか?
|
||||
|
||||
- コード表示の自動化、以下の図の通り
|
||||
|
||||

|
||||
|
||||
図1.5 sublimeコードの自動化画面
|
||||
|
||||
- 保存した時にはコードが自動的に整形されています。あなたの書いたコードをより美しくGoの標準に合うよう仕上げてくれます。
|
||||
- プロジェクト管理のサポート
|
||||
|
||||

|
||||
|
||||
図1.6 sublimeプロジェクト管理画面
|
||||
|
||||
- 文法のハイライトサポート
|
||||
- Sublime Text 2はフリーで使用できます。保存回数が一定の量を超えると購入するかのダイアログが現れるので、継続利用をキャンセルするをクリックします。正式登録版とは何の違いもありません。
|
||||
|
||||
|
||||
次はどのようにインストールするかご説明します。[Sublime](http://www.sublimetext.com/)ダウンロードします。
|
||||
|
||||
自分のシステムに合わせて対応するバージョンをダウンロードし、Sublimeを開きます。Sublimeに詳しくない方はまず[Sublime Text 2 入門とテクニック](http://lucifr.com/139225/sublime-text-2-tricks-and-tips/)の文章を読んでみてください。
|
||||
|
||||
1. 開いた後、 Package Controlをインストールします。Ctrl+`でコマンドラインを開き、以下のコードを実行します:
|
||||
|
||||
import urllib2,os; pf='Package Control.sublime-package'; ipp=sublime.installed_packages_path(); os.makedirs(ipp) if not os.path.exists(ipp) else None; urllib2.install_opener(urllib2.build_opener(urllib2.ProxyHandler())); open(os.path.join(ipp,pf),'wb').write(urllib2.urlopen('http://sublime.wbond.net/'+pf.replace(' ','%20')).read()); print 'Please restart Sublime Text to finish installation'
|
||||
|
||||
この時Sublimeを再度開き直してください。メニュー欄に一つ項目が増えているのがお分かりいただけるかと思います。これでPackage Controlが正しくインストールされました。
|
||||
|
||||

|
||||
|
||||
図1.7 sublimeパッケージ管理
|
||||
|
||||
|
||||
2. インストールが完了するとSublimeのプラグインをインストールできます。GoSublime, SidebarEnhancementsとGo Buildをインストールする必要があるので、プラグインをインストールしたあとSublimeを再起動させて有効にしてください。Ctrl+Shift+pでPackage Controlを開き、`pcip`を入力します。(これは"Package Control: Install Package"と省略されます)。
|
||||
|
||||
この時、左下のコーナーに現在読み込んでいるパッケージデータが表示されます。完了すると下のような画面になります。
|
||||
|
||||

|
||||
|
||||
図1.8 sublimeプラグインのインストール画面
|
||||
|
||||
この時、GoSublimeと入力し、「確認」をクリックするとインストールが始まります。同じようにSidebarEnhancementsとGo Buildにも行います。
|
||||
|
||||
3. インストールが成功したかテストします。Sublimeを開き、main.goを開いて文法がハイライトされているのをご確認ください。`import`を入力してコードの自動表示がされます。`import "fmt"`のあとに`fmt.`を入力すると自動的に関数の候補が現れます。
|
||||
|
||||
もしすでにこのような表示がされる場合は、インストールが成功しており、自動補完が完了しています。
|
||||
|
||||
もしこのような表示がなされない場合、あなたの`$PATH`が正しく設定されていないのかもしれません。ターミナルを開き、gocodeを入力して、正しく実行できるか確認してください。もしダメであれば`$PATH`が正しく設定されていません。
|
||||
(XP向け)たまたまターミナルでの実行が成功することもあります。しかしsublimeは何も知らせてくれないかデコードエラーが発生します。sublime text3とconvert utf8プラグインを試してみてください。
|
||||
|
||||
4. MacOSではすでに$GOROOT, $GOPATH, $GOBINが設定されていても自動的にはどうすればよいか教えてくれません。
|
||||
|
||||
sublimeにてcommand + 9を押し、envを入力して$PATH, $GOROOT, $GOPATH, $GOBINといった変数を確認します。もしなければ、以下の手順に従ってください。
|
||||
|
||||
まず下のシンボリックリンクを作成し、Terminalで直接sublimeを起動します
|
||||
|
||||
ln -s /Applications/Sublime\ Text\ 2.app/Contents/SharedSupport/bin/subl /usr/local/bin/sublime
|
||||
|
||||
|
||||
## Vim
|
||||
Vimはviから発展したテキストエディタです。コード補完、コンパイルまたエラージャンプなど、プログラミングに特化した機能が豊富です。広くプログラマに使用されています。
|
||||
|
||||

|
||||
|
||||
図1.9 VIMエディタのGoの自動補完画面
|
||||
|
||||
1. vimハイライト表示の設定
|
||||
|
||||
cp -r $GOROOT/misc/vim/* ~/.vim/
|
||||
|
||||
2. ~/.vimrcファイルで文法のハイライト表示を追加します
|
||||
|
||||
filetype plugin indent on
|
||||
syntax on
|
||||
|
||||
3. [Gocode](https://github.com/nsf/gocode/)をインストールします
|
||||
|
||||
go get -u github.com/nsf/gocode
|
||||
|
||||
gocodeはデフォルトで`$GOPATH/bin`の下にインストールされています。
|
||||
|
||||
4. [Gocode](https://github.com/nsf/gocode/)を設定します。
|
||||
|
||||
~ cd $GOPATH/src/github.com/nsf/gocode/vim
|
||||
~ ./update.bash
|
||||
~ gocode set propose-builtins true
|
||||
propose-builtins true
|
||||
~ gocode set lib-path "/home/border/gocode/pkg/linux_amd64"
|
||||
lib-path "/home/border/gocode/pkg/linux_amd64"
|
||||
~ gocode set
|
||||
propose-builtins true
|
||||
lib-path "/home/border/gocode/pkg/linux_amd64"
|
||||
|
||||
>gocode setの2つのパラメータの意味を説明します:
|
||||
>
|
||||
>propose-builtins:はGoのビルトイン関数を補完するかです。タイプは定数です。デフォルトはfalseで、表示しません。
|
||||
>
|
||||
>lib-path:デフォルトで、gocodeは**$GOPATH/pkg/$GOOS_$GOARCH**と**$GOROOT/pkg/$GOOS_$GOARCH**ディレクトリのパッケージを検索するだけです。当然この設定には私達の外側のlibを検索できるようパスを設定することができます。
|
||||
|
||||
|
||||
5. おめでとうございます。インストール完了です。あなたは今から`:e main.go`でGoで開発する面白さを体験することができます。
|
||||
|
||||
より多くのVIMの設定は、[リンク](http://monnand.me/p/vim-golang-environment/zhCN/)をご参照ください。
|
||||
|
||||
## Emacs
|
||||
Emacsは伝説の神器です。彼女はエディタであるだけでなく、統合環境でもあります。または開発環境の集大成と呼んでもよいかもしれません。これらの機能はユーザの身を万能のオペレーティングシステムに置きます。
|
||||
|
||||

|
||||
|
||||
図1.10 EmacsでGoを編集するメイン画面
|
||||
|
||||
1. Emacsのハイライト表示設定
|
||||
|
||||
cp $GOROOT/misc/emacs/* ~/.emacs.d/
|
||||
|
||||
2. [Gocode](https://github.com/nsf/gocode/)をインストール
|
||||
|
||||
go get -u github.com/nsf/gocode
|
||||
|
||||
gocodeはデフォルトで`$GOBIN`の下にインストールされます。
|
||||
|
||||
3. [Gocode](https://github.com/nsf/gocode/)を設定
|
||||
|
||||
|
||||
~ cd $GOPATH/src/github.com/nsf/gocode/emacs
|
||||
~ cp go-autocomplete.el ~/.emacs.d/
|
||||
~ gocode set propose-builtins true
|
||||
propose-builtins true
|
||||
~ gocode set lib-path "/home/border/gocode/pkg/linux_amd64" // あなたのパスに置き換えてください。
|
||||
lib-path "/home/border/gocode/pkg/linux_amd64"
|
||||
~ gocode set
|
||||
propose-builtins true
|
||||
lib-path "/home/border/gocode/pkg/linux_amd64"
|
||||
|
||||
4. [Auto Completion](http://www.emacswiki.org/emacs/AutoComplete)をインストールする必要があります。
|
||||
|
||||
AutoCompleteをダウンロードして解凍します。
|
||||
|
||||
~ make install DIR=$HOME/.emacs.d/auto-complete
|
||||
|
||||
~/.emacsファイルを設定します。
|
||||
|
||||
;;auto-complete
|
||||
(require 'auto-complete-config)
|
||||
(add-to-list 'ac-dictionary-directories "~/.emacs.d/auto-complete/ac-dict")
|
||||
(ac-config-default)
|
||||
(local-set-key (kbd "M-/") 'semantic-complete-analyze-inline)
|
||||
(local-set-key "." 'semantic-complete-self-insert)
|
||||
(local-set-key ">" 'semantic-complete-self-insert)
|
||||
|
||||
詳細情報はこちらを参考にしてください:http://www.emacswiki.org/emacs/AutoComplete
|
||||
|
||||
5. .emacsを設定します。
|
||||
|
||||
;; golang mode
|
||||
(require 'go-mode-load)
|
||||
(require 'go-autocomplete)
|
||||
;; speedbar
|
||||
;; (speedbar 1)
|
||||
(speedbar-add-supported-extension ".go")
|
||||
(add-hook
|
||||
'go-mode-hook
|
||||
'(lambda ()
|
||||
;; gocode
|
||||
(auto-complete-mode 1)
|
||||
(setq ac-sources '(ac-source-go))
|
||||
;; Imenu & Speedbar
|
||||
(setq imenu-generic-expression
|
||||
'(("type" "^type *\\([^ \t\n\r\f]*\\)" 1)
|
||||
("func" "^func *\\(.*\\) {" 1)))
|
||||
(imenu-add-to-menubar "Index")
|
||||
;; Outline mode
|
||||
(make-local-variable 'outline-regexp)
|
||||
(setq outline-regexp "//\\.\\|//[^\r\n\f][^\r\n\f]\\|pack\\|func\\|impo\\|cons\\|var.\\|type\\|\t\t*....")
|
||||
(outline-minor-mode 1)
|
||||
(local-set-key "\M-a" 'outline-previous-visible-heading)
|
||||
(local-set-key "\M-e" 'outline-next-visible-heading)
|
||||
;; Menu bar
|
||||
(require 'easymenu)
|
||||
(defconst go-hooked-menu
|
||||
'("Go tools"
|
||||
["Go run buffer" go t]
|
||||
["Go reformat buffer" go-fmt-buffer t]
|
||||
["Go check buffer" go-fix-buffer t]))
|
||||
(easy-menu-define
|
||||
go-added-menu
|
||||
(current-local-map)
|
||||
"Go tools"
|
||||
go-hooked-menu)
|
||||
|
||||
;; Other
|
||||
(setq show-trailing-whitespace t)
|
||||
))
|
||||
;; helper function
|
||||
(defun go ()
|
||||
"run current buffer"
|
||||
(interactive)
|
||||
(compile (concat "go run " (buffer-file-name))))
|
||||
|
||||
;; helper function
|
||||
(defun go-fmt-buffer ()
|
||||
"run gofmt on current buffer"
|
||||
(interactive)
|
||||
(if buffer-read-only
|
||||
(progn
|
||||
(ding)
|
||||
(message "Buffer is read only"))
|
||||
(let ((p (line-number-at-pos))
|
||||
(filename (buffer-file-name))
|
||||
(old-max-mini-window-height max-mini-window-height))
|
||||
(show-all)
|
||||
(if (get-buffer "*Go Reformat Errors*")
|
||||
(progn
|
||||
(delete-windows-on "*Go Reformat Errors*")
|
||||
(kill-buffer "*Go Reformat Errors*")))
|
||||
(setq max-mini-window-height 1)
|
||||
(if (= 0 (shell-command-on-region (point-min) (point-max) "gofmt" "*Go Reformat Output*" nil "*Go Reformat Errors*" t))
|
||||
(progn
|
||||
(erase-buffer)
|
||||
(insert-buffer-substring "*Go Reformat Output*")
|
||||
(goto-char (point-min))
|
||||
(forward-line (1- p)))
|
||||
(with-current-buffer "*Go Reformat Errors*"
|
||||
(progn
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "<standard input>" nil t)
|
||||
(replace-match filename))
|
||||
(goto-char (point-min))
|
||||
(compilation-mode))))
|
||||
(setq max-mini-window-height old-max-mini-window-height)
|
||||
(delete-windows-on "*Go Reformat Output*")
|
||||
(kill-buffer "*Go Reformat Output*"))))
|
||||
;; helper function
|
||||
(defun go-fix-buffer ()
|
||||
"run gofix on current buffer"
|
||||
(interactive)
|
||||
(show-all)
|
||||
(shell-command-on-region (point-min) (point-max) "go tool fix -diff"))
|
||||
|
||||
6. おめでとうございます。今からあなたはこの神器を使ってGo開発の楽しみを体験できます。デフォルトのspeedbarは閉じています。もし開く場合は ;; (speedbar 1) の前のコメントを取り去るか、*M-x speedbar*を手動で起動してください。
|
||||
|
||||
## Eclipse
|
||||
Eclipseも非常によく使われる開発ツールです。以下ではEclipseを使ってどのようにGoプログラムを編集するかご紹介します。
|
||||
|
||||

|
||||
|
||||
図1.11 EclipseでのGo編集のメイン画面
|
||||
|
||||
1. まず[Eclipse](http://www.eclipse.org/)をダウンロードしてインストールします。
|
||||
|
||||
2. [goclipse](https://code.google.com/p/goclipse/)プラグインをダウンロードします。
|
||||
|
||||
http://code.google.com/p/goclipse/wiki/InstallationInstructions
|
||||
|
||||
3. gocodeをダウンロードして、goのコード補完を表示させます。
|
||||
|
||||
gocodeのgithubアドレス:
|
||||
|
||||
https://github.com/nsf/gocode
|
||||
|
||||
windowsではgitをインストールする必要があります。通常は[msysgit](https://code.google.com/p/msysgit/)を使います。
|
||||
|
||||
cmdでインストールを行います:
|
||||
|
||||
go get -u github.com/nsf/gocode
|
||||
|
||||
以下のコードをダウンロードし、直接go buildでコンパイルしてもかまいません。この場合はgocode.exeが生成されます。
|
||||
|
||||
4. [MinGW](http://sourceforge.net/projects/mingw/files/MinGW/)をダウンロードして要求に従いインストールしてください。
|
||||
|
||||
5. プラグイン設定
|
||||
|
||||
Windows->Reference->Go
|
||||
|
||||
(1).Goのコンパイラを設定します。
|
||||
|
||||

|
||||
|
||||
図1.12 Goの基本情報を設定します。
|
||||
|
||||
|
||||
(2).Gocodeを設定します(オプション、コード補完)、Gocodeのパスは事前に生成したgocode.exeファイルを設定します。
|
||||
|
||||

|
||||
|
||||
図1.13 gocode情報を設定します。
|
||||
|
||||
(3).GDBを設定します(オプション、テスト用)、GDBのパスはMingGWのインストールディレクトリ下のgdb.exeファイルを設定します。
|
||||
|
||||

|
||||
|
||||
図1.14 GDB情報の設定
|
||||
|
||||
6. テストが成功するか
|
||||
|
||||
goプロジェクトを一つ新規作成して、hello.goを作成します:
|
||||
|
||||

|
||||
|
||||
図1.15 プロジェクトの新規作成とファイルの編集
|
||||
|
||||
テストの実行(consoleでコマンドを入力する必要があります):
|
||||
|
||||

|
||||
|
||||
図1.16 Goプログラムのテスト
|
||||
|
||||
## IntelliJ IDEA
|
||||
Javaに親しい読者はideaに詳しいことでしょう。ideaはプラグインを通してgo言語のシンタックスハイライト、コード補完およびリビルドをサポートしています。
|
||||
|
||||
1. ideaを先にダウンロードします。ideaはマルチプラットフォームをサポートしています:win,mac,linux、もしお金があれば正式版を購入します、もし無ければ、コミュニティの無料版を使ってください。Go言語を開発するだけであれば無料版で十分事足ります。
|
||||
|
||||

|
||||
|
||||
2. Goプラグインをインストールし、FileメニューのSettingをクリックします。Pluginsを探したら、Browser repoボタンをクリックします。中国国内のユーザはおそらくエラーが出るかもしれませんが、自分で解決してくれよな。
|
||||
|
||||

|
||||
|
||||
3. この時いくつものプラグインが見つかります。Golangを検索して、download and installをダブルクリックしてください。golangの行末にDownloadedの表示が現れるのを待って、OKをクリックします。
|
||||
|
||||

|
||||
|
||||
その後Applyをクリックすると、IDEが再起動を要求します。
|
||||
|
||||
4. 再起動が完了し、新規プロジェクトを作成すると、golangプロジェクトが作成可能であることがお分かりいただけるかとおもいます:
|
||||
|
||||

|
||||
|
||||
次に、go sdkの場所を入力するよう促されるかもしれません。普段はいつもC:\Goにインストールされています。Linuxとmacは自分のインストールディレクトリの設定にしたがって、ディレクトリを選択すれば大丈夫です。
|
||||
|
||||
## links
|
||||
* [目次](<preface.md>)
|
||||
* 前へ: [Goのコマンド](<01.3.md>)
|
||||
* 次へ: [まとめ](<01.5.md>)
|
||||
# 1.4 Go開発ツール
|
||||
|
||||
本章ではいくつかの開発ツールをご紹介します。これらはすべて自動化を備えており、fmt機能を自動化します。なぜならこれらはすべてクロスプラットフォームであり、そのためインストール手順といったものはすべて同じものです。
|
||||
|
||||
## LiteIDE
|
||||
|
||||
LiteIDEはGo言語の開発に特化したクロスプラットフォームの軽量統合開発環境(IDE)です。visualfcで書かれています。
|
||||
|
||||

|
||||
|
||||
図1.4 LiteIDEのメイン画面
|
||||
|
||||
**LiteIDEの主な特徴:**
|
||||
|
||||
* 主なオペレーティングシステムのサポート
|
||||
* Windows
|
||||
* Linux
|
||||
* MacOS X
|
||||
* Goコンパイル環境の管理と切り替え
|
||||
* 複数のGoコンパイル環境の管理と切り替え
|
||||
* Go言語のクロスコンパイルのサポート
|
||||
* Go標準と同じ項目管理方式
|
||||
* GOPATHに基づいたパッケージブラウザ
|
||||
* GOPATHに基づいたコンパイルシステム
|
||||
* GOPATHに基づいたドキュメント検索
|
||||
* Go言語の編集サポート
|
||||
* クラスブラウザとアウトライン表示
|
||||
* Gocode(コード自動作成ツール)の完全なサポート
|
||||
* Go言語ドキュメントとApi高速検索
|
||||
* コード表現情報の表示`F1`
|
||||
* ソースコード定義とジャンプのサポート`F2`
|
||||
* Gdbブレークポイントとテストサポート
|
||||
* gofmt自動整形のサポート
|
||||
* その他の特徴
|
||||
* 多言語メニューのサポート
|
||||
* 完全にプラガブルな構成
|
||||
* エディタのカラーリングサポート
|
||||
* Kateに基づいた文法表示サポート
|
||||
* 全文に基づく単語の自動補完
|
||||
* キーボードショートカットのバインディングサポート
|
||||
* Markdownドキュメントの編集サポート
|
||||
* リアルタイムプレビューと表示の同期
|
||||
* カスタムCSS表示
|
||||
* HTML及びPDFドキュメントのエクスポート
|
||||
* HTML/PDFドキュメントへの変換とマージ
|
||||
|
||||
**LiteIDEインストール設定**
|
||||
|
||||
* LiteIDEインストール
|
||||
* ダウンロード http://sourceforge.net/projects/liteide/files/>
|
||||
* ソースコード <https://github.com/visualfc/liteide>
|
||||
|
||||
まずGo言語環境をインストールし、その後オペレーティングシステムにしたがってLiteIDEの対応圧縮ファイルを直接解凍すれば使用できます。
|
||||
|
||||
* コンパイル環境設定
|
||||
|
||||
自身のシステムの要求にしたがってLiteIDEが現在使用している環境変数を切り替えまたは設定します。
|
||||
|
||||
Windowsオペレーティングシステムの64bitGo言語の場合、
|
||||
ツール欄の環境設定のなかでwin64を選択し、`編集環境`をクリックしてLiteIDEからwin64.envファイルを編集します。
|
||||
|
||||
GOROOT=c:\go
|
||||
GOBIN=
|
||||
GOARCH=amd64
|
||||
GOOS=windows
|
||||
CGO_ENABLED=1
|
||||
|
||||
PATH=%GOBIN%;%GOROOT%\bin;%PATH%
|
||||
。。。
|
||||
|
||||
この中の`GOROOT=c:\go`を現在のGoのインストールパスに修正し、保存するだけです。もしMinGW64があれば、`c:\MinGW64\bin`をPATHの中に入れて、goによるgccのコールでCGOコンパイラのサポートを利用することができます。
|
||||
|
||||
Linuxオペレーティングシステムで64bitGo言語の場合、
|
||||
ツール欄の環境設定の中からlinux64を選び、`編集環境`をクリックし、LiteIDEからlinux64.envファイルを編集します。
|
||||
|
||||
GOROOT=$HOME/go
|
||||
GOBIN=
|
||||
GOARCH=amd64
|
||||
GOOS=linux
|
||||
CGO_ENABLED=1
|
||||
|
||||
PATH=$GOBIN:$GOROOT/bin:$PATH
|
||||
。。。
|
||||
|
||||
この中の`GOROOT=$HOME/go`を現在のGoのインストールパスに修正して保存します。
|
||||
|
||||
* GOPATH設定
|
||||
|
||||
Go言語のツールキーはGOPATH設定を使用します。Go言語開発のプロジェクトのパスリストです。コマンドライン(LiteIDEでは`Ctrl+,`を直接入力できます)で`go help gopath`を入力するとGOPATHドキュメントを素早く確認できます。
|
||||
|
||||
LiteIDEでは簡単に確認でき、GOPATHを設定することができます。`メニュー-確認-GOPATH`設定を通じて、システム中に存在するGOPATHリストを確認することができます。
|
||||
同時に必要な追加項目にそってカスタムのGOPATHリストに追加することができます。
|
||||
|
||||
## Sublime Text
|
||||
|
||||
ここではSublime Text 2(以下「Sublime」)+GoSublimeの組み合わせをご紹介します。なぜこの組み合わせなのでしょうか?
|
||||
|
||||
- コード表示の自動化、以下の図の通り
|
||||
|
||||

|
||||
|
||||
図1.5 sublimeコードの自動化画面
|
||||
|
||||
- 保存した時にはコードが自動的に整形されています。あなたの書いたコードをより美しくGoの標準に合うよう仕上げてくれます。
|
||||
- プロジェクト管理のサポート
|
||||
|
||||

|
||||
|
||||
図1.6 sublimeプロジェクト管理画面
|
||||
|
||||
- 文法のハイライトサポート
|
||||
- Sublime Text 2はフリーで使用できます。保存回数が一定の量を超えると購入するかのダイアログが現れるので、継続利用をキャンセルするをクリックします。正式登録版とは何の違いもありません。
|
||||
|
||||
|
||||
次はどのようにインストールするかご説明します。[Sublime](http://www.sublimetext.com/)ダウンロードします。
|
||||
|
||||
自分のシステムに合わせて対応するバージョンをダウンロードし、Sublimeを開きます。Sublimeに詳しくない方はまず[Sublime Text 2 入門とテクニック](http://lucifr.com/139225/sublime-text-2-tricks-and-tips/)の文章を読んでみてください。
|
||||
|
||||
1. 開いた後、 Package Controlをインストールします。Ctrl+`でコマンドラインを開き、以下のコードを実行します:
|
||||
|
||||
import urllib2,os; pf='Package Control.sublime-package'; ipp=sublime.installed_packages_path(); os.makedirs(ipp) if not os.path.exists(ipp) else None; urllib2.install_opener(urllib2.build_opener(urllib2.ProxyHandler())); open(os.path.join(ipp,pf),'wb').write(urllib2.urlopen('http://sublime.wbond.net/'+pf.replace(' ','%20')).read()); print 'Please restart Sublime Text to finish installation'
|
||||
|
||||
この時Sublimeを再度開き直してください。メニュー欄に一つ項目が増えているのがお分かりいただけるかと思います。これでPackage Controlが正しくインストールされました。
|
||||
|
||||

|
||||
|
||||
図1.7 sublimeパッケージ管理
|
||||
|
||||
|
||||
2. インストールが完了するとSublimeのプラグインをインストールできます。GoSublime, SidebarEnhancementsとGo Buildをインストールする必要があるので、プラグインをインストールしたあとSublimeを再起動させて有効にしてください。Ctrl+Shift+pでPackage Controlを開き、`pcip`を入力します。(これは"Package Control: Install Package"と省略されます)。
|
||||
|
||||
この時、左下のコーナーに現在読み込んでいるパッケージデータが表示されます。完了すると下のような画面になります。
|
||||
|
||||

|
||||
|
||||
図1.8 sublimeプラグインのインストール画面
|
||||
|
||||
この時、GoSublimeと入力し、「確認」をクリックするとインストールが始まります。同じようにSidebarEnhancementsとGo Buildにも行います。
|
||||
|
||||
3. インストールが成功したかテストします。Sublimeを開き、main.goを開いて文法がハイライトされているのをご確認ください。`import`を入力してコードの自動表示がされます。`import "fmt"`のあとに`fmt.`を入力すると自動的に関数の候補が現れます。
|
||||
|
||||
もしすでにこのような表示がされる場合は、インストールが成功しており、自動補完が完了しています。
|
||||
|
||||
もしこのような表示がなされない場合、あなたの`$PATH`が正しく設定されていないのかもしれません。ターミナルを開き、gocodeを入力して、正しく実行できるか確認してください。もしダメであれば`$PATH`が正しく設定されていません。
|
||||
(XP向け)たまたまターミナルでの実行が成功することもあります。しかしsublimeは何も知らせてくれないかデコードエラーが発生します。sublime text3とconvert utf8プラグインを試してみてください。
|
||||
|
||||
4. MacOSではすでに$GOROOT, $GOPATH, $GOBINが設定されていても自動的にはどうすればよいか教えてくれません。
|
||||
|
||||
sublimeにてcommand + 9を押し、envを入力して$PATH, $GOROOT, $GOPATH, $GOBINといった変数を確認します。もしなければ、以下の手順に従ってください。
|
||||
|
||||
まず下のシンボリックリンクを作成し、Terminalで直接sublimeを起動します
|
||||
|
||||
ln -s /Applications/Sublime\ Text\ 2.app/Contents/SharedSupport/bin/subl /usr/local/bin/sublime
|
||||
|
||||
|
||||
## Vim
|
||||
Vimはviから発展したテキストエディタです。コード補完、コンパイルまたエラージャンプなど、プログラミングに特化した機能が豊富です。広くプログラマに使用されています。
|
||||
|
||||

|
||||
|
||||
図1.9 VIMエディタのGoの自動補完画面
|
||||
|
||||
1. vimハイライト表示の設定
|
||||
|
||||
cp -r $GOROOT/misc/vim/* ~/.vim/
|
||||
|
||||
2. ~/.vimrcファイルで文法のハイライト表示を追加します
|
||||
|
||||
filetype plugin indent on
|
||||
syntax on
|
||||
|
||||
3. [Gocode](https://github.com/nsf/gocode/)をインストールします
|
||||
|
||||
go get -u github.com/nsf/gocode
|
||||
|
||||
gocodeはデフォルトで`$GOPATH/bin`の下にインストールされています。
|
||||
|
||||
4. [Gocode](https://github.com/nsf/gocode/)を設定します。
|
||||
|
||||
~ cd $GOPATH/src/github.com/nsf/gocode/vim
|
||||
~ ./update.bash
|
||||
~ gocode set propose-builtins true
|
||||
propose-builtins true
|
||||
~ gocode set lib-path "/home/border/gocode/pkg/linux_amd64"
|
||||
lib-path "/home/border/gocode/pkg/linux_amd64"
|
||||
~ gocode set
|
||||
propose-builtins true
|
||||
lib-path "/home/border/gocode/pkg/linux_amd64"
|
||||
|
||||
>gocode setの2つのパラメータの意味を説明します:
|
||||
>
|
||||
>propose-builtins:はGoのビルトイン関数を補完するかです。タイプは定数です。デフォルトはfalseで、表示しません。
|
||||
>
|
||||
>lib-path:デフォルトで、gocodeは**$GOPATH/pkg/$GOOS_$GOARCH**と**$GOROOT/pkg/$GOOS_$GOARCH**ディレクトリのパッケージを検索するだけです。当然この設定には私達の外側のlibを検索できるようパスを設定することができます。
|
||||
|
||||
|
||||
5. おめでとうございます。インストール完了です。あなたは今から`:e main.go`でGoで開発する面白さを体験することができます。
|
||||
|
||||
より多くのVIMの設定は、[リンク](http://monnand.me/p/vim-golang-environment/zhCN/)をご参照ください。
|
||||
|
||||
## Emacs
|
||||
Emacsは伝説の神器です。彼女はエディタであるだけでなく、統合環境でもあります。または開発環境の集大成と呼んでもよいかもしれません。これらの機能はユーザの身を万能のオペレーティングシステムに置きます。
|
||||
|
||||

|
||||
|
||||
図1.10 EmacsでGoを編集するメイン画面
|
||||
|
||||
1. Emacsのハイライト表示設定
|
||||
|
||||
cp $GOROOT/misc/emacs/* ~/.emacs.d/
|
||||
|
||||
2. [Gocode](https://github.com/nsf/gocode/)をインストール
|
||||
|
||||
go get -u github.com/nsf/gocode
|
||||
|
||||
gocodeはデフォルトで`$GOBIN`の下にインストールされます。
|
||||
|
||||
3. [Gocode](https://github.com/nsf/gocode/)を設定
|
||||
|
||||
|
||||
~ cd $GOPATH/src/github.com/nsf/gocode/emacs
|
||||
~ cp go-autocomplete.el ~/.emacs.d/
|
||||
~ gocode set propose-builtins true
|
||||
propose-builtins true
|
||||
~ gocode set lib-path "/home/border/gocode/pkg/linux_amd64" // あなたのパスに置き換えてください。
|
||||
lib-path "/home/border/gocode/pkg/linux_amd64"
|
||||
~ gocode set
|
||||
propose-builtins true
|
||||
lib-path "/home/border/gocode/pkg/linux_amd64"
|
||||
|
||||
4. [Auto Completion](http://www.emacswiki.org/emacs/AutoComplete)をインストールする必要があります。
|
||||
|
||||
AutoCompleteをダウンロードして解凍します。
|
||||
|
||||
~ make install DIR=$HOME/.emacs.d/auto-complete
|
||||
|
||||
~/.emacsファイルを設定します。
|
||||
|
||||
;;auto-complete
|
||||
(require 'auto-complete-config)
|
||||
(add-to-list 'ac-dictionary-directories "~/.emacs.d/auto-complete/ac-dict")
|
||||
(ac-config-default)
|
||||
(local-set-key (kbd "M-/") 'semantic-complete-analyze-inline)
|
||||
(local-set-key "." 'semantic-complete-self-insert)
|
||||
(local-set-key ">" 'semantic-complete-self-insert)
|
||||
|
||||
詳細情報はこちらを参考にしてください:http://www.emacswiki.org/emacs/AutoComplete
|
||||
|
||||
5. .emacsを設定します。
|
||||
|
||||
;; golang mode
|
||||
(require 'go-mode-load)
|
||||
(require 'go-autocomplete)
|
||||
;; speedbar
|
||||
;; (speedbar 1)
|
||||
(speedbar-add-supported-extension ".go")
|
||||
(add-hook
|
||||
'go-mode-hook
|
||||
'(lambda ()
|
||||
;; gocode
|
||||
(auto-complete-mode 1)
|
||||
(setq ac-sources '(ac-source-go))
|
||||
;; Imenu & Speedbar
|
||||
(setq imenu-generic-expression
|
||||
'(("type" "^type *\\([^ \t\n\r\f]*\\)" 1)
|
||||
("func" "^func *\\(.*\\) {" 1)))
|
||||
(imenu-add-to-menubar "Index")
|
||||
;; Outline mode
|
||||
(make-local-variable 'outline-regexp)
|
||||
(setq outline-regexp "//\\.\\|//[^\r\n\f][^\r\n\f]\\|pack\\|func\\|impo\\|cons\\|var.\\|type\\|\t\t*....")
|
||||
(outline-minor-mode 1)
|
||||
(local-set-key "\M-a" 'outline-previous-visible-heading)
|
||||
(local-set-key "\M-e" 'outline-next-visible-heading)
|
||||
;; Menu bar
|
||||
(require 'easymenu)
|
||||
(defconst go-hooked-menu
|
||||
'("Go tools"
|
||||
["Go run buffer" go t]
|
||||
["Go reformat buffer" go-fmt-buffer t]
|
||||
["Go check buffer" go-fix-buffer t]))
|
||||
(easy-menu-define
|
||||
go-added-menu
|
||||
(current-local-map)
|
||||
"Go tools"
|
||||
go-hooked-menu)
|
||||
|
||||
;; Other
|
||||
(setq show-trailing-whitespace t)
|
||||
))
|
||||
;; helper function
|
||||
(defun go ()
|
||||
"run current buffer"
|
||||
(interactive)
|
||||
(compile (concat "go run " (buffer-file-name))))
|
||||
|
||||
;; helper function
|
||||
(defun go-fmt-buffer ()
|
||||
"run gofmt on current buffer"
|
||||
(interactive)
|
||||
(if buffer-read-only
|
||||
(progn
|
||||
(ding)
|
||||
(message "Buffer is read only"))
|
||||
(let ((p (line-number-at-pos))
|
||||
(filename (buffer-file-name))
|
||||
(old-max-mini-window-height max-mini-window-height))
|
||||
(show-all)
|
||||
(if (get-buffer "*Go Reformat Errors*")
|
||||
(progn
|
||||
(delete-windows-on "*Go Reformat Errors*")
|
||||
(kill-buffer "*Go Reformat Errors*")))
|
||||
(setq max-mini-window-height 1)
|
||||
(if (= 0 (shell-command-on-region (point-min) (point-max) "gofmt" "*Go Reformat Output*" nil "*Go Reformat Errors*" t))
|
||||
(progn
|
||||
(erase-buffer)
|
||||
(insert-buffer-substring "*Go Reformat Output*")
|
||||
(goto-char (point-min))
|
||||
(forward-line (1- p)))
|
||||
(with-current-buffer "*Go Reformat Errors*"
|
||||
(progn
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "<standard input>" nil t)
|
||||
(replace-match filename))
|
||||
(goto-char (point-min))
|
||||
(compilation-mode))))
|
||||
(setq max-mini-window-height old-max-mini-window-height)
|
||||
(delete-windows-on "*Go Reformat Output*")
|
||||
(kill-buffer "*Go Reformat Output*"))))
|
||||
;; helper function
|
||||
(defun go-fix-buffer ()
|
||||
"run gofix on current buffer"
|
||||
(interactive)
|
||||
(show-all)
|
||||
(shell-command-on-region (point-min) (point-max) "go tool fix -diff"))
|
||||
|
||||
6. おめでとうございます。今からあなたはこの神器を使ってGo開発の楽しみを体験できます。デフォルトのspeedbarは閉じています。もし開く場合は ;; (speedbar 1) の前のコメントを取り去るか、*M-x speedbar*を手動で起動してください。
|
||||
|
||||
## Eclipse
|
||||
Eclipseも非常によく使われる開発ツールです。以下ではEclipseを使ってどのようにGoプログラムを編集するかご紹介します。
|
||||
|
||||

|
||||
|
||||
図1.11 EclipseでのGo編集のメイン画面
|
||||
|
||||
1. まず[Eclipse](http://www.eclipse.org/)をダウンロードしてインストールします。
|
||||
|
||||
2. [goclipse](https://code.google.com/p/goclipse/)プラグインをダウンロードします。
|
||||
|
||||
http://code.google.com/p/goclipse/wiki/InstallationInstructions
|
||||
|
||||
3. gocodeをダウンロードして、goのコード補完を表示させます。
|
||||
|
||||
gocodeのGitHubアドレス:
|
||||
|
||||
https://github.com/nsf/gocode
|
||||
|
||||
windowsではgitをインストールする必要があります。通常は[msysgit](https://code.google.com/p/msysgit/)を使います。
|
||||
|
||||
cmdでインストールを行います:
|
||||
|
||||
go get -u github.com/nsf/gocode
|
||||
|
||||
以下のコードをダウンロードし、直接go buildでコンパイルしてもかまいません。この場合はgocode.exeが生成されます。
|
||||
|
||||
4. [MinGW](http://sourceforge.net/projects/mingw/files/MinGW/)をダウンロードして要求に従いインストールしてください。
|
||||
|
||||
5. プラグイン設定
|
||||
|
||||
Windows->Reference->Go
|
||||
|
||||
(1).Goのコンパイラを設定します。
|
||||
|
||||

|
||||
|
||||
図1.12 Goの基本情報を設定します。
|
||||
|
||||
|
||||
(2).Gocodeを設定します(オプション、コード補完)、Gocodeのパスは事前に生成したgocode.exeファイルを設定します。
|
||||
|
||||

|
||||
|
||||
図1.13 gocode情報を設定します。
|
||||
|
||||
(3).GDBを設定します(オプション、テスト用)、GDBのパスはMingGWのインストールディレクトリ下のgdb.exeファイルを設定します。
|
||||
|
||||

|
||||
|
||||
図1.14 GDB情報の設定
|
||||
|
||||
6. テストが成功するか
|
||||
|
||||
goプロジェクトを一つ新規作成して、hello.goを作成します:
|
||||
|
||||

|
||||
|
||||
図1.15 プロジェクトの新規作成とファイルの編集
|
||||
|
||||
テストの実行(consoleでコマンドを入力する必要があります):
|
||||
|
||||

|
||||
|
||||
図1.16 Goプログラムのテスト
|
||||
|
||||
## IntelliJ IDEA
|
||||
Javaに親しい読者はideaに詳しいことでしょう。ideaはプラグインを通してgo言語のシンタックスハイライト、コード補完およびリビルドをサポートしています。
|
||||
|
||||
1. ideaを先にダウンロードします。ideaはマルチプラットフォームをサポートしています:win,mac,linux、もしお金があれば正式版を購入します、もし無ければ、コミュニティの無料版を使ってください。Go言語を開発するだけであれば無料版で十分事足ります。
|
||||
|
||||

|
||||
|
||||
2. Goプラグインをインストールし、FileメニューのSettingをクリックします。Pluginsを探したら、Browser repoボタンをクリックします。中国国内のユーザはおそらくエラーが出るかもしれませんが、自分で解決してくれよな。
|
||||
|
||||

|
||||
|
||||
3. この時いくつものプラグインが見つかります。Golangを検索して、download and installをダブルクリックしてください。golangの行末にDownloadedの表示が現れるのを待って、OKをクリックします。
|
||||
|
||||

|
||||
|
||||
その後Applyをクリックすると、IDEが再起動を要求します。
|
||||
|
||||
4. 再起動が完了し、新規プロジェクトを作成すると、golangプロジェクトが作成可能であることがお分かりいただけるかとおもいます:
|
||||
|
||||

|
||||
|
||||
次に、go sdkの場所を入力するよう促されるかもしれません。普段はいつもC:\Goにインストールされています。Linuxとmacは自分のインストールディレクトリの設定にしたがって、ディレクトリを選択すれば大丈夫です。
|
||||
|
||||
## links
|
||||
* [目次](<preface.md>)
|
||||
* 前へ: [Goのコマンド](<01.3.md>)
|
||||
* 次へ: [まとめ](<01.5.md>)
|
||||
|
||||
248
ja/05.4.md
248
ja/05.4.md
@@ -1,124 +1,124 @@
|
||||
# 5.4 PostgreSQLデータベースの使用
|
||||
|
||||
PostgreSQLはフリーなオブジェクト-リレーショナルデータベースサーバ(データベース管理システム)です。これは活発なBSDライクなライセンスで公開されています。他のオープンソースなデータベースシステム(MySQLやFirebird)やOracle、Sybase、IBMのDB2やMicrosoft SQL Serverといったプロプライエタリなシステムに対する選択肢の一つです。
|
||||
|
||||
PostgreSQLとMySQLを比較すると、これは少々巨大です。これはOracleの代替として設計されているためです。そのため、企業のアプリケーションではPostgreSQLを選択することが賢い選択の一つとなっています。
|
||||
|
||||
MySQLはOracleに買収され、現在徐々にクローズされつつあります。(MySQL 5.5.31以降のすべてのバージョンがGPLライセンスを順守していません)。これに鑑み、将来我々もプロジェクトのバックエンドのデータベースとしてMySQLではなくPostgreSQLを選択することになるかもしれません。
|
||||
|
||||
## ドライバ
|
||||
GoはPostgreSQLをサポートしたドライバも非常に多く実装されています。国外では多くの人が開発でこのデータベースを使用しているためです。
|
||||
|
||||
- https://github.com/lib/pq database/sqlドライバをサポートしています。純粋にGoで書かれています。
|
||||
- https://github.com/jbarham/gopgsqldriver database/sqlドライバをサポートしています。純粋にGoで書かれています。
|
||||
- https://github.com/lxn/go-pgsql database/sqlドライバをサポートしています。純粋にGoで書かれています。
|
||||
|
||||
下の例では一つ目のドライバを採用してご説明します。これは使用している人が最も多く、githubでも比較的活発であるからです。
|
||||
|
||||
## 実例コード
|
||||
データベースのテーブル作成文:
|
||||
|
||||
CREATE TABLE userinfo
|
||||
(
|
||||
uid serial NOT NULL,
|
||||
username character varying(100) NOT NULL,
|
||||
department character varying(500) NOT NULL,
|
||||
Created date,
|
||||
CONSTRAINT userinfo_pkey PRIMARY KEY (uid)
|
||||
)
|
||||
WITH (OIDS=FALSE);
|
||||
|
||||
CREATE TABLE userdeatail
|
||||
(
|
||||
uid integer,
|
||||
intro character varying(100),
|
||||
profile character varying(100)
|
||||
)
|
||||
WITH(OIDS=FALSE);
|
||||
|
||||
下ではGoがどのようにデータベースのテーブルのデータを操作するか見て行きましょう:追加・削除・修正・検索
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
_ "https://github.com/lib/pq"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db, err := sql.Open("postgres", "user=astaxie password=astaxie dbname=test sslmode=disable")
|
||||
checkErr(err)
|
||||
|
||||
//データの挿入
|
||||
stmt, err := db.Prepare("INSERT INTO userinfo(username,department,created) VALUES($1,$2,$3) RETURNING uid")
|
||||
checkErr(err)
|
||||
|
||||
res, err := stmt.Exec("astaxie", "研究開発部門", "2012-12-09")
|
||||
checkErr(err)
|
||||
|
||||
//pgはこの関数をサポートしていません。MySQLのインクリメンタルなIDのようなものが無いためです。
|
||||
id, err := res.LastInsertId()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(id)
|
||||
|
||||
//データの更新
|
||||
stmt, err = db.Prepare("update userinfo set username=$1 where uid=$2")
|
||||
checkErr(err)
|
||||
|
||||
res, err = stmt.Exec("astaxieupdate", 1)
|
||||
checkErr(err)
|
||||
|
||||
affect, err := res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect)
|
||||
|
||||
//データの検索
|
||||
rows, err := db.Query("SELECT * FROM userinfo")
|
||||
checkErr(err)
|
||||
|
||||
for rows.Next() {
|
||||
var uid int
|
||||
var username string
|
||||
var department string
|
||||
var created string
|
||||
err = rows.Scan(&uid, &username, &department, &created)
|
||||
checkErr(err)
|
||||
fmt.Println(uid)
|
||||
fmt.Println(username)
|
||||
fmt.Println(department)
|
||||
fmt.Println(created)
|
||||
}
|
||||
|
||||
//データの削除
|
||||
stmt, err = db.Prepare("delete from userinfo where uid=$1")
|
||||
checkErr(err)
|
||||
|
||||
res, err = stmt.Exec(1)
|
||||
checkErr(err)
|
||||
|
||||
affect, err = res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect)
|
||||
|
||||
db.Close()
|
||||
|
||||
}
|
||||
|
||||
func checkErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
上のコードによって、PostgreSQLが`$1`や`$2`といった方法によって引数を渡している様子がお分かりいただけるかとおもいます。MySQLの中の`?`ではありません。また、sql.Openではdsn情報のシンタックスがMySQLのドライバでのdsnシンタックスと異なります。そのため、使用される際はこの違いにご注意ください。
|
||||
|
||||
また、pgはLastInsertId関数をサポートしていません。PostgreSQLの内部ではMySQLのインクリメンタルなIDを返すといった実装がないためです。その他のコードはほとんど同じです。
|
||||
|
||||
## links
|
||||
* [目次](<preface.md>)
|
||||
* 前へ: [SQLiteデータベースの使用](<05.3.md>)
|
||||
* 次へ: [beedbライブラリを使ってORM開発を行う](<05.5.md>)
|
||||
# 5.4 PostgreSQLデータベースの使用
|
||||
|
||||
PostgreSQLはフリーなオブジェクト-リレーショナルデータベースサーバ(データベース管理システム)です。これは活発なBSDライクなライセンスで公開されています。他のオープンソースなデータベースシステム(MySQLやFirebird)やOracle、Sybase、IBMのDB2やMicrosoft SQL Serverといったプロプライエタリなシステムに対する選択肢の一つです。
|
||||
|
||||
PostgreSQLとMySQLを比較すると、これは少々巨大です。これはOracleの代替として設計されているためです。そのため、企業のアプリケーションではPostgreSQLを選択することが賢い選択の一つとなっています。
|
||||
|
||||
MySQLはOracleに買収され、現在徐々にクローズされつつあります。(MySQL 5.5.31以降のすべてのバージョンがGPLライセンスを順守していません)。これに鑑み、将来我々もプロジェクトのバックエンドのデータベースとしてMySQLではなくPostgreSQLを選択することになるかもしれません。
|
||||
|
||||
## ドライバ
|
||||
GoはPostgreSQLをサポートしたドライバも非常に多く実装されています。国外では多くの人が開発でこのデータベースを使用しているためです。
|
||||
|
||||
- https://github.com/lib/pq database/sqlドライバをサポートしています。純粋にGoで書かれています。
|
||||
- https://github.com/jbarham/gopgsqldriver database/sqlドライバをサポートしています。純粋にGoで書かれています。
|
||||
- https://github.com/lxn/go-pgsql database/sqlドライバをサポートしています。純粋にGoで書かれています。
|
||||
|
||||
下の例では一つ目のドライバを採用してご説明します。これは使用している人が最も多く、GitHubでも比較的活発であるからです。
|
||||
|
||||
## 実例コード
|
||||
データベースのテーブル作成文:
|
||||
|
||||
CREATE TABLE userinfo
|
||||
(
|
||||
uid serial NOT NULL,
|
||||
username character varying(100) NOT NULL,
|
||||
department character varying(500) NOT NULL,
|
||||
Created date,
|
||||
CONSTRAINT userinfo_pkey PRIMARY KEY (uid)
|
||||
)
|
||||
WITH (OIDS=FALSE);
|
||||
|
||||
CREATE TABLE userdeatail
|
||||
(
|
||||
uid integer,
|
||||
intro character varying(100),
|
||||
profile character varying(100)
|
||||
)
|
||||
WITH(OIDS=FALSE);
|
||||
|
||||
下ではGoがどのようにデータベースのテーブルのデータを操作するか見て行きましょう:追加・削除・修正・検索
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
_ "https://github.com/lib/pq"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db, err := sql.Open("postgres", "user=astaxie password=astaxie dbname=test sslmode=disable")
|
||||
checkErr(err)
|
||||
|
||||
//データの挿入
|
||||
stmt, err := db.Prepare("INSERT INTO userinfo(username,department,created) VALUES($1,$2,$3) RETURNING uid")
|
||||
checkErr(err)
|
||||
|
||||
res, err := stmt.Exec("astaxie", "研究開発部門", "2012-12-09")
|
||||
checkErr(err)
|
||||
|
||||
//pgはこの関数をサポートしていません。MySQLのインクリメンタルなIDのようなものが無いためです。
|
||||
id, err := res.LastInsertId()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(id)
|
||||
|
||||
//データの更新
|
||||
stmt, err = db.Prepare("update userinfo set username=$1 where uid=$2")
|
||||
checkErr(err)
|
||||
|
||||
res, err = stmt.Exec("astaxieupdate", 1)
|
||||
checkErr(err)
|
||||
|
||||
affect, err := res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect)
|
||||
|
||||
//データの検索
|
||||
rows, err := db.Query("SELECT * FROM userinfo")
|
||||
checkErr(err)
|
||||
|
||||
for rows.Next() {
|
||||
var uid int
|
||||
var username string
|
||||
var department string
|
||||
var created string
|
||||
err = rows.Scan(&uid, &username, &department, &created)
|
||||
checkErr(err)
|
||||
fmt.Println(uid)
|
||||
fmt.Println(username)
|
||||
fmt.Println(department)
|
||||
fmt.Println(created)
|
||||
}
|
||||
|
||||
//データの削除
|
||||
stmt, err = db.Prepare("delete from userinfo where uid=$1")
|
||||
checkErr(err)
|
||||
|
||||
res, err = stmt.Exec(1)
|
||||
checkErr(err)
|
||||
|
||||
affect, err = res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect)
|
||||
|
||||
db.Close()
|
||||
|
||||
}
|
||||
|
||||
func checkErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
上のコードによって、PostgreSQLが`$1`や`$2`といった方法によって引数を渡している様子がお分かりいただけるかとおもいます。MySQLの中の`?`ではありません。また、sql.Openではdsn情報のシンタックスがMySQLのドライバでのdsnシンタックスと異なります。そのため、使用される際はこの違いにご注意ください。
|
||||
|
||||
また、pgはLastInsertId関数をサポートしていません。PostgreSQLの内部ではMySQLのインクリメンタルなIDを返すといった実装がないためです。その他のコードはほとんど同じです。
|
||||
|
||||
## links
|
||||
* [目次](<preface.md>)
|
||||
* 前へ: [SQLiteデータベースの使用](<05.3.md>)
|
||||
* 次へ: [beedbライブラリを使ってORM開発を行う](<05.5.md>)
|
||||
|
||||
14
ja/13.6.md
14
ja/13.6.md
@@ -1,7 +1,7 @@
|
||||
# 13.6 まとめ
|
||||
この章ではどのように基礎的なGo言語のフレームワークを実装するかについてご紹介しました。フレームワークにはルーティング設計が含まれます。Goのビルトインのhttpパッケージにあるルーティングにはいくつか足りない部分があるため、我々は動的なルーティング規則を設計し、その後MVCモデルにおけるController設計をご紹介しました。controllerはRESTを実装しており、主な考え方はtornadeフレームワークからきています。次にも出るのlayoutおよびテンプレートの自動化技術を実装しました。主に採用したのはGoのビルトインのモデルエンジンです。最後に補足的なログ、設定といった情報の設計をご紹介しました。これらの設計を通して基礎的なフレームワークbeegoを実装しました。現在このフレームワークはすでにgithub上でオープンソースになっています。最後に我々はbeegoを通じてブログシステムの実装を行いました。この実例コードを通してどのように快速にホームページを開発するのかが見渡せたのではないかと思います。
|
||||
|
||||
## links
|
||||
* [目次](<preface.md>)
|
||||
* 前へ: [ブログの追加/削除/修正の実装](<13.5.md>)
|
||||
* 次へ: [Webフレームワークの拡張](<14.0.md>)
|
||||
# 13.6 まとめ
|
||||
この章ではどのように基礎的なGo言語のフレームワークを実装するかについてご紹介しました。フレームワークにはルーティング設計が含まれます。Goのビルトインのhttpパッケージにあるルーティングにはいくつか足りない部分があるため、我々は動的なルーティング規則を設計し、その後MVCモデルにおけるController設計をご紹介しました。controllerはRESTを実装しており、主な考え方はtornadeフレームワークからきています。次にも出るのlayoutおよびテンプレートの自動化技術を実装しました。主に採用したのはGoのビルトインのモデルエンジンです。最後に補足的なログ、設定といった情報の設計をご紹介しました。これらの設計を通して基礎的なフレームワークbeegoを実装しました。現在このフレームワークはすでにGitHub上でオープンソースになっています。最後に我々はbeegoを通じてブログシステムの実装を行いました。この実例コードを通してどのように快速にホームページを開発するのかが見渡せたのではないかと思います。
|
||||
|
||||
## links
|
||||
* [目次](<preface.md>)
|
||||
* 前へ: [ブログの追加/削除/修正の実装](<13.5.md>)
|
||||
* 次へ: [Webフレームワークの拡張](<14.0.md>)
|
||||
|
||||
518
ja/14.4.md
518
ja/14.4.md
@@ -1,259 +1,259 @@
|
||||
# 14.4 ユーザの認証
|
||||
Webアプリケーションを開発する過程で、ユーザ認証は開発者がよくぶつかる問題です。ユーザのログイン、サインアップ、ログアウト等といった操作で、一般的な認証は3つの方面の認証に分けることができます
|
||||
|
||||
- HTTP BasicとHTTP Digest認証
|
||||
- サードパーティ認証:QQ、weibo、doubian、OPENID、google、github、facebookおよびtwitterなどです
|
||||
- カスタム定義のユーザログイン、サインアップ、ログアウトは一般的にsession、cookie認証にもとづいています。
|
||||
|
||||
beegoは現在この3つの方式のどの形式にも対応していません。しかしサードパーティのオープンソースライブラリによって上の3つの方法のユーザ認証を実装することができます。しかし後々beegoは前者2つの認証を一つ一つ実装するかもしれません。
|
||||
|
||||
## HTTP BasicとHTTP Digest認証
|
||||
この2つの認証はいくつかのアプリケーションが採用している比較的簡単な認証です。現在すでにオープンソースのサードパーティライブラリでこの2つの認証をサポートしています;
|
||||
|
||||
github.com/abbot/go-http-auth
|
||||
|
||||
下のコードはこれらのライブラリをどのようにbeegoに導入するかを示しています:
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/abbot/go-http-auth"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
func Secret(user, realm string) string {
|
||||
if user == "john" {
|
||||
// password is "hello"
|
||||
return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type MainController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *MainController) Prepare() {
|
||||
a := auth.NewBasicAuthenticator("example.com", Secret)
|
||||
if username := a.CheckAuth(this.Ctx.Request); username == "" {
|
||||
a.RequireAuth(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *MainController) Get() {
|
||||
this.Data["Username"] = "astaxie"
|
||||
this.Data["Email"] = "astaxie@gmail.com"
|
||||
this.TplNames = "index.tpl"
|
||||
}
|
||||
|
||||
上のコードはbeegoのprepare関数を利用しています。正常なロジックを実行する前に認証関数をコールすることで、非常に簡単にhttp authを実装しています。digest認証も同様の原理です。
|
||||
|
||||
## oauthとoauth2の認証
|
||||
oauthとoauth2は現在比較的流行している二種類の認証方式です。サードパーティでちょうどこの認証を実装しているライブラリがあるのですが、国外で実装されたもので、QQ、weiboといった中国国内のアプリケーション認証はありません。
|
||||
|
||||
github.com/bradrydzewski/go.auth
|
||||
|
||||
下のコードはどのようにしてこのライブラリをbeegoの中に導入しoauth認証を実装するか示しています。ここではgithubを例にしています:
|
||||
|
||||
1. ルーティングを2本追加
|
||||
|
||||
beego.RegisterController("/auth/login", &controllers.GithubController{})
|
||||
beego.RegisterController("/mainpage", &controllers.PageController{})
|
||||
|
||||
2. 次にGithubControllerログインの画面を処理:
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/bradrydzewski/go.auth"
|
||||
)
|
||||
|
||||
const (
|
||||
githubClientKey = "a0864ea791ce7e7bd0df"
|
||||
githubSecretKey = "a0ec09a647a688a64a28f6190b5a0d2705df56ca"
|
||||
)
|
||||
|
||||
type GithubController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *GithubController) Get() {
|
||||
// set the auth parameters
|
||||
auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV")
|
||||
auth.Config.LoginSuccessRedirect = "/mainpage"
|
||||
auth.Config.CookieSecure = false
|
||||
|
||||
githubHandler := auth.Github(githubClientKey, githubSecretKey)
|
||||
|
||||
githubHandler.ServeHTTP(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
}
|
||||
|
||||
|
||||
3. ログインに成功した後のページ画面を処理
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/bradrydzewski/go.auth"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type PageController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *PageController) Get() {
|
||||
// set the auth parameters
|
||||
auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV")
|
||||
auth.Config.LoginSuccessRedirect = "/mainpage"
|
||||
auth.Config.CookieSecure = false
|
||||
|
||||
user, err := auth.GetUserCookie(this.Ctx.Request)
|
||||
|
||||
//if no active user session then authorize user
|
||||
if err != nil || user.Id() == "" {
|
||||
http.Redirect(this.Ctx.ResponseWriter, this.Ctx.Request, auth.Config.LoginRedirect, http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
//else, add the user to the URL and continue
|
||||
this.Ctx.Request.URL.User = url.User(user.Id())
|
||||
this.Data["pic"] = user.Picture()
|
||||
this.Data["id"] = user.Id()
|
||||
this.Data["name"] = user.Name()
|
||||
this.TplNames = "home.tpl"
|
||||
}
|
||||
|
||||
全体の流れは以下のようになります。まずブラウザを開いてアドレスを入力します:
|
||||
|
||||

|
||||
|
||||
図14.4 ログインボタンを持つトップページの表示
|
||||
|
||||
次にリンクをクリックすると以下のようなインターフェースが現れます:
|
||||
|
||||

|
||||
|
||||
図14.5 ログインボタンをクリックしてgithubの権限取得ページを表示
|
||||
|
||||
Authorize appをクリックすると以下のようなインターフェースが現れます:
|
||||
|
||||

|
||||
|
||||
図14.6 権限取得にログインした後表示される取得済みのgithub情報のページ
|
||||
|
||||
## カスタム定義認証
|
||||
カスタム定義の認証は一般的にはsessionと組み合わせて検証されます。以下のコードはあるbeegoのオープンソースブログに基づいています:
|
||||
|
||||
|
||||
//ログイン処理
|
||||
func (this *LoginController) Post() {
|
||||
this.TplNames = "login.tpl"
|
||||
this.Ctx.Request.ParseForm()
|
||||
username := this.Ctx.Request.Form.Get("username")
|
||||
password := this.Ctx.Request.Form.Get("password")
|
||||
md5Password := md5.New()
|
||||
io.WriteString(md5Password, password)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
fmt.Fprintf(buffer, "%x", md5Password.Sum(nil))
|
||||
newPass := buffer.String()
|
||||
|
||||
now := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
userInfo := models.GetUserInfo(username)
|
||||
if userInfo.Password == newPass {
|
||||
var users models.User
|
||||
users.Last_logintime = now
|
||||
models.UpdateUserInfo(users)
|
||||
|
||||
//ログイン成功でsessionを設定
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess.Set("uid", userInfo.Id)
|
||||
sess.Set("uname", userInfo.Username)
|
||||
|
||||
this.Ctx.Redirect(302, "/")
|
||||
}
|
||||
}
|
||||
|
||||
//サインアップ処理
|
||||
func (this *RegController) Post() {
|
||||
this.TplNames = "reg.tpl"
|
||||
this.Ctx.Request.ParseForm()
|
||||
username := this.Ctx.Request.Form.Get("username")
|
||||
password := this.Ctx.Request.Form.Get("password")
|
||||
usererr := checkUsername(username)
|
||||
fmt.Println(usererr)
|
||||
if usererr == false {
|
||||
this.Data["UsernameErr"] = "Username error, Please to again"
|
||||
return
|
||||
}
|
||||
|
||||
passerr := checkPassword(password)
|
||||
if passerr == false {
|
||||
this.Data["PasswordErr"] = "Password error, Please to again"
|
||||
return
|
||||
}
|
||||
|
||||
md5Password := md5.New()
|
||||
io.WriteString(md5Password, password)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
fmt.Fprintf(buffer, "%x", md5Password.Sum(nil))
|
||||
newPass := buffer.String()
|
||||
|
||||
now := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
userInfo := models.GetUserInfo(username)
|
||||
|
||||
if userInfo.Username == "" {
|
||||
var users models.User
|
||||
users.Username = username
|
||||
users.Password = newPass
|
||||
users.Created = now
|
||||
users.Last_logintime = now
|
||||
models.AddUser(users)
|
||||
|
||||
//ログイン成功でsessionを設定
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess.Set("uid", userInfo.Id)
|
||||
sess.Set("uname", userInfo.Username)
|
||||
this.Ctx.Redirect(302, "/")
|
||||
} else {
|
||||
this.Data["UsernameErr"] = "User already exists"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func checkPassword(password string) (b bool) {
|
||||
if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", password); !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func checkUsername(username string) (b bool) {
|
||||
if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", username); !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
ユーザのログインとサインアップがあって、その他のモジュールでも以下のようにユーザがログインしているかどうかの判断を追加することができます:
|
||||
|
||||
func (this *AddBlogController) Prepare() {
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess_uid := sess.Get("userid")
|
||||
sess_username := sess.Get("username")
|
||||
if sess_uid == nil {
|
||||
this.Ctx.Redirect(302, "/admin/login")
|
||||
return
|
||||
}
|
||||
this.Data["Username"] = sess_username
|
||||
}
|
||||
|
||||
## links
|
||||
* [目次](<preface.md>)
|
||||
* 前へ: [フォームおよび検証のサポート](<14.3.md>)
|
||||
* 次へ: [多言語サポート](<14.5.md>)
|
||||
# 14.4 ユーザの認証
|
||||
Webアプリケーションを開発する過程で、ユーザ認証は開発者がよくぶつかる問題です。ユーザのログイン、サインアップ、ログアウト等といった操作で、一般的な認証は3つの方面の認証に分けることができます
|
||||
|
||||
- HTTP BasicとHTTP Digest認証
|
||||
- サードパーティ認証:QQ、weibo、doubian、OPENID、google、GitHub、facebookおよびtwitterなどです
|
||||
- カスタム定義のユーザログイン、サインアップ、ログアウトは一般的にsession、cookie認証にもとづいています。
|
||||
|
||||
beegoは現在この3つの方式のどの形式にも対応していません。しかしサードパーティのオープンソースライブラリによって上の3つの方法のユーザ認証を実装することができます。しかし後々beegoは前者2つの認証を一つ一つ実装するかもしれません。
|
||||
|
||||
## HTTP BasicとHTTP Digest認証
|
||||
この2つの認証はいくつかのアプリケーションが採用している比較的簡単な認証です。現在すでにオープンソースのサードパーティライブラリでこの2つの認証をサポートしています;
|
||||
|
||||
github.com/abbot/go-http-auth
|
||||
|
||||
下のコードはこれらのライブラリをどのようにbeegoに導入するかを示しています:
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/abbot/go-http-auth"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
func Secret(user, realm string) string {
|
||||
if user == "john" {
|
||||
// password is "hello"
|
||||
return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type MainController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *MainController) Prepare() {
|
||||
a := auth.NewBasicAuthenticator("example.com", Secret)
|
||||
if username := a.CheckAuth(this.Ctx.Request); username == "" {
|
||||
a.RequireAuth(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *MainController) Get() {
|
||||
this.Data["Username"] = "astaxie"
|
||||
this.Data["Email"] = "astaxie@gmail.com"
|
||||
this.TplNames = "index.tpl"
|
||||
}
|
||||
|
||||
上のコードはbeegoのprepare関数を利用しています。正常なロジックを実行する前に認証関数をコールすることで、非常に簡単にhttp authを実装しています。digest認証も同様の原理です。
|
||||
|
||||
## oauthとoauth2の認証
|
||||
oauthとoauth2は現在比較的流行している二種類の認証方式です。サードパーティでちょうどこの認証を実装しているライブラリがあるのですが、国外で実装されたもので、QQ、weiboといった中国国内のアプリケーション認証はありません。
|
||||
|
||||
github.com/bradrydzewski/go.auth
|
||||
|
||||
下のコードはどのようにしてこのライブラリをbeegoの中に導入しoauth認証を実装するか示しています。ここではGitHubを例にしています:
|
||||
|
||||
1. ルーティングを2本追加
|
||||
|
||||
beego.RegisterController("/auth/login", &controllers.GithubController{})
|
||||
beego.RegisterController("/mainpage", &controllers.PageController{})
|
||||
|
||||
2. 次にGithubControllerログインの画面を処理:
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/bradrydzewski/go.auth"
|
||||
)
|
||||
|
||||
const (
|
||||
githubClientKey = "a0864ea791ce7e7bd0df"
|
||||
githubSecretKey = "a0ec09a647a688a64a28f6190b5a0d2705df56ca"
|
||||
)
|
||||
|
||||
type GithubController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *GithubController) Get() {
|
||||
// set the auth parameters
|
||||
auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV")
|
||||
auth.Config.LoginSuccessRedirect = "/mainpage"
|
||||
auth.Config.CookieSecure = false
|
||||
|
||||
githubHandler := auth.Github(githubClientKey, githubSecretKey)
|
||||
|
||||
githubHandler.ServeHTTP(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
}
|
||||
|
||||
|
||||
3. ログインに成功した後のページ画面を処理
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/bradrydzewski/go.auth"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type PageController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *PageController) Get() {
|
||||
// set the auth parameters
|
||||
auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV")
|
||||
auth.Config.LoginSuccessRedirect = "/mainpage"
|
||||
auth.Config.CookieSecure = false
|
||||
|
||||
user, err := auth.GetUserCookie(this.Ctx.Request)
|
||||
|
||||
//if no active user session then authorize user
|
||||
if err != nil || user.Id() == "" {
|
||||
http.Redirect(this.Ctx.ResponseWriter, this.Ctx.Request, auth.Config.LoginRedirect, http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
//else, add the user to the URL and continue
|
||||
this.Ctx.Request.URL.User = url.User(user.Id())
|
||||
this.Data["pic"] = user.Picture()
|
||||
this.Data["id"] = user.Id()
|
||||
this.Data["name"] = user.Name()
|
||||
this.TplNames = "home.tpl"
|
||||
}
|
||||
|
||||
全体の流れは以下のようになります。まずブラウザを開いてアドレスを入力します:
|
||||
|
||||

|
||||
|
||||
図14.4 ログインボタンを持つトップページの表示
|
||||
|
||||
次にリンクをクリックすると以下のようなインターフェースが現れます:
|
||||
|
||||

|
||||
|
||||
図14.5 ログインボタンをクリックしてGitHubの権限取得ページを表示
|
||||
|
||||
Authorize appをクリックすると以下のようなインターフェースが現れます:
|
||||
|
||||

|
||||
|
||||
図14.6 権限取得にログインした後表示される取得済みのGitHub情報のページ
|
||||
|
||||
## カスタム定義認証
|
||||
カスタム定義の認証は一般的にはsessionと組み合わせて検証されます。以下のコードはあるbeegoのオープンソースブログに基づいています:
|
||||
|
||||
|
||||
//ログイン処理
|
||||
func (this *LoginController) Post() {
|
||||
this.TplNames = "login.tpl"
|
||||
this.Ctx.Request.ParseForm()
|
||||
username := this.Ctx.Request.Form.Get("username")
|
||||
password := this.Ctx.Request.Form.Get("password")
|
||||
md5Password := md5.New()
|
||||
io.WriteString(md5Password, password)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
fmt.Fprintf(buffer, "%x", md5Password.Sum(nil))
|
||||
newPass := buffer.String()
|
||||
|
||||
now := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
userInfo := models.GetUserInfo(username)
|
||||
if userInfo.Password == newPass {
|
||||
var users models.User
|
||||
users.Last_logintime = now
|
||||
models.UpdateUserInfo(users)
|
||||
|
||||
//ログイン成功でsessionを設定
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess.Set("uid", userInfo.Id)
|
||||
sess.Set("uname", userInfo.Username)
|
||||
|
||||
this.Ctx.Redirect(302, "/")
|
||||
}
|
||||
}
|
||||
|
||||
//サインアップ処理
|
||||
func (this *RegController) Post() {
|
||||
this.TplNames = "reg.tpl"
|
||||
this.Ctx.Request.ParseForm()
|
||||
username := this.Ctx.Request.Form.Get("username")
|
||||
password := this.Ctx.Request.Form.Get("password")
|
||||
usererr := checkUsername(username)
|
||||
fmt.Println(usererr)
|
||||
if usererr == false {
|
||||
this.Data["UsernameErr"] = "Username error, Please to again"
|
||||
return
|
||||
}
|
||||
|
||||
passerr := checkPassword(password)
|
||||
if passerr == false {
|
||||
this.Data["PasswordErr"] = "Password error, Please to again"
|
||||
return
|
||||
}
|
||||
|
||||
md5Password := md5.New()
|
||||
io.WriteString(md5Password, password)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
fmt.Fprintf(buffer, "%x", md5Password.Sum(nil))
|
||||
newPass := buffer.String()
|
||||
|
||||
now := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
userInfo := models.GetUserInfo(username)
|
||||
|
||||
if userInfo.Username == "" {
|
||||
var users models.User
|
||||
users.Username = username
|
||||
users.Password = newPass
|
||||
users.Created = now
|
||||
users.Last_logintime = now
|
||||
models.AddUser(users)
|
||||
|
||||
//ログイン成功でsessionを設定
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess.Set("uid", userInfo.Id)
|
||||
sess.Set("uname", userInfo.Username)
|
||||
this.Ctx.Redirect(302, "/")
|
||||
} else {
|
||||
this.Data["UsernameErr"] = "User already exists"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func checkPassword(password string) (b bool) {
|
||||
if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", password); !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func checkUsername(username string) (b bool) {
|
||||
if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", username); !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
ユーザのログインとサインアップがあって、その他のモジュールでも以下のようにユーザがログインしているかどうかの判断を追加することができます:
|
||||
|
||||
func (this *AddBlogController) Prepare() {
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess_uid := sess.Get("userid")
|
||||
sess_username := sess.Get("username")
|
||||
if sess_uid == nil {
|
||||
this.Ctx.Redirect(302, "/admin/login")
|
||||
return
|
||||
}
|
||||
this.Data["Username"] = sess_username
|
||||
}
|
||||
|
||||
## links
|
||||
* [目次](<preface.md>)
|
||||
* 前へ: [フォームおよび検証のサポート](<14.3.md>)
|
||||
* 次へ: [多言語サポート](<14.5.md>)
|
||||
|
||||
@@ -91,7 +91,7 @@ Para compilar nossa aplicação, deveremos alterar o código fonte de diretório
|
||||
|
||||
## Instalando pacotes remotamente
|
||||
|
||||
Go possui uma ferramenta para utilizar pacotes remotos, chamada `go get`. Ela é suportada por grandes comunidades de código aberto, incluindo: Github, Google Code, Bitbucket e Launchpad.
|
||||
Go possui uma ferramenta para utilizar pacotes remotos, chamada `go get`. Ela é suportada por grandes comunidades de código aberto, incluindo: GitHub, Google Code, Bitbucket e Launchpad.
|
||||
|
||||
go get github.com/astaxie/beedb
|
||||
|
||||
|
||||
@@ -56,10 +56,10 @@ Normalmente, usamos o comando `gofmt -w` ao invés de simplesmente `go fmt`. A d
|
||||
|
||||
## go get
|
||||
|
||||
Esse comando serve para obtenção de pacotes remotamente. Até o momento, o comando suporta BitBucket, Github, Google Code e Launchpad. De fato, duas coisas ocorrem quando esse comando é executado. Primeiramente é feito o download do código fonte e então é executado o comando `go install`. Antes de utilizar esse comando, tenha certeza de possuir instalados as seguintes ferramentas.
|
||||
Esse comando serve para obtenção de pacotes remotamente. Até o momento, o comando suporta BitBucket, GitHub, Google Code e Launchpad. De fato, duas coisas ocorrem quando esse comando é executado. Primeiramente é feito o download do código fonte e então é executado o comando `go install`. Antes de utilizar esse comando, tenha certeza de possuir instalados as seguintes ferramentas.
|
||||
|
||||
BitBucket (Mercurial Git)
|
||||
Github (git)
|
||||
GitHub (git)
|
||||
Google Code (Git, Mercurial, Subversion)
|
||||
Launchpad (Bazaar)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ When our web application is finally production ready, what are the steps necessa
|
||||
|
||||
## Daemons
|
||||
|
||||
Currently, Go programs cannot cannot be run as daemon processes (for additional information, see the open issue on github [here](https://github.com/golang/go/issues/227)). It's difficult to fork existing threads in Go because there is no way of ensuring a consistent state in all threads that have been used.
|
||||
Currently, Go programs cannot cannot be run as daemon processes (for additional information, see the open issue on GitHub [here](https://github.com/golang/go/issues/227)). It's difficult to fork existing threads in Go because there is no way of ensuring a consistent state in all threads that have been used.
|
||||
|
||||
We can, however, see many attempts at implementing daemons online, such as in the two following ways;
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ OAuth and OAuth 2 are currently two of the most popular authentication methods.
|
||||
|
||||
github.com/bradrydzewski/go.auth
|
||||
|
||||
The code below demonstrates how to use this library to implement OAuth authentication in Beego using our Github credentials:
|
||||
The code below demonstrates how to use this library to implement OAuth authentication in Beego using our GitHub credentials:
|
||||
|
||||
1. Let's add some routes
|
||||
|
||||
@@ -147,7 +147,7 @@ After clicking "Authorize app", the following screen appears:
|
||||
|
||||

|
||||
|
||||
Figure 14.6 authorized Github information gets displayed after the login page
|
||||
Figure 14.6 authorized GitHub information gets displayed after the login page
|
||||
|
||||
## Custom authentication
|
||||
|
||||
|
||||
@@ -90,13 +90,13 @@ func main() {
|
||||
|
||||
## Установка удаленных пакетов
|
||||
|
||||
В Go есть инструмент для установки удаленных пакетов - команда `go get`. Он поддерживает работу с большинством сообществ Open Source, включая Github, Google Code, BitBucket и Launchpad.
|
||||
В Go есть инструмент для установки удаленных пакетов - команда `go get`. Он поддерживает работу с большинством сообществ Open Source, включая GitHub, Google Code, BitBucket и Launchpad.
|
||||
|
||||
go get github.com/astaxie/beedb
|
||||
|
||||
Чтобы обновить Ваши удаленные пакеты, выполните `go get -u …`, при этом установятся все дополнительные зависимости .
|
||||
|
||||
Для разных Open Source платформ потребуются различные системы контроля версий, например `git` для Github и `hg` для Google Code. Поэтому Вам нужно установить соответствующие системы контроля версий перед использованием `go get`.
|
||||
Для разных Open Source платформ потребуются различные системы контроля версий, например `git` для GitHub и `hg` для Google Code. Поэтому Вам нужно установить соответствующие системы контроля версий перед использованием `go get`.
|
||||
|
||||
После выполнения команд выше структура каталогов будет выглядеть следующим образом:
|
||||
|
||||
|
||||
@@ -55,10 +55,10 @@
|
||||
|
||||
## go get
|
||||
|
||||
Эта команда служит для установки удаленных пакетов. На данный момент она поддерживает BitBucket, Github, Google Code и Launchpad. При запуске этой команды происходят вещи: первая - Go скачивает исходники пакетов, вторая - исполняется `go install`. Перед использованием этой команды убедитесь, что у Вас установлены соответствующие инструменты:
|
||||
Эта команда служит для установки удаленных пакетов. На данный момент она поддерживает BitBucket, GitHub, Google Code и Launchpad. При запуске этой команды происходят вещи: первая - Go скачивает исходники пакетов, вторая - исполняется `go install`. Перед использованием этой команды убедитесь, что у Вас установлены соответствующие инструменты:
|
||||
|
||||
BitBucket (Mercurial Git)
|
||||
Github (git)
|
||||
GitHub (git)
|
||||
Google Code (Git, Mercurial, Subversion)
|
||||
Launchpad (Bazaar)
|
||||
|
||||
|
||||
@@ -327,7 +327,7 @@ Eclipse также является отличным инструментом р
|
||||
2. Скачайте [goclipse](https://code.google.com/p/goclipse/) [http://code.google.com/p/goclipse/wiki/InstallationInstructions](http://code.google.com/p/goclipse/wiki/InstallationInstructions).
|
||||
3. Скачайте gocode:
|
||||
|
||||
gocode на Github:
|
||||
gocode на GitHub:
|
||||
|
||||
https://github.com/nsf/gocode
|
||||
|
||||
|
||||
@@ -96,13 +96,13 @@ func main() {
|
||||
|
||||
## การติดตั้ง package เพิ่มเติม
|
||||
|
||||
Go มาพร้อมกับเครื่องมือที่ใช้ในการติดตั้ง package เสริม ซึ่งได้แก่คำสั่งที่เรียกว่า `go get` โดยรองรับ opensource comunity เกือบทุกที่ รวมถึง Github, Google Code, BitBucket และ Launchpad
|
||||
Go มาพร้อมกับเครื่องมือที่ใช้ในการติดตั้ง package เสริม ซึ่งได้แก่คำสั่งที่เรียกว่า `go get` โดยรองรับ opensource comunity เกือบทุกที่ รวมถึง GitHub, Google Code, BitBucket และ Launchpad
|
||||
|
||||
go get github.com/astaxie/beedb
|
||||
|
||||
โดยสามารถใช้ `go get -u …` ในการอัพเดท package และยังสามารถติดตั้ง package ที่เป็น dependency ให้โดยอัตโนมัติด้วย
|
||||
|
||||
ซึ่งเครื่องมือนี้จะใช้ version control ที่แตกต่างกันสำหรับแต่ละ opensource platform ยกตัวอย่างเช่น จะใช้่่ `git` สำหรับ Github และใช้ `hg` สำหรับ Google Code ดังนั้นเราจำเป็นที่จะต้องติดตั้งเครื่องมือ version control เหล่านี้ก่อนที่เราจะใช้ `go get` ได้
|
||||
ซึ่งเครื่องมือนี้จะใช้ version control ที่แตกต่างกันสำหรับแต่ละ opensource platform ยกตัวอย่างเช่น จะใช้่่ `git` สำหรับ GitHub และใช้ `hg` สำหรับ Google Code ดังนั้นเราจำเป็นที่จะต้องติดตั้งเครื่องมือ version control เหล่านี้ก่อนที่เราจะใช้ `go get` ได้
|
||||
|
||||
หลังจากที่รันคำสั่งที่กล่าวมาแล้ว โครงสร้างไดเร็คทอรีควรมีหน้าตาดังนี้
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
DIR.test(.exe) // สร้างจากคำสั่ง go test -c
|
||||
MAINFILE(.exe) // สร้างจากคำสั่ง go build MAINFILE.go
|
||||
|
||||
โดยปรกติผมจะใช้คำสั่งนี้เพื่อลบไฟล์ที่ไม่ต้องการก่อนที่จะอัพโหลดโปรเจ็คไปที่ Github ซึ่งไฟล์เหล่านี้มีประโยชน์ในการทำงานบนเครื่อง แต่ไม่ได้มีประโยชน์กับ version control
|
||||
โดยปรกติผมจะใช้คำสั่งนี้เพื่อลบไฟล์ที่ไม่ต้องการก่อนที่จะอัพโหลดโปรเจ็คไปที่ GitHub ซึ่งไฟล์เหล่านี้มีประโยชน์ในการทำงานบนเครื่อง แต่ไม่ได้มีประโยชน์กับ version control
|
||||
|
||||
## go fmt และ gofmt
|
||||
|
||||
@@ -56,10 +56,10 @@
|
||||
|
||||
## go get
|
||||
|
||||
คำสั่งนี้จะเป็นการดึง package มาใช้งานจากเครื่องอื่น โดยตั้งแต่ต้นนั้นจะ support การดึงมาจาก BitBucket, Github, Google Code และ Launchpad โดยจะเกิดการทำงานสองอย่างขึ้นจากการสั่งคำสั่งนี้ อย่างแรกคือ Go จะดาวน์โหลด source code มา เสร็จแล้วจะสั่ง `go install` ให้เองเลย แต่ก่อนที่เราจะใช้คำสั่งนี้ กรุณาตรวจสอบให้มั่นใจว่ามีการติดตั้งเครื่องมือที่เกี่ยวข้องไว้ก่อนแล้ว ดังนี้
|
||||
คำสั่งนี้จะเป็นการดึง package มาใช้งานจากเครื่องอื่น โดยตั้งแต่ต้นนั้นจะ support การดึงมาจาก BitBucket, GitHub, Google Code และ Launchpad โดยจะเกิดการทำงานสองอย่างขึ้นจากการสั่งคำสั่งนี้ อย่างแรกคือ Go จะดาวน์โหลด source code มา เสร็จแล้วจะสั่ง `go install` ให้เองเลย แต่ก่อนที่เราจะใช้คำสั่งนี้ กรุณาตรวจสอบให้มั่นใจว่ามีการติดตั้งเครื่องมือที่เกี่ยวข้องไว้ก่อนแล้ว ดังนี้
|
||||
|
||||
BitBucket (Mercurial Git)
|
||||
Github (git)
|
||||
GitHub (git)
|
||||
Google Code (Git, Mercurial, Subversion)
|
||||
Launchpad (Bazaar)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ To mitigate all the problems that Google faced with current tools, they wrote a
|
||||
|
||||
Go was designed with concurrency in mind, please note that parallelism != concurrency, there is an [amazing post](https://blog.golang.org/concurrency-is-not-parallelism) by Rob Pike on the [golang blog](https://blog.golang.org/), you will find it there, it is worth a read.
|
||||
|
||||
Another very important change that is the concept of `GOPATH`. Gone are the days when you had to create a folder called `code` and then create workspaces for eclipse and what not. Now you have to keep one folder tree for go code which will be updated by the package manager automatically. It is also recommended to create folders with either a custom domain or the github domain, for example I created a task manager using golang so I created a set of folders
|
||||
Another very important change that is the concept of `GOPATH`. Gone are the days when you had to create a folder called `code` and then create workspaces for eclipse and what not. Now you have to keep one folder tree for go code which will be updated by the package manager automatically. It is also recommended to create folders with either a custom domain or the GitHub domain, for example I created a task manager using golang so I created a set of folders
|
||||
`~/go/src/github.com/thewhitetulip/Tasks`
|
||||
|
||||
**Note:** In *nix systems `~` stands for home directory, which is the windows equivalent of `C:\\Users\\username`.
|
||||
|
||||
@@ -4,7 +4,7 @@ When our web application is finally production ready, what are the steps necessa
|
||||
|
||||
## Daemons
|
||||
|
||||
Currently, Go programs cannot be run as daemon processes (for additional information, see the open issue on github [here](https://github.com/golang/go/issues/227)). It's difficult to fork existing threads in Go because there is no way of ensuring a consistent state in all threads that have been used.
|
||||
Currently, Go programs cannot be run as daemon processes (for additional information, see the open issue on GitHub [here](https://github.com/golang/go/issues/227)). It's difficult to fork existing threads in Go because there is no way of ensuring a consistent state in all threads that have been used.
|
||||
|
||||
We can, however, see many attempts at implementing daemons online, such as in the two following ways;
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ OAuth and OAuth 2 are currently two of the most popular authentication methods.
|
||||
|
||||
github.com/bradrydzewski/go.auth
|
||||
|
||||
The code below demonstrates how to use this library to implement OAuth authentication in Beego using our Github credentials:
|
||||
The code below demonstrates how to use this library to implement OAuth authentication in Beego using our GitHub credentials:
|
||||
|
||||
1. Let's add some routes
|
||||
|
||||
@@ -147,7 +147,7 @@ After clicking "Authorize app", the following screen appears:
|
||||
|
||||

|
||||
|
||||
Figure 14.6 authorized Github information gets displayed after the login page
|
||||
Figure 14.6 authorized GitHub information gets displayed after the login page
|
||||
|
||||
## Custom authentication
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ Uygulamyı derlemek için, `$GOPATH/src/mathapp` dizinine geçip, `go install` k
|
||||
|
||||
## Üçüncü-parti paketleri kurmak
|
||||
|
||||
Üçüncü-parti paketleri kurmak için `go get` komutunu kullanabilirsiniz. Bir çok açık-kaynak platformu destekliyor; Github, Google Code, BitBucket, ve Launchpad.
|
||||
Üçüncü-parti paketleri kurmak için `go get` komutunu kullanabilirsiniz. Bir çok açık-kaynak platformu destekliyor; GitHub, Google Code, BitBucket, ve Launchpad.
|
||||
|
||||
go get github.com/astaxie/beedb
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ Derleyici tarafından oluşturulmuş aşağıdaki dosyaları temizler:
|
||||
DIR.test(.exe) // go test -c tarafından oluşturulmuş
|
||||
MAINFILE(.exe) // go build MAINFILE.go tarafından oluşturulmuş
|
||||
|
||||
Projelerimi Github'a göndermeden önce genellikle bu komutu çalıştırırım. Yereldeki testler için önemli, ama sürüm takip için gereksiz dosyalar.
|
||||
Projelerimi GitHub'a göndermeden önce genellikle bu komutu çalıştırırım. Yereldeki testler için önemli, ama sürüm takip için gereksiz dosyalar.
|
||||
|
||||
## go fmt
|
||||
|
||||
@@ -56,10 +56,10 @@ Projelerimi Github'a göndermeden önce genellikle bu komutu çalıştırırım.
|
||||
|
||||
## go get
|
||||
|
||||
Bu komut üçüncü parti paketleri almanızı sağlar. Şuanda; BitBucket, Github, Google Code ve Launchpad desteği sunuyor. Bu komutu çalıştırdığımızda iki şey yapılıyor. Birincisi Go kaynak kodunu indiriyor, ikinci olarakta `go install` komutunu çalıştırıyor. Bu komutu çalıştırmadan önce, gerekli araçları kurduğunuzdan emin olun.
|
||||
Bu komut üçüncü parti paketleri almanızı sağlar. Şuanda; BitBucket, GitHub, Google Code ve Launchpad desteği sunuyor. Bu komutu çalıştırdığımızda iki şey yapılıyor. Birincisi Go kaynak kodunu indiriyor, ikinci olarakta `go install` komutunu çalıştırıyor. Bu komutu çalıştırmadan önce, gerekli araçları kurduğunuzdan emin olun.
|
||||
|
||||
BitBucket (Mercurial Git)
|
||||
Github (git)
|
||||
GitHub (git)
|
||||
Google Code (Git, Mercurial, Subversion)
|
||||
Launchpad (Bazaar)
|
||||
|
||||
|
||||
@@ -315,7 +315,7 @@ Eclipse'de çok tutulan geliştirme araçlarındandır. Size Eclipse ile nasıl
|
||||
[http://code.google.com/p/goclipse/wiki/InstallationInstructions](http://code.google.com/p/goclipse/wiki/InstallationInstructions)
|
||||
3. gocode indirin
|
||||
|
||||
Github'dan gocode.
|
||||
GitHub'dan gocode.
|
||||
|
||||
https://github.com/nsf/gocode
|
||||
|
||||
|
||||
382
zh-tw/01.2.md
382
zh-tw/01.2.md
@@ -1,191 +1,191 @@
|
||||
# 1.2 GOPATH 與工作空間
|
||||
|
||||
前面我們在安裝 Go 的時候看到需要設定 GOPATH 變數,Go 從 1.1 版本到 1.7 必須設定這個變數,而且不能和 Go 的安裝目錄一樣,這個目錄用來存放 Go 原始碼,Go 的可執行檔案,以及相應的編譯之後的套件檔案。所以這個目錄下面有三個子目錄:src、bin、pkg
|
||||
|
||||
從 go 1.8 開始,GOPATH 環境變數現在有一個預設值,如果它沒有被設定。 它在 Unix 上預設為$HOME/go,在 Windows 上預設為%USERPROFILE%/go。
|
||||
## GOPATH 設定
|
||||
go 命令依賴一個重要的環境變數:$GOPATH
|
||||
|
||||
Windows 系統中環境變數的形式為`%GOPATH%`,本書主要使用 Unix 形式,Windows 使用者請自行替換。
|
||||
|
||||
*(注:這個不是 Go 安裝目錄。下面以筆者的工作目錄為範例,如果你想不一樣請把 GOPATH 替換成你的工作目錄。)*
|
||||
|
||||
在類別 Unix 環境下大概這樣設定:
|
||||
|
||||
```sh
|
||||
export GOPATH=/home/apple/mygo
|
||||
```
|
||||
為了方便,應該建立以上資料夾,並且上一行加入到 `.bashrc` 或者 `.zshrc` 或者自己的 `sh` 的配置檔案中。
|
||||
|
||||
Windows 設定如下,建立一個環境變數名稱叫做 GOPATH:
|
||||
|
||||
```sh
|
||||
GOPATH=c:\mygo
|
||||
```
|
||||
GOPATH 允許多個目錄,當有多個目錄時,請注意分隔符,多個目錄的時候 Windows 是分號,Linux 系統是冒號,當有多個 GOPATH 時,預設會將 go get 的內容放在第一個目錄下。
|
||||
|
||||
|
||||
以上 $GOPATH 目錄約定有三個子目錄:
|
||||
|
||||
- src 存放原始碼(比如:.go .c .h .s 等)
|
||||
- pkg 編譯後生成的檔案(比如:.a)
|
||||
- bin 編譯後生成的可執行檔案(為了方便,可以把此目錄加入到 $PATH 變數中,如果有多個 gopath,那麼使用`${GOPATH//://bin:}/bin`新增所有的 bin 目錄)
|
||||
|
||||
以後我所有的例子都是以 mygo 作為我的 gopath 目錄
|
||||
|
||||
|
||||
## 程式碼目錄結構規劃
|
||||
GOPATH 下的 src 目錄就是接下來開發程式的主要目錄,所有的原始碼都是放在這個目錄下面,那麼一般我們的做法就是一個目錄一個專案,例如: $GOPATH/src/mymath 表示 mymath 這個套件或者可執行應用,這個根據 package 是 main 還是其他來決定,main 的話就是可執行應用,其他的話就是套件,這個會在後續詳細介紹 package。
|
||||
|
||||
|
||||
所以當建立應用或者一個程式碼套件時都是在 src 目錄下建立一個資料夾,資料夾名稱一般是程式碼套件名稱,當然也允許多階層目錄,例如在 src 下面建立了目錄$GOPATH/src/github.com/astaxie/beedb 那麼這個套件路徑就是"github.com/astaxie/beedb",套件名稱是最後一個目錄 beedb
|
||||
|
||||
|
||||
下面我就以 mymath 為例來講述如何編寫套件,執行如下程式碼
|
||||
|
||||
```sh
|
||||
cd $GOPATH/src
|
||||
mkdir mymath
|
||||
```
|
||||
|
||||
建立檔案 sqrt.go,內容如下
|
||||
```go
|
||||
// $GOPATH/src/mymath/sqrt.go 原始碼如下:
|
||||
package mymath
|
||||
|
||||
func Sqrt(x float64) float64 {
|
||||
z := 0.0
|
||||
for i := 0; i < 1000; i++ {
|
||||
z -= (z*z - x) / (2 * x)
|
||||
}
|
||||
return z
|
||||
}
|
||||
```
|
||||
這樣我的套件目錄和程式碼已經建立完畢,注意:一般建議 package 的名稱和目錄名保持一致
|
||||
|
||||
## 編譯應用
|
||||
上面我們已經建立了自己的套件,如何進行編譯安裝呢?有兩種方式可以進行安裝
|
||||
|
||||
1、只要進入對應的套件目錄,然後執行`go install`,就可以安裝了
|
||||
|
||||
2、在任意的目錄執行如下程式碼`go install mymath`
|
||||
|
||||
安裝完之後,我們可以進入如下目錄
|
||||
|
||||
```sh
|
||||
cd $GOPATH/pkg/${GOOS}_${GOARCH}
|
||||
//可以看到如下檔案
|
||||
mymath.a
|
||||
```
|
||||
這個.a 檔案是套件,那麼我們如何進行呼叫呢?
|
||||
|
||||
接下來我們建立一個應用程式來呼叫這個套件
|
||||
|
||||
建立套件 mathapp
|
||||
|
||||
```sh
|
||||
cd $GOPATH/src
|
||||
mkdir mathapp
|
||||
cd mathapp
|
||||
vim main.go
|
||||
```
|
||||
|
||||
`$GOPATH/src/mathapp/main.go`原始碼:
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"mymath"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Hello, world. Sqrt(2) = %v\n", mymath.Sqrt(2))
|
||||
}
|
||||
```
|
||||
|
||||
可以看到這個的 package 是`main`,import 裡面呼叫的套件是`mymath`,這個就是相對於`$GOPATH/src`的路徑,如果是多階層目錄,就在 import 裡面引入多階層目錄,如果你有多個 GOPATH,也是一樣,Go 會自動在多個`$GOPATH/src`中尋找。
|
||||
|
||||
如何編譯程式呢?進入該應用目錄,然後執行`go build`,那麼在該目錄下面會產生一個 mathapp 的可執行檔案
|
||||
|
||||
```sh
|
||||
./mathapp
|
||||
```
|
||||
|
||||
輸出如下內容
|
||||
|
||||
```sh
|
||||
Hello, world. Sqrt(2) = 1.414213562373095
|
||||
```
|
||||
|
||||
如何安裝該應用,進入該目錄執行`go install`,那麼在$GOPATH/bin/下增加了一個可執行檔案 mathapp, 還記得前面我們把`$GOPATH/bin`加到我們的 PATH 裡面了,這樣可以在命令列輸入如下命令就可以執行
|
||||
|
||||
```sh
|
||||
mathapp
|
||||
```
|
||||
|
||||
也是輸出如下內容
|
||||
|
||||
Hello, world. Sqrt(2) = 1.414213562373095
|
||||
|
||||
這裡我們展示如何編譯和安裝一個可執行的應用,以及如何設計我們的目錄結構。
|
||||
|
||||
## 取得遠端套件
|
||||
|
||||
go 語言有一個取得遠端套件的工具就是`go get`,目前 go get 支援多數開源社群(例如:github、googlecode、bitbucket、Launchpad)
|
||||
|
||||
go get github.com/astaxie/beedb
|
||||
|
||||
>go get -u 參數可以自動更新套件,而且當 go get 的時候會自動取得該套件依賴的其他第三方套件
|
||||
|
||||
|
||||
透過這個命令可以取得相應的原始碼,對應的開源平臺採用不同的原始碼控制工具,例如 github 採用 git、googlecode 採用 hg,所以要想取得這些原始碼,必須先安裝相應的原始碼控制工具
|
||||
|
||||
透過上面取得的程式碼在我們本地的原始碼相應的程式碼結構如下
|
||||
|
||||
$GOPATH
|
||||
src
|
||||
|--github.com
|
||||
|-astaxie
|
||||
|-beedb
|
||||
pkg
|
||||
|--相應平臺
|
||||
|-github.com
|
||||
|--astaxie
|
||||
|beedb.a
|
||||
|
||||
go get 本質上可以理解為首先第一步是透過原始碼工具 clone 程式碼到 src 下面,然後執行`go install`
|
||||
|
||||
在程式碼中如何使用遠端套件,很簡單的就是和使用本地套件一樣,只要在開頭 import 相應的路徑就可以
|
||||
|
||||
import "github.com/astaxie/beedb"
|
||||
|
||||
## 程式的整體結構
|
||||
透過上面建立的我本地的 mygo 的目錄結構如下所示
|
||||
|
||||
bin/
|
||||
mathapp
|
||||
pkg/
|
||||
平臺名/ 如:darwin_amd64、linux_amd64
|
||||
mymath.a
|
||||
github.com/
|
||||
astaxie/
|
||||
beedb.a
|
||||
src/
|
||||
mathapp
|
||||
main.go
|
||||
mymath/
|
||||
sqrt.go
|
||||
github.com/
|
||||
astaxie/
|
||||
beedb/
|
||||
beedb.go
|
||||
util.go
|
||||
|
||||
從上面的結構我們可以很清晰的看到,bin 目錄下面存的是編譯之後可執行的檔案,pkg 下面存放的是套件,src 下面儲存的是應用原始碼
|
||||
|
||||
|
||||
## links
|
||||
* [目錄](<preface.md>)
|
||||
* 上一節: [安裝 Go](<01.1.md>)
|
||||
* 下一節: [GO 命令](<01.3.md>)
|
||||
# 1.2 GOPATH 與工作空間
|
||||
|
||||
前面我們在安裝 Go 的時候看到需要設定 GOPATH 變數,Go 從 1.1 版本到 1.7 必須設定這個變數,而且不能和 Go 的安裝目錄一樣,這個目錄用來存放 Go 原始碼,Go 的可執行檔案,以及相應的編譯之後的套件檔案。所以這個目錄下面有三個子目錄:src、bin、pkg
|
||||
|
||||
從 go 1.8 開始,GOPATH 環境變數現在有一個預設值,如果它沒有被設定。 它在 Unix 上預設為$HOME/go,在 Windows 上預設為%USERPROFILE%/go。
|
||||
## GOPATH 設定
|
||||
go 命令依賴一個重要的環境變數:$GOPATH
|
||||
|
||||
Windows 系統中環境變數的形式為`%GOPATH%`,本書主要使用 Unix 形式,Windows 使用者請自行替換。
|
||||
|
||||
*(注:這個不是 Go 安裝目錄。下面以筆者的工作目錄為範例,如果你想不一樣請把 GOPATH 替換成你的工作目錄。)*
|
||||
|
||||
在類別 Unix 環境下大概這樣設定:
|
||||
|
||||
```sh
|
||||
export GOPATH=/home/apple/mygo
|
||||
```
|
||||
為了方便,應該建立以上資料夾,並且上一行加入到 `.bashrc` 或者 `.zshrc` 或者自己的 `sh` 的配置檔案中。
|
||||
|
||||
Windows 設定如下,建立一個環境變數名稱叫做 GOPATH:
|
||||
|
||||
```sh
|
||||
GOPATH=c:\mygo
|
||||
```
|
||||
GOPATH 允許多個目錄,當有多個目錄時,請注意分隔符,多個目錄的時候 Windows 是分號,Linux 系統是冒號,當有多個 GOPATH 時,預設會將 go get 的內容放在第一個目錄下。
|
||||
|
||||
|
||||
以上 $GOPATH 目錄約定有三個子目錄:
|
||||
|
||||
- src 存放原始碼(比如:.go .c .h .s 等)
|
||||
- pkg 編譯後生成的檔案(比如:.a)
|
||||
- bin 編譯後生成的可執行檔案(為了方便,可以把此目錄加入到 $PATH 變數中,如果有多個 gopath,那麼使用`${GOPATH//://bin:}/bin`新增所有的 bin 目錄)
|
||||
|
||||
以後我所有的例子都是以 mygo 作為我的 gopath 目錄
|
||||
|
||||
|
||||
## 程式碼目錄結構規劃
|
||||
GOPATH 下的 src 目錄就是接下來開發程式的主要目錄,所有的原始碼都是放在這個目錄下面,那麼一般我們的做法就是一個目錄一個專案,例如: $GOPATH/src/mymath 表示 mymath 這個套件或者可執行應用,這個根據 package 是 main 還是其他來決定,main 的話就是可執行應用,其他的話就是套件,這個會在後續詳細介紹 package。
|
||||
|
||||
|
||||
所以當建立應用或者一個程式碼套件時都是在 src 目錄下建立一個資料夾,資料夾名稱一般是程式碼套件名稱,當然也允許多階層目錄,例如在 src 下面建立了目錄$GOPATH/src/github.com/astaxie/beedb 那麼這個套件路徑就是"github.com/astaxie/beedb",套件名稱是最後一個目錄 beedb
|
||||
|
||||
|
||||
下面我就以 mymath 為例來講述如何編寫套件,執行如下程式碼
|
||||
|
||||
```sh
|
||||
cd $GOPATH/src
|
||||
mkdir mymath
|
||||
```
|
||||
|
||||
建立檔案 sqrt.go,內容如下
|
||||
```go
|
||||
// $GOPATH/src/mymath/sqrt.go 原始碼如下:
|
||||
package mymath
|
||||
|
||||
func Sqrt(x float64) float64 {
|
||||
z := 0.0
|
||||
for i := 0; i < 1000; i++ {
|
||||
z -= (z*z - x) / (2 * x)
|
||||
}
|
||||
return z
|
||||
}
|
||||
```
|
||||
這樣我的套件目錄和程式碼已經建立完畢,注意:一般建議 package 的名稱和目錄名保持一致
|
||||
|
||||
## 編譯應用
|
||||
上面我們已經建立了自己的套件,如何進行編譯安裝呢?有兩種方式可以進行安裝
|
||||
|
||||
1、只要進入對應的套件目錄,然後執行`go install`,就可以安裝了
|
||||
|
||||
2、在任意的目錄執行如下程式碼`go install mymath`
|
||||
|
||||
安裝完之後,我們可以進入如下目錄
|
||||
|
||||
```sh
|
||||
cd $GOPATH/pkg/${GOOS}_${GOARCH}
|
||||
//可以看到如下檔案
|
||||
mymath.a
|
||||
```
|
||||
這個.a 檔案是套件,那麼我們如何進行呼叫呢?
|
||||
|
||||
接下來我們建立一個應用程式來呼叫這個套件
|
||||
|
||||
建立套件 mathapp
|
||||
|
||||
```sh
|
||||
cd $GOPATH/src
|
||||
mkdir mathapp
|
||||
cd mathapp
|
||||
vim main.go
|
||||
```
|
||||
|
||||
`$GOPATH/src/mathapp/main.go`原始碼:
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"mymath"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Hello, world. Sqrt(2) = %v\n", mymath.Sqrt(2))
|
||||
}
|
||||
```
|
||||
|
||||
可以看到這個的 package 是`main`,import 裡面呼叫的套件是`mymath`,這個就是相對於`$GOPATH/src`的路徑,如果是多階層目錄,就在 import 裡面引入多階層目錄,如果你有多個 GOPATH,也是一樣,Go 會自動在多個`$GOPATH/src`中尋找。
|
||||
|
||||
如何編譯程式呢?進入該應用目錄,然後執行`go build`,那麼在該目錄下面會產生一個 mathapp 的可執行檔案
|
||||
|
||||
```sh
|
||||
./mathapp
|
||||
```
|
||||
|
||||
輸出如下內容
|
||||
|
||||
```sh
|
||||
Hello, world. Sqrt(2) = 1.414213562373095
|
||||
```
|
||||
|
||||
如何安裝該應用,進入該目錄執行`go install`,那麼在$GOPATH/bin/下增加了一個可執行檔案 mathapp, 還記得前面我們把`$GOPATH/bin`加到我們的 PATH 裡面了,這樣可以在命令列輸入如下命令就可以執行
|
||||
|
||||
```sh
|
||||
mathapp
|
||||
```
|
||||
|
||||
也是輸出如下內容
|
||||
|
||||
Hello, world. Sqrt(2) = 1.414213562373095
|
||||
|
||||
這裡我們展示如何編譯和安裝一個可執行的應用,以及如何設計我們的目錄結構。
|
||||
|
||||
## 取得遠端套件
|
||||
|
||||
go 語言有一個取得遠端套件的工具就是`go get`,目前 go get 支援多數開源社群(例如:GitHub、googlecode、bitbucket、Launchpad)
|
||||
|
||||
go get github.com/astaxie/beedb
|
||||
|
||||
>go get -u 參數可以自動更新套件,而且當 go get 的時候會自動取得該套件依賴的其他第三方套件
|
||||
|
||||
|
||||
透過這個命令可以取得相應的原始碼,對應的開源平臺採用不同的原始碼控制工具,例如 GitHub 採用 git、googlecode 採用 hg,所以要想取得這些原始碼,必須先安裝相應的原始碼控制工具
|
||||
|
||||
透過上面取得的程式碼在我們本地的原始碼相應的程式碼結構如下
|
||||
|
||||
$GOPATH
|
||||
src
|
||||
|--github.com
|
||||
|-astaxie
|
||||
|-beedb
|
||||
pkg
|
||||
|--相應平臺
|
||||
|-github.com
|
||||
|--astaxie
|
||||
|beedb.a
|
||||
|
||||
go get 本質上可以理解為首先第一步是透過原始碼工具 clone 程式碼到 src 下面,然後執行`go install`
|
||||
|
||||
在程式碼中如何使用遠端套件,很簡單的就是和使用本地套件一樣,只要在開頭 import 相應的路徑就可以
|
||||
|
||||
import "github.com/astaxie/beedb"
|
||||
|
||||
## 程式的整體結構
|
||||
透過上面建立的我本地的 mygo 的目錄結構如下所示
|
||||
|
||||
bin/
|
||||
mathapp
|
||||
pkg/
|
||||
平臺名/ 如:darwin_amd64、linux_amd64
|
||||
mymath.a
|
||||
github.com/
|
||||
astaxie/
|
||||
beedb.a
|
||||
src/
|
||||
mathapp
|
||||
main.go
|
||||
mymath/
|
||||
sqrt.go
|
||||
github.com/
|
||||
astaxie/
|
||||
beedb/
|
||||
beedb.go
|
||||
util.go
|
||||
|
||||
從上面的結構我們可以很清晰的看到,bin 目錄下面存的是編譯之後可執行的檔案,pkg 下面存放的是套件,src 下面儲存的是應用原始碼
|
||||
|
||||
|
||||
## links
|
||||
* [目錄](<preface.md>)
|
||||
* 上一節: [安裝 Go](<01.1.md>)
|
||||
* 下一節: [GO 命令](<01.3.md>)
|
||||
|
||||
422
zh-tw/01.3.md
422
zh-tw/01.3.md
@@ -1,211 +1,211 @@
|
||||
# 1.3 Go 命令
|
||||
|
||||
## Go 命令
|
||||
|
||||
Go 語言自帶有一套完整的命令列工具,你可以透過在命令列中執行 `go` 來檢視它們:
|
||||
|
||||

|
||||
|
||||
圖 1.3 Go 命令顯示詳細的資訊
|
||||
|
||||
這些命令對於我們平時編寫的程式碼非常有用,接下來就讓我們了解一些常用的命令。
|
||||
|
||||
## go build
|
||||
|
||||
這個命令主要用於編譯程式碼。在套件的編譯過程中,若有必要,會同時編譯與之相關聯的套件。
|
||||
|
||||
- 如果是普通套件,就像我們在 1.2 節中編寫的 `mymath` 套件那樣,當你執行`go build`之後,它不會產生任何檔案。如果你需要在`$GOPATH/pkg`下產生相應的檔案,那就得執行`go install`。
|
||||
|
||||
- 如果是 `main` 套件,當你執行`go build`之後,它就會在當前目錄下產生一個可執行檔案。如果你需要在`$GOPATH/bin`下產生相應的檔案,需要執行`go install`,或者使用`go build -o 路徑/a.exe`。
|
||||
|
||||
- 如果某個專案資料夾下有多個檔案,而你只想編譯某個檔案,就可在`go build`之後加上檔名,例如`go build a.go`;`go build`命令預設會編譯當前目錄下的所有 go 檔案。
|
||||
|
||||
- 你也可以指定編譯輸出的檔名。例如 1.2 節中的 `mathapp` 應用,我們可以指定`go build -o astaxie.exe`,預設情況是你的 package 名(非 main 套件),或者是第一個原始檔的檔名(main 套件)。
|
||||
|
||||
(注:實際上,package 名在 [Go 語言規範](https://golang.org/ref/spec)中指程式碼中“package”後使用的名稱,此名稱可以與資料夾名不同。預設產生的可執行檔名是資料夾名。)
|
||||
|
||||
- go build 會忽略目錄下以“_”或“.”開頭的 go 檔案。
|
||||
|
||||
- 如果你的原始碼針對不同的作業系統需要不同的處理,那麼你可以根據不同的作業系統字尾來命名檔案。例如有一個讀取陣列的程式,它對於不同的作業系統可能有如下幾個原始檔:
|
||||
|
||||
array_linux.go
|
||||
array_darwin.go
|
||||
array_windows.go
|
||||
array_freebsd.go
|
||||
|
||||
`go build`的時候會選擇性地編譯以系統名結尾的檔案(Linux、Darwin、Windows、Freebsd)。例如 Linux 系統下面編譯只會選擇 array_linux.go 檔案,其它系統命名字尾檔案全部忽略。
|
||||
|
||||
參數的介紹
|
||||
|
||||
- `-o` 指定輸出的檔名,可以帶上路徑,例如 `go build -o a/b/c`
|
||||
- `-i` 安裝相應的套件,編譯+`go install`
|
||||
- `-a` 更新全部已經是最新的套件的,但是對標準套件不適用
|
||||
- `-n` 把需要執行的編譯命令顯示出來,但是不執行,這樣就可以很容易的知道底層是如何執行的
|
||||
- `-p n` 指定可以並行可執行的編譯數目,預設是 CPU 數目
|
||||
- `-race` 開啟編譯的時候自動檢測資料競爭的情況,目前只支援 64 位的機器
|
||||
- `-v` 顯示出來我們正在編譯的套件名
|
||||
- `-work` 顯示出來編譯時候的臨時資料夾名稱,並且如果已經存在的話就不要刪除
|
||||
- `-x` 顯示出來執行的命令,其實就是和`-n`的結果類似,只是這個會執行
|
||||
- `-ccflags 'arg list'` 傳遞參數給 5c, 6c, 8c 呼叫
|
||||
- `-compiler name` 指定相應的編譯器,gccgo 還是 gc
|
||||
|
||||
- `-gccgoflags 'arg list'` 傳遞參數給 gccgo 編譯連線呼叫
|
||||
- `-gcflags 'arg list'` 傳遞參數給 5g, 6g, 8g 呼叫
|
||||
- `-installsuffix suffix` 為了和預設的安裝套件區別開來,採用這個字首來重新安裝那些依賴的套件,`-race`的時候預設已經是`-installsuffix race`,大家可以透過`-n`命令來驗證
|
||||
- `-ldflags 'flag list'` 傳遞參數給 5l, 6l, 8l 呼叫
|
||||
- `-tags 'tag list'` 設定在編譯的時候可以適配的那些 tag,詳細的 tag 限制參考裡面的 [Build Constraints](http://golang.org/pkg/go/build/)
|
||||
|
||||
## go clean
|
||||
|
||||
這個命令是用來移除當前原始碼套件和關聯原始碼套件裡面編譯產生的檔案。這些檔案包括
|
||||
|
||||
_obj/ 舊的 object 目錄,由 Makefiles 遺留
|
||||
_test/ 舊的 test 目錄,由 Makefiles 遺留
|
||||
_testmain.go 舊的 gotest 檔案,由 Makefiles 遺留
|
||||
test.out 舊的 test 記錄,由 Makefiles 遺留
|
||||
build.out 舊的 test 記錄,由 Makefiles 遺留
|
||||
*.[568ao] object 檔案,由 Makefiles 遺留
|
||||
|
||||
DIR(.exe) 由 go build 產生
|
||||
DIR.test(.exe) 由 go test -c 產生
|
||||
MAINFILE(.exe) 由 go build MAINFILE.go 產生
|
||||
*.so 由 SWIG 產生
|
||||
|
||||
我一般都是利用這個命令清除編譯檔案,然後 github 提交原始碼,在本機測試的時候這些編譯檔案都是和系統相關的,但是對於原始碼管理來說沒必要。
|
||||
|
||||
$ go clean -i -n
|
||||
cd /Users/astaxie/develop/gopath/src/mathapp
|
||||
rm -f mathapp mathapp.exe mathapp.test mathapp.test.exe app app.exe
|
||||
rm -f /Users/astaxie/develop/gopath/bin/mathapp
|
||||
|
||||
參數介紹
|
||||
|
||||
- `-i` 清除關聯的安裝的套件和可執行檔案,也就是透過 go install 安裝的檔案
|
||||
- `-n` 把需要執行的清除命令顯示出來,但是不執行,這樣就可以很容易的知道底層是如何執行的
|
||||
- `-r` 迴圈的清除在 import 中引入的套件
|
||||
|
||||
- `-x` 顯示出來執行的詳細命令,其實就是`-n`列印的執行版本
|
||||
|
||||
## go fmt
|
||||
|
||||
有過 C/C++經驗的讀者會知道,一些人經常為程式碼採取 K&R 風格還是 ANSI 風格而爭論不休。在 go 中,程式碼則有標準的風格。由於之前已經有的一些習慣或其它的原因我們常將程式碼寫成 ANSI 風格或者其它更合適自己的格式,這將為人們在閱讀別人的程式碼時新增不必要的負擔,所以 go 強制了程式碼格式(比如左大括號必須放在行尾),不按照此格式的程式碼將不能編譯透過,為了減少浪費在排版上的時間,go 工具集中提供了一個`go fmt`命令 它可以幫你格式化你寫好的程式碼檔案,使你寫程式碼的時候不需要關心格式,你只需要在寫完之後執行`go fmt <檔名>.go`,你的程式碼就被修改成了標準格式,但是我平常很少用到這個命令,因為開發工具裡面一般都帶了儲存時候自動格式化功能,這個功能其實在底層就是呼叫了`go fmt`。接下來的一節我將講述兩個工具,這兩個工具都自帶了儲存檔案時自動化`go fmt`功能。
|
||||
|
||||
使用 go fmt 命令,其實是呼叫了 gofmt,而且需要參數-w,否則格式化結果不會寫入檔案。gofmt -w -l src,可以格式化整個專案。
|
||||
|
||||
所以 go fmt 是 gofmt 的上層一個封裝命令,如果想要更多的自訂格式化,可以參考 [gofmt](http://golang.org/cmd/gofmt/)
|
||||
|
||||
gofmt 的參數介紹
|
||||
|
||||
- `-l` 顯示那些需要格式化的檔案
|
||||
- `-w` 把改寫後的內容直接寫入到檔案中,而不是作為結果列印到標準輸出。
|
||||
- `-r` 新增形如“a[b:len(a)] -> a[b:]”的重寫規則,方便我們做批量替換
|
||||
- `-s` 簡化檔案中的程式碼
|
||||
- `-d` 顯示格式化前後的 diff 而不是寫入檔案,預設是 false
|
||||
|
||||
- `-e` 列印所有的語法錯誤到標準輸出。如果不使用此標記,則只會列印不同行的前 10 個錯誤。
|
||||
- `-cpuprofile` 支援除錯模式,寫入相應的 cpufile 到指定的檔案
|
||||
|
||||
## go get
|
||||
|
||||
這個命令是用來動態取得遠端程式碼套件的,目前支援的有 BitBucket、GitHub、Google Code 和 Launchpad。這個命令在內部實際上分成了兩步操作:第一步是下載原始碼套件,第二步是執行`go install`。下載原始碼套件的 go 工具會自動根據不同的域名呼叫不同的原始碼工具,對應關係如下:
|
||||
|
||||
BitBucket (Mercurial Git)
|
||||
GitHub (Git)
|
||||
Google Code Project Hosting (Git, Mercurial, Subversion)
|
||||
Launchpad (Bazaar)
|
||||
|
||||
所以為了`go get` 能正常工作,你必須確保安裝了合適的原始碼管理工具,並同時把這些命令加入你的 PATH 中。其實`go get`支援自訂域名的功能,具體參見`go help remote`。
|
||||
|
||||
參數介紹:
|
||||
|
||||
- `-d` 只下載不安裝
|
||||
- `-f` 只有在你包含了`-u`參數的時候才有效,不讓`-u`去驗證 import 中的每一個都已經取得了,這對於本地 fork 的套件特別有用
|
||||
- `-fix` 在取得原始碼之後先執行 fix,然後再去做其他的事情
|
||||
- `-t` 同時也下載需要為執行測試所需要的套件
|
||||
|
||||
- `-u` 強制使用網路去更新套件和它的相依套件
|
||||
- `-v` 顯示執行的命令
|
||||
|
||||
## go install
|
||||
|
||||
這個命令在內部實際上分成了兩步操作:第一步是產生結果檔案(可執行檔案或者.a 套件),第二步會把編譯好的結果移到`$GOPATH/pkg`或者`$GOPATH/bin`。
|
||||
|
||||
參數支援`go build`的編譯參數。大家只要記住一個參數`-v`就好了,這個隨時隨地的可以檢視底層的執行資訊。
|
||||
|
||||
## go test
|
||||
|
||||
執行這個命令,會自動讀取原始碼目錄下面名為`*_test.go`的檔案,產生並執行測試用的可執行檔案。輸出的資訊類似
|
||||
|
||||
ok archive/tar 0.011s
|
||||
FAIL archive/zip 0.022s
|
||||
ok compress/gzip 0.033s
|
||||
...
|
||||
|
||||
預設的情況下,不需要任何的參數,它會自動把你原始碼套件下面所有 test 檔案測試完畢,當然你也可以帶上參數,詳情請參考`go help testflag`
|
||||
|
||||
這裡我介紹幾個我們常用的參數:
|
||||
|
||||
- `-bench regexp` 執行相應的 benchmarks,例如 `-bench=.`
|
||||
- `-cover` 開啟測試覆蓋率
|
||||
- `-run regexp` 只執行 regexp 匹配的函式,例如 `-run=Array` 那麼就執行包含有 Array 開頭的函式
|
||||
- `-v` 顯示測試的詳細命令
|
||||
|
||||
## go tool
|
||||
`go tool`下面下載聚集了很多命令,這裡我們只介紹兩個,fix 和 vet
|
||||
|
||||
|
||||
- `go tool fix .` 用來修復以前老版本的程式碼到新版本,例如 go1 之前老版本的程式碼轉化到 go1,例如 API 的變化
|
||||
- `go tool vet directory|files` 用來分析當前目錄的程式碼是否都是正確的程式碼,例如是不是呼叫 fmt.Printf 裡面的參數不正確,例如函式裡面提前 return 了然後出現了無用程式碼之類別的。
|
||||
|
||||
## go generate
|
||||
|
||||
這個命令是從 Go1.4 開始才設計的,用於在編譯前自動化產生某類別程式碼。`go generate`和`go build`是完全不一樣的命令,透過分析原始碼中特殊的註釋,然後執行相應的命令。這些命令都是很明確的,沒有任何的依賴在裡面。而且大家在用這個之前心裡面一定要有一個觀念,這個 `go generate` 是給你用的,不是給使用你這個套件的人用的,主要是方便你自動產生一些程式碼。
|
||||
|
||||
這裡我們來舉一個簡單的例子,例如我們經常會使用 `yacc` 來產生程式碼,那麼我們常用這樣的命令:
|
||||
|
||||
go tool yacc -o gopher.go -p parser gopher.y
|
||||
|
||||
-o 指定了輸出的檔名, -p 指定了 package 的名稱,這是一個單獨的命令,如果我們想讓`go generate`來觸發這個命令,那麼就可以在當前目錄的任意一個`xxx.go`檔案裡面的任意位置增加一行如下的註釋:
|
||||
|
||||
//go:generate go tool yacc -o gopher.go -p parser gopher.y
|
||||
|
||||
這裡我們注意了,`//go:generate`是沒有任何空格的,這其實就是一個固定的格式,在掃描原始碼檔案的時候就是根據這個來判斷的。
|
||||
|
||||
所以我們可以透過如下的命令來產生,編譯,測試。如果`gopher.y`檔案有修改,那麼就重新執行`go generate`重新產生檔案就好。
|
||||
|
||||
$ go generate
|
||||
$ go build
|
||||
$ go test
|
||||
|
||||
|
||||
## godoc
|
||||
|
||||
在 Go1.2 版本之前還支援`go doc`命令,但是之後全部移到了 godoc 這個命令下,需要這樣安裝`go get golang.org/x/tools/cmd/godoc`
|
||||
|
||||
很多人說 go 不需要任何的第三方文件,例如 chm 手冊之類別的(其實我已經做了一個了,[chm 手冊](https://github.com/astaxie/godoc)),因為它內部就有一個很強大的文件工具。
|
||||
|
||||
如何檢視相應 package 的文件呢?
|
||||
例如 builtin 套件,那麼執行`godoc builtin`
|
||||
如果是 http 套件,那麼執行`godoc net/http`
|
||||
檢視某一個套件裡面的函式,那麼執行`godoc fmt Printf`
|
||||
也可以檢視相應的程式碼,執行`godoc -src fmt Printf`
|
||||
|
||||
透過命令在命令列執行 godoc -http=:埠號 比如`godoc -http=:8080`。然後在瀏覽器中開啟`127.0.0.1:8080`,你將會看到一個 golang.org 的本地 copy 版本,透過它你可以查詢 pkg 文件等其它內容。如果你設定了 GOPATH,在 pkg 分類下,不但會列出標準套件的文件,還會列出你本地 `GOPATH` 中所有專案的相關文件,這對於經常被牆的使用者來說是一個不錯的選擇。
|
||||
|
||||
## 其它命令
|
||||
|
||||
go 還提供了其它很多的工具,例如下面的這些工具
|
||||
|
||||
go version 檢視 go 當前的版本
|
||||
go env 檢視當前 go 的環境變數
|
||||
go list 列出當前全部安裝的 package
|
||||
|
||||
go run 編譯並執行 Go 程式
|
||||
|
||||
以上這些工具還有很多參數沒有一一介紹,使用者可以使用`go help 命令 ` 取得更詳細的幫助資訊。
|
||||
|
||||
|
||||
## links
|
||||
* [目錄](<preface.md>)
|
||||
* 上一節: [GOPATH 與工作空間](<01.2.md>)
|
||||
* 下一節: [Go 開發工具](<01.4.md>)
|
||||
# 1.3 Go 命令
|
||||
|
||||
## Go 命令
|
||||
|
||||
Go 語言自帶有一套完整的命令列工具,你可以透過在命令列中執行 `go` 來檢視它們:
|
||||
|
||||

|
||||
|
||||
圖 1.3 Go 命令顯示詳細的資訊
|
||||
|
||||
這些命令對於我們平時編寫的程式碼非常有用,接下來就讓我們了解一些常用的命令。
|
||||
|
||||
## go build
|
||||
|
||||
這個命令主要用於編譯程式碼。在套件的編譯過程中,若有必要,會同時編譯與之相關聯的套件。
|
||||
|
||||
- 如果是普通套件,就像我們在 1.2 節中編寫的 `mymath` 套件那樣,當你執行`go build`之後,它不會產生任何檔案。如果你需要在`$GOPATH/pkg`下產生相應的檔案,那就得執行`go install`。
|
||||
|
||||
- 如果是 `main` 套件,當你執行`go build`之後,它就會在當前目錄下產生一個可執行檔案。如果你需要在`$GOPATH/bin`下產生相應的檔案,需要執行`go install`,或者使用`go build -o 路徑/a.exe`。
|
||||
|
||||
- 如果某個專案資料夾下有多個檔案,而你只想編譯某個檔案,就可在`go build`之後加上檔名,例如`go build a.go`;`go build`命令預設會編譯當前目錄下的所有 go 檔案。
|
||||
|
||||
- 你也可以指定編譯輸出的檔名。例如 1.2 節中的 `mathapp` 應用,我們可以指定`go build -o astaxie.exe`,預設情況是你的 package 名(非 main 套件),或者是第一個原始檔的檔名(main 套件)。
|
||||
|
||||
(注:實際上,package 名在 [Go 語言規範](https://golang.org/ref/spec)中指程式碼中“package”後使用的名稱,此名稱可以與資料夾名不同。預設產生的可執行檔名是資料夾名。)
|
||||
|
||||
- go build 會忽略目錄下以“_”或“.”開頭的 go 檔案。
|
||||
|
||||
- 如果你的原始碼針對不同的作業系統需要不同的處理,那麼你可以根據不同的作業系統字尾來命名檔案。例如有一個讀取陣列的程式,它對於不同的作業系統可能有如下幾個原始檔:
|
||||
|
||||
array_linux.go
|
||||
array_darwin.go
|
||||
array_windows.go
|
||||
array_freebsd.go
|
||||
|
||||
`go build`的時候會選擇性地編譯以系統名結尾的檔案(Linux、Darwin、Windows、Freebsd)。例如 Linux 系統下面編譯只會選擇 array_linux.go 檔案,其它系統命名字尾檔案全部忽略。
|
||||
|
||||
參數的介紹
|
||||
|
||||
- `-o` 指定輸出的檔名,可以帶上路徑,例如 `go build -o a/b/c`
|
||||
- `-i` 安裝相應的套件,編譯+`go install`
|
||||
- `-a` 更新全部已經是最新的套件的,但是對標準套件不適用
|
||||
- `-n` 把需要執行的編譯命令顯示出來,但是不執行,這樣就可以很容易的知道底層是如何執行的
|
||||
- `-p n` 指定可以並行可執行的編譯數目,預設是 CPU 數目
|
||||
- `-race` 開啟編譯的時候自動檢測資料競爭的情況,目前只支援 64 位的機器
|
||||
- `-v` 顯示出來我們正在編譯的套件名
|
||||
- `-work` 顯示出來編譯時候的臨時資料夾名稱,並且如果已經存在的話就不要刪除
|
||||
- `-x` 顯示出來執行的命令,其實就是和`-n`的結果類似,只是這個會執行
|
||||
- `-ccflags 'arg list'` 傳遞參數給 5c, 6c, 8c 呼叫
|
||||
- `-compiler name` 指定相應的編譯器,gccgo 還是 gc
|
||||
|
||||
- `-gccgoflags 'arg list'` 傳遞參數給 gccgo 編譯連線呼叫
|
||||
- `-gcflags 'arg list'` 傳遞參數給 5g, 6g, 8g 呼叫
|
||||
- `-installsuffix suffix` 為了和預設的安裝套件區別開來,採用這個字首來重新安裝那些依賴的套件,`-race`的時候預設已經是`-installsuffix race`,大家可以透過`-n`命令來驗證
|
||||
- `-ldflags 'flag list'` 傳遞參數給 5l, 6l, 8l 呼叫
|
||||
- `-tags 'tag list'` 設定在編譯的時候可以適配的那些 tag,詳細的 tag 限制參考裡面的 [Build Constraints](http://golang.org/pkg/go/build/)
|
||||
|
||||
## go clean
|
||||
|
||||
這個命令是用來移除當前原始碼套件和關聯原始碼套件裡面編譯產生的檔案。這些檔案包括
|
||||
|
||||
_obj/ 舊的 object 目錄,由 Makefiles 遺留
|
||||
_test/ 舊的 test 目錄,由 Makefiles 遺留
|
||||
_testmain.go 舊的 gotest 檔案,由 Makefiles 遺留
|
||||
test.out 舊的 test 記錄,由 Makefiles 遺留
|
||||
build.out 舊的 test 記錄,由 Makefiles 遺留
|
||||
*.[568ao] object 檔案,由 Makefiles 遺留
|
||||
|
||||
DIR(.exe) 由 go build 產生
|
||||
DIR.test(.exe) 由 go test -c 產生
|
||||
MAINFILE(.exe) 由 go build MAINFILE.go 產生
|
||||
*.so 由 SWIG 產生
|
||||
|
||||
我一般都是利用這個命令清除編譯檔案,然後 GitHub 提交原始碼,在本機測試的時候這些編譯檔案都是和系統相關的,但是對於原始碼管理來說沒必要。
|
||||
|
||||
$ go clean -i -n
|
||||
cd /Users/astaxie/develop/gopath/src/mathapp
|
||||
rm -f mathapp mathapp.exe mathapp.test mathapp.test.exe app app.exe
|
||||
rm -f /Users/astaxie/develop/gopath/bin/mathapp
|
||||
|
||||
參數介紹
|
||||
|
||||
- `-i` 清除關聯的安裝的套件和可執行檔案,也就是透過 go install 安裝的檔案
|
||||
- `-n` 把需要執行的清除命令顯示出來,但是不執行,這樣就可以很容易的知道底層是如何執行的
|
||||
- `-r` 迴圈的清除在 import 中引入的套件
|
||||
|
||||
- `-x` 顯示出來執行的詳細命令,其實就是`-n`列印的執行版本
|
||||
|
||||
## go fmt
|
||||
|
||||
有過 C/C++經驗的讀者會知道,一些人經常為程式碼採取 K&R 風格還是 ANSI 風格而爭論不休。在 go 中,程式碼則有標準的風格。由於之前已經有的一些習慣或其它的原因我們常將程式碼寫成 ANSI 風格或者其它更合適自己的格式,這將為人們在閱讀別人的程式碼時新增不必要的負擔,所以 go 強制了程式碼格式(比如左大括號必須放在行尾),不按照此格式的程式碼將不能編譯透過,為了減少浪費在排版上的時間,go 工具集中提供了一個`go fmt`命令 它可以幫你格式化你寫好的程式碼檔案,使你寫程式碼的時候不需要關心格式,你只需要在寫完之後執行`go fmt <檔名>.go`,你的程式碼就被修改成了標準格式,但是我平常很少用到這個命令,因為開發工具裡面一般都帶了儲存時候自動格式化功能,這個功能其實在底層就是呼叫了`go fmt`。接下來的一節我將講述兩個工具,這兩個工具都自帶了儲存檔案時自動化`go fmt`功能。
|
||||
|
||||
使用 go fmt 命令,其實是呼叫了 gofmt,而且需要參數-w,否則格式化結果不會寫入檔案。gofmt -w -l src,可以格式化整個專案。
|
||||
|
||||
所以 go fmt 是 gofmt 的上層一個封裝命令,如果想要更多的自訂格式化,可以參考 [gofmt](http://golang.org/cmd/gofmt/)
|
||||
|
||||
gofmt 的參數介紹
|
||||
|
||||
- `-l` 顯示那些需要格式化的檔案
|
||||
- `-w` 把改寫後的內容直接寫入到檔案中,而不是作為結果列印到標準輸出。
|
||||
- `-r` 新增形如“a[b:len(a)] -> a[b:]”的重寫規則,方便我們做批量替換
|
||||
- `-s` 簡化檔案中的程式碼
|
||||
- `-d` 顯示格式化前後的 diff 而不是寫入檔案,預設是 false
|
||||
|
||||
- `-e` 列印所有的語法錯誤到標準輸出。如果不使用此標記,則只會列印不同行的前 10 個錯誤。
|
||||
- `-cpuprofile` 支援除錯模式,寫入相應的 cpufile 到指定的檔案
|
||||
|
||||
## go get
|
||||
|
||||
這個命令是用來動態取得遠端程式碼套件的,目前支援的有 BitBucket、GitHub、Google Code 和 Launchpad。這個命令在內部實際上分成了兩步操作:第一步是下載原始碼套件,第二步是執行`go install`。下載原始碼套件的 go 工具會自動根據不同的域名呼叫不同的原始碼工具,對應關係如下:
|
||||
|
||||
BitBucket (Mercurial Git)
|
||||
GitHub (Git)
|
||||
Google Code Project Hosting (Git, Mercurial, Subversion)
|
||||
Launchpad (Bazaar)
|
||||
|
||||
所以為了`go get` 能正常工作,你必須確保安裝了合適的原始碼管理工具,並同時把這些命令加入你的 PATH 中。其實`go get`支援自訂域名的功能,具體參見`go help remote`。
|
||||
|
||||
參數介紹:
|
||||
|
||||
- `-d` 只下載不安裝
|
||||
- `-f` 只有在你包含了`-u`參數的時候才有效,不讓`-u`去驗證 import 中的每一個都已經取得了,這對於本地 fork 的套件特別有用
|
||||
- `-fix` 在取得原始碼之後先執行 fix,然後再去做其他的事情
|
||||
- `-t` 同時也下載需要為執行測試所需要的套件
|
||||
|
||||
- `-u` 強制使用網路去更新套件和它的相依套件
|
||||
- `-v` 顯示執行的命令
|
||||
|
||||
## go install
|
||||
|
||||
這個命令在內部實際上分成了兩步操作:第一步是產生結果檔案(可執行檔案或者.a 套件),第二步會把編譯好的結果移到`$GOPATH/pkg`或者`$GOPATH/bin`。
|
||||
|
||||
參數支援`go build`的編譯參數。大家只要記住一個參數`-v`就好了,這個隨時隨地的可以檢視底層的執行資訊。
|
||||
|
||||
## go test
|
||||
|
||||
執行這個命令,會自動讀取原始碼目錄下面名為`*_test.go`的檔案,產生並執行測試用的可執行檔案。輸出的資訊類似
|
||||
|
||||
ok archive/tar 0.011s
|
||||
FAIL archive/zip 0.022s
|
||||
ok compress/gzip 0.033s
|
||||
...
|
||||
|
||||
預設的情況下,不需要任何的參數,它會自動把你原始碼套件下面所有 test 檔案測試完畢,當然你也可以帶上參數,詳情請參考`go help testflag`
|
||||
|
||||
這裡我介紹幾個我們常用的參數:
|
||||
|
||||
- `-bench regexp` 執行相應的 benchmarks,例如 `-bench=.`
|
||||
- `-cover` 開啟測試覆蓋率
|
||||
- `-run regexp` 只執行 regexp 匹配的函式,例如 `-run=Array` 那麼就執行包含有 Array 開頭的函式
|
||||
- `-v` 顯示測試的詳細命令
|
||||
|
||||
## go tool
|
||||
`go tool`下面下載聚集了很多命令,這裡我們只介紹兩個,fix 和 vet
|
||||
|
||||
|
||||
- `go tool fix .` 用來修復以前老版本的程式碼到新版本,例如 go1 之前老版本的程式碼轉化到 go1,例如 API 的變化
|
||||
- `go tool vet directory|files` 用來分析當前目錄的程式碼是否都是正確的程式碼,例如是不是呼叫 fmt.Printf 裡面的參數不正確,例如函式裡面提前 return 了然後出現了無用程式碼之類別的。
|
||||
|
||||
## go generate
|
||||
|
||||
這個命令是從 Go1.4 開始才設計的,用於在編譯前自動化產生某類別程式碼。`go generate`和`go build`是完全不一樣的命令,透過分析原始碼中特殊的註釋,然後執行相應的命令。這些命令都是很明確的,沒有任何的依賴在裡面。而且大家在用這個之前心裡面一定要有一個觀念,這個 `go generate` 是給你用的,不是給使用你這個套件的人用的,主要是方便你自動產生一些程式碼。
|
||||
|
||||
這裡我們來舉一個簡單的例子,例如我們經常會使用 `yacc` 來產生程式碼,那麼我們常用這樣的命令:
|
||||
|
||||
go tool yacc -o gopher.go -p parser gopher.y
|
||||
|
||||
-o 指定了輸出的檔名, -p 指定了 package 的名稱,這是一個單獨的命令,如果我們想讓`go generate`來觸發這個命令,那麼就可以在當前目錄的任意一個`xxx.go`檔案裡面的任意位置增加一行如下的註釋:
|
||||
|
||||
//go:generate go tool yacc -o gopher.go -p parser gopher.y
|
||||
|
||||
這裡我們注意了,`//go:generate`是沒有任何空格的,這其實就是一個固定的格式,在掃描原始碼檔案的時候就是根據這個來判斷的。
|
||||
|
||||
所以我們可以透過如下的命令來產生,編譯,測試。如果`gopher.y`檔案有修改,那麼就重新執行`go generate`重新產生檔案就好。
|
||||
|
||||
$ go generate
|
||||
$ go build
|
||||
$ go test
|
||||
|
||||
|
||||
## godoc
|
||||
|
||||
在 Go1.2 版本之前還支援`go doc`命令,但是之後全部移到了 godoc 這個命令下,需要這樣安裝`go get golang.org/x/tools/cmd/godoc`
|
||||
|
||||
很多人說 go 不需要任何的第三方文件,例如 chm 手冊之類別的(其實我已經做了一個了,[chm 手冊](https://github.com/astaxie/godoc)),因為它內部就有一個很強大的文件工具。
|
||||
|
||||
如何檢視相應 package 的文件呢?
|
||||
例如 builtin 套件,那麼執行`godoc builtin`
|
||||
如果是 http 套件,那麼執行`godoc net/http`
|
||||
檢視某一個套件裡面的函式,那麼執行`godoc fmt Printf`
|
||||
也可以檢視相應的程式碼,執行`godoc -src fmt Printf`
|
||||
|
||||
透過命令在命令列執行 godoc -http=:埠號 比如`godoc -http=:8080`。然後在瀏覽器中開啟`127.0.0.1:8080`,你將會看到一個 golang.org 的本地 copy 版本,透過它你可以查詢 pkg 文件等其它內容。如果你設定了 GOPATH,在 pkg 分類下,不但會列出標準套件的文件,還會列出你本地 `GOPATH` 中所有專案的相關文件,這對於經常被牆的使用者來說是一個不錯的選擇。
|
||||
|
||||
## 其它命令
|
||||
|
||||
go 還提供了其它很多的工具,例如下面的這些工具
|
||||
|
||||
go version 檢視 go 當前的版本
|
||||
go env 檢視當前 go 的環境變數
|
||||
go list 列出當前全部安裝的 package
|
||||
|
||||
go run 編譯並執行 Go 程式
|
||||
|
||||
以上這些工具還有很多參數沒有一一介紹,使用者可以使用`go help 命令 ` 取得更詳細的幫助資訊。
|
||||
|
||||
|
||||
## links
|
||||
* [目錄](<preface.md>)
|
||||
* 上一節: [GOPATH 與工作空間](<01.2.md>)
|
||||
* 下一節: [Go 開發工具](<01.4.md>)
|
||||
|
||||
1288
zh-tw/01.4.md
1288
zh-tw/01.4.md
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@ Go 實現的支援 PostgreSQL 的驅動也很多,因為國外很多人在開
|
||||
- https://github.com/jbarham/gopgsqldriver 支援 database/sql 驅動,純 Go 寫的
|
||||
- https://github.com/lxn/go-pgsql 支援 database/sql 驅動,純 Go 寫的
|
||||
|
||||
在下面的範例中我採用了第一個驅動,因為它目前使用的人最多,在 github 上也比較活躍。
|
||||
在下面的範例中我採用了第一個驅動,因為它目前使用的人最多,在 GitHub 上也比較活躍。
|
||||
|
||||
## 範例程式碼
|
||||
資料庫建表語句:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 13.6 小結
|
||||
這一章我們主要介紹了如何實現一個基礎的 Go 語言框架,框架包含有路由設計,由於 Go 內建的 http 套件中路由的一些不足點,我們設計了動態路由規則,然後介紹了 MVC 模式中的 Controller 設計,controller 實現了 REST 的實現,這個主要思路來源於 tornado 框架,然後設計實現了範本的 layout 以及自動化渲染等技術,主要採用了 Go 內建的範本引擎,最後我們介紹了一些輔助的日誌、配置等資訊的設計,透過這些設計我們實現了一個基礎的框架 beego,目前該框架已經開源在 github,最後我們透過 beego 實現了一個部落格系統,透過範例程式碼詳細的展現了如何快速的開發一個站點。
|
||||
|
||||
## links
|
||||
* [目錄](<preface.md>)
|
||||
* 上一章: [實現部落格的增刪改](<13.5.md>)
|
||||
* 下一節: [擴充套件 Web 框架](<14.0.md>)
|
||||
# 13.6 小結
|
||||
這一章我們主要介紹了如何實現一個基礎的 Go 語言框架,框架包含有路由設計,由於 Go 內建的 http 套件中路由的一些不足點,我們設計了動態路由規則,然後介紹了 MVC 模式中的 Controller 設計,controller 實現了 REST 的實現,這個主要思路來源於 tornado 框架,然後設計實現了範本的 layout 以及自動化渲染等技術,主要採用了 Go 內建的範本引擎,最後我們介紹了一些輔助的日誌、配置等資訊的設計,透過這些設計我們實現了一個基礎的框架 beego,目前該框架已經開源在 GitHub,最後我們透過 beego 實現了一個部落格系統,透過範例程式碼詳細的展現了如何快速的開發一個站點。
|
||||
|
||||
## links
|
||||
* [目錄](<preface.md>)
|
||||
* 上一章: [實現部落格的增刪改](<13.5.md>)
|
||||
* 下一節: [擴充套件 Web 框架](<14.0.md>)
|
||||
|
||||
550
zh-tw/14.4.md
550
zh-tw/14.4.md
@@ -1,275 +1,275 @@
|
||||
# 14.4 使用者認證
|
||||
在開發 Web 應用過程中,使用者認證是開發者經常遇到的問題,使用者登入、註冊、登出等操作,而一般認證也分為三個方面的認證
|
||||
|
||||
- HTTP Basic 和 HTTP Digest 認證
|
||||
- 第三方整合認證:QQ、微博、豆瓣、OPENID、google、github、facebook 和 twitter 等
|
||||
- 自訂的使用者登入、註冊、登出,一般都是基於 session、cookie 認證
|
||||
|
||||
beego 目前沒有針對這三種方式進行任何形式的整合,但是可以充分的利用第三方開源函式庫來實現上面的三種方式的使用者認證,不過後續 beego 會對前面兩種認證逐步整合。
|
||||
|
||||
## HTTP Basic 和 HTTP Digest 認證
|
||||
這兩個認證是一些應用採用的比較簡單的認證,目前已經有開源的第三方函式庫支援這兩個認證:
|
||||
|
||||
```Go
|
||||
|
||||
github.com/abbot/go-http-auth
|
||||
```
|
||||
下面程式碼示範了如何把這個函式庫引入 beego 中從而實現認證:
|
||||
|
||||
```Go
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/abbot/go-http-auth"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
func Secret(user, realm string) string {
|
||||
if user == "john" {
|
||||
// password is "hello"
|
||||
return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type MainController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *MainController) Prepare() {
|
||||
a := auth.NewBasicAuthenticator("example.com", Secret)
|
||||
if username := a.CheckAuth(this.Ctx.Request); username == "" {
|
||||
a.RequireAuth(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *MainController) Get() {
|
||||
this.Data["Username"] = "astaxie"
|
||||
this.Data["Email"] = "astaxie@gmail.com"
|
||||
this.TplNames = "index.tpl"
|
||||
}
|
||||
```
|
||||
上面程式碼利用了 beego 的 prepare 函式,在執行正常邏輯之前呼叫了認證函式,這樣就非常簡單的實現了 http auth,digest 的認證也是同樣的原理。
|
||||
|
||||
## oauth 和 oauth2 的認證
|
||||
oauth 和 oauth2 是目前比較流行的兩種認證方式,還好第三方有一個函式庫實現了這個認證,但是是國外實現的,並沒有 QQ、微博之類別的國內應用認證整合:
|
||||
|
||||
```Go
|
||||
|
||||
github.com/bradrydzewski/go.auth
|
||||
```
|
||||
下面程式碼示範了如何把該函式庫引入 beego 中從而實現 oauth 的認證,這裡以 github 為例示範:
|
||||
|
||||
1. 新增兩條路由
|
||||
|
||||
```Go
|
||||
|
||||
beego.RegisterController("/auth/login", &controllers.GithubController{})
|
||||
beego.RegisterController("/mainpage", &controllers.PageController{})
|
||||
```
|
||||
2. 然後我們處理 GithubController 登陸的頁面:
|
||||
|
||||
```Go
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/bradrydzewski/go.auth"
|
||||
)
|
||||
|
||||
const (
|
||||
githubClientKey = "a0864ea791ce7e7bd0df"
|
||||
githubSecretKey = "a0ec09a647a688a64a28f6190b5a0d2705df56ca"
|
||||
)
|
||||
|
||||
type GithubController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *GithubController) Get() {
|
||||
// set the auth parameters
|
||||
auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV")
|
||||
auth.Config.LoginSuccessRedirect = "/mainpage"
|
||||
auth.Config.CookieSecure = false
|
||||
|
||||
githubHandler := auth.Github(githubClientKey, githubSecretKey)
|
||||
|
||||
githubHandler.ServeHTTP(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
}
|
||||
```
|
||||
|
||||
3. 處理登陸成功之後的頁面
|
||||
|
||||
```Go
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/bradrydzewski/go.auth"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type PageController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *PageController) Get() {
|
||||
// set the auth parameters
|
||||
auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV")
|
||||
auth.Config.LoginSuccessRedirect = "/mainpage"
|
||||
auth.Config.CookieSecure = false
|
||||
|
||||
user, err := auth.GetUserCookie(this.Ctx.Request)
|
||||
|
||||
//if no active user session then authorize user
|
||||
if err != nil || user.Id() == "" {
|
||||
http.Redirect(this.Ctx.ResponseWriter, this.Ctx.Request, auth.Config.LoginRedirect, http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
//else, add the user to the URL and continue
|
||||
this.Ctx.Request.URL.User = url.User(user.Id())
|
||||
this.Data["pic"] = user.Picture()
|
||||
this.Data["id"] = user.Id()
|
||||
this.Data["name"] = user.Name()
|
||||
this.TplNames = "home.tpl"
|
||||
}
|
||||
```
|
||||
|
||||
整個的流程如下,首先開啟瀏覽器輸入地址:
|
||||
|
||||

|
||||
|
||||
圖 14.4 顯示帶有登入按鈕的首頁
|
||||
|
||||
然後點選連結出現如下介面:
|
||||
|
||||

|
||||
|
||||
圖 14.5 點選登入按鈕後顯示 github 的授權頁
|
||||
|
||||
然後點選 Authorize app 就出現如下介面:
|
||||
|
||||

|
||||
|
||||
圖 14.6 授權登入之後顯示的取得到的 github 資訊頁
|
||||
|
||||
## 自訂認證
|
||||
自訂的認證一般都是和 session 結合驗證的,如下程式碼來源於一個基於 beego 的開源部落格:
|
||||
|
||||
```Go
|
||||
|
||||
//登陸處理
|
||||
func (this *LoginController) Post() {
|
||||
this.TplNames = "login.tpl"
|
||||
this.Ctx.Request.ParseForm()
|
||||
username := this.Ctx.Request.Form.Get("username")
|
||||
password := this.Ctx.Request.Form.Get("password")
|
||||
md5Password := md5.New()
|
||||
io.WriteString(md5Password, password)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
fmt.Fprintf(buffer, "%x", md5Password.Sum(nil))
|
||||
newPass := buffer.String()
|
||||
|
||||
now := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
userInfo := models.GetUserInfo(username)
|
||||
if userInfo.Password == newPass {
|
||||
var users models.User
|
||||
users.Last_logintime = now
|
||||
models.UpdateUserInfo(users)
|
||||
|
||||
//登入成功設定 session
|
||||
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess.Set("uid", userInfo.Id)
|
||||
sess.Set("uname", userInfo.Username)
|
||||
|
||||
this.Ctx.Redirect(302, "/")
|
||||
}
|
||||
}
|
||||
|
||||
//註冊處理
|
||||
func (this *RegController) Post() {
|
||||
this.TplNames = "reg.tpl"
|
||||
this.Ctx.Request.ParseForm()
|
||||
username := this.Ctx.Request.Form.Get("username")
|
||||
password := this.Ctx.Request.Form.Get("password")
|
||||
usererr := checkUsername(username)
|
||||
fmt.Println(usererr)
|
||||
if usererr == false {
|
||||
this.Data["UsernameErr"] = "Username error, Please to again"
|
||||
return
|
||||
}
|
||||
|
||||
passerr := checkPassword(password)
|
||||
if passerr == false {
|
||||
this.Data["PasswordErr"] = "Password error, Please to again"
|
||||
return
|
||||
}
|
||||
|
||||
md5Password := md5.New()
|
||||
io.WriteString(md5Password, password)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
fmt.Fprintf(buffer, "%x", md5Password.Sum(nil))
|
||||
newPass := buffer.String()
|
||||
|
||||
now := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
userInfo := models.GetUserInfo(username)
|
||||
|
||||
if userInfo.Username == "" {
|
||||
var users models.User
|
||||
users.Username = username
|
||||
users.Password = newPass
|
||||
users.Created = now
|
||||
users.Last_logintime = now
|
||||
models.AddUser(users)
|
||||
|
||||
//登入成功設定 session
|
||||
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess.Set("uid", userInfo.Id)
|
||||
sess.Set("uname", userInfo.Username)
|
||||
this.Ctx.Redirect(302, "/")
|
||||
} else {
|
||||
this.Data["UsernameErr"] = "User already exists"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func checkPassword(password string) (b bool) {
|
||||
if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", password); !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func checkUsername(username string) (b bool) {
|
||||
if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", username); !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
```
|
||||
有了使用者登陸和註冊之後,其他模組的地方可以增加如下這樣的使用者是否登陸的判斷:
|
||||
|
||||
```Go
|
||||
|
||||
func (this *AddBlogController) Prepare() {
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess_uid := sess.Get("userid")
|
||||
sess_username := sess.Get("username")
|
||||
if sess_uid == nil {
|
||||
this.Ctx.Redirect(302, "/admin/login")
|
||||
return
|
||||
}
|
||||
this.Data["Username"] = sess_username
|
||||
}
|
||||
```
|
||||
## links
|
||||
* [目錄](<preface.md>)
|
||||
* 上一節: [表單及驗證支援](<14.3.md>)
|
||||
* 下一節: [多語言支援](<14.5.md>)
|
||||
# 14.4 使用者認證
|
||||
在開發 Web 應用過程中,使用者認證是開發者經常遇到的問題,使用者登入、註冊、登出等操作,而一般認證也分為三個方面的認證
|
||||
|
||||
- HTTP Basic 和 HTTP Digest 認證
|
||||
- 第三方整合認證:QQ、微博、豆瓣、OPENID、google、GitHub、facebook 和 twitter 等
|
||||
- 自訂的使用者登入、註冊、登出,一般都是基於 session、cookie 認證
|
||||
|
||||
beego 目前沒有針對這三種方式進行任何形式的整合,但是可以充分的利用第三方開源函式庫來實現上面的三種方式的使用者認證,不過後續 beego 會對前面兩種認證逐步整合。
|
||||
|
||||
## HTTP Basic 和 HTTP Digest 認證
|
||||
這兩個認證是一些應用採用的比較簡單的認證,目前已經有開源的第三方函式庫支援這兩個認證:
|
||||
|
||||
```Go
|
||||
|
||||
github.com/abbot/go-http-auth
|
||||
```
|
||||
下面程式碼示範了如何把這個函式庫引入 beego 中從而實現認證:
|
||||
|
||||
```Go
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/abbot/go-http-auth"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
func Secret(user, realm string) string {
|
||||
if user == "john" {
|
||||
// password is "hello"
|
||||
return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type MainController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *MainController) Prepare() {
|
||||
a := auth.NewBasicAuthenticator("example.com", Secret)
|
||||
if username := a.CheckAuth(this.Ctx.Request); username == "" {
|
||||
a.RequireAuth(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *MainController) Get() {
|
||||
this.Data["Username"] = "astaxie"
|
||||
this.Data["Email"] = "astaxie@gmail.com"
|
||||
this.TplNames = "index.tpl"
|
||||
}
|
||||
```
|
||||
上面程式碼利用了 beego 的 prepare 函式,在執行正常邏輯之前呼叫了認證函式,這樣就非常簡單的實現了 http auth,digest 的認證也是同樣的原理。
|
||||
|
||||
## oauth 和 oauth2 的認證
|
||||
oauth 和 oauth2 是目前比較流行的兩種認證方式,還好第三方有一個函式庫實現了這個認證,但是是國外實現的,並沒有 QQ、微博之類別的國內應用認證整合:
|
||||
|
||||
```Go
|
||||
|
||||
github.com/bradrydzewski/go.auth
|
||||
```
|
||||
下面程式碼示範了如何把該函式庫引入 beego 中從而實現 oauth 的認證,這裡以 GitHub 為例示範:
|
||||
|
||||
1. 新增兩條路由
|
||||
|
||||
```Go
|
||||
|
||||
beego.RegisterController("/auth/login", &controllers.GithubController{})
|
||||
beego.RegisterController("/mainpage", &controllers.PageController{})
|
||||
```
|
||||
2. 然後我們處理 GithubController 登陸的頁面:
|
||||
|
||||
```Go
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/bradrydzewski/go.auth"
|
||||
)
|
||||
|
||||
const (
|
||||
githubClientKey = "a0864ea791ce7e7bd0df"
|
||||
githubSecretKey = "a0ec09a647a688a64a28f6190b5a0d2705df56ca"
|
||||
)
|
||||
|
||||
type GithubController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *GithubController) Get() {
|
||||
// set the auth parameters
|
||||
auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV")
|
||||
auth.Config.LoginSuccessRedirect = "/mainpage"
|
||||
auth.Config.CookieSecure = false
|
||||
|
||||
githubHandler := auth.Github(githubClientKey, githubSecretKey)
|
||||
|
||||
githubHandler.ServeHTTP(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
}
|
||||
```
|
||||
|
||||
3. 處理登陸成功之後的頁面
|
||||
|
||||
```Go
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/bradrydzewski/go.auth"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type PageController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *PageController) Get() {
|
||||
// set the auth parameters
|
||||
auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV")
|
||||
auth.Config.LoginSuccessRedirect = "/mainpage"
|
||||
auth.Config.CookieSecure = false
|
||||
|
||||
user, err := auth.GetUserCookie(this.Ctx.Request)
|
||||
|
||||
//if no active user session then authorize user
|
||||
if err != nil || user.Id() == "" {
|
||||
http.Redirect(this.Ctx.ResponseWriter, this.Ctx.Request, auth.Config.LoginRedirect, http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
//else, add the user to the URL and continue
|
||||
this.Ctx.Request.URL.User = url.User(user.Id())
|
||||
this.Data["pic"] = user.Picture()
|
||||
this.Data["id"] = user.Id()
|
||||
this.Data["name"] = user.Name()
|
||||
this.TplNames = "home.tpl"
|
||||
}
|
||||
```
|
||||
|
||||
整個的流程如下,首先開啟瀏覽器輸入地址:
|
||||
|
||||

|
||||
|
||||
圖 14.4 顯示帶有登入按鈕的首頁
|
||||
|
||||
然後點選連結出現如下介面:
|
||||
|
||||

|
||||
|
||||
圖 14.5 點選登入按鈕後顯示 GitHub 的授權頁
|
||||
|
||||
然後點選 Authorize app 就出現如下介面:
|
||||
|
||||

|
||||
|
||||
圖 14.6 授權登入之後顯示的取得到的 GitHub 資訊頁
|
||||
|
||||
## 自訂認證
|
||||
自訂的認證一般都是和 session 結合驗證的,如下程式碼來源於一個基於 beego 的開源部落格:
|
||||
|
||||
```Go
|
||||
|
||||
//登陸處理
|
||||
func (this *LoginController) Post() {
|
||||
this.TplNames = "login.tpl"
|
||||
this.Ctx.Request.ParseForm()
|
||||
username := this.Ctx.Request.Form.Get("username")
|
||||
password := this.Ctx.Request.Form.Get("password")
|
||||
md5Password := md5.New()
|
||||
io.WriteString(md5Password, password)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
fmt.Fprintf(buffer, "%x", md5Password.Sum(nil))
|
||||
newPass := buffer.String()
|
||||
|
||||
now := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
userInfo := models.GetUserInfo(username)
|
||||
if userInfo.Password == newPass {
|
||||
var users models.User
|
||||
users.Last_logintime = now
|
||||
models.UpdateUserInfo(users)
|
||||
|
||||
//登入成功設定 session
|
||||
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess.Set("uid", userInfo.Id)
|
||||
sess.Set("uname", userInfo.Username)
|
||||
|
||||
this.Ctx.Redirect(302, "/")
|
||||
}
|
||||
}
|
||||
|
||||
//註冊處理
|
||||
func (this *RegController) Post() {
|
||||
this.TplNames = "reg.tpl"
|
||||
this.Ctx.Request.ParseForm()
|
||||
username := this.Ctx.Request.Form.Get("username")
|
||||
password := this.Ctx.Request.Form.Get("password")
|
||||
usererr := checkUsername(username)
|
||||
fmt.Println(usererr)
|
||||
if usererr == false {
|
||||
this.Data["UsernameErr"] = "Username error, Please to again"
|
||||
return
|
||||
}
|
||||
|
||||
passerr := checkPassword(password)
|
||||
if passerr == false {
|
||||
this.Data["PasswordErr"] = "Password error, Please to again"
|
||||
return
|
||||
}
|
||||
|
||||
md5Password := md5.New()
|
||||
io.WriteString(md5Password, password)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
fmt.Fprintf(buffer, "%x", md5Password.Sum(nil))
|
||||
newPass := buffer.String()
|
||||
|
||||
now := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
userInfo := models.GetUserInfo(username)
|
||||
|
||||
if userInfo.Username == "" {
|
||||
var users models.User
|
||||
users.Username = username
|
||||
users.Password = newPass
|
||||
users.Created = now
|
||||
users.Last_logintime = now
|
||||
models.AddUser(users)
|
||||
|
||||
//登入成功設定 session
|
||||
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess.Set("uid", userInfo.Id)
|
||||
sess.Set("uname", userInfo.Username)
|
||||
this.Ctx.Redirect(302, "/")
|
||||
} else {
|
||||
this.Data["UsernameErr"] = "User already exists"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func checkPassword(password string) (b bool) {
|
||||
if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", password); !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func checkUsername(username string) (b bool) {
|
||||
if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", username); !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
```
|
||||
有了使用者登陸和註冊之後,其他模組的地方可以增加如下這樣的使用者是否登陸的判斷:
|
||||
|
||||
```Go
|
||||
|
||||
func (this *AddBlogController) Prepare() {
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess_uid := sess.Get("userid")
|
||||
sess_username := sess.Get("username")
|
||||
if sess_uid == nil {
|
||||
this.Ctx.Redirect(302, "/admin/login")
|
||||
return
|
||||
}
|
||||
this.Data["Username"] = sess_username
|
||||
}
|
||||
```
|
||||
## links
|
||||
* [目錄](<preface.md>)
|
||||
* 上一節: [表單及驗證支援](<14.3.md>)
|
||||
* 下一節: [多語言支援](<14.5.md>)
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 开发者 github token
|
||||
// 开发者 GitHub token
|
||||
const token = ""
|
||||
|
||||
// 定义一个访问者结构体
|
||||
|
||||
362
zh/01.2.md
362
zh/01.2.md
@@ -1,181 +1,181 @@
|
||||
# 1.2 GOPATH与工作空间
|
||||
|
||||
前面我们在安装Go的时候看到需要设置GOPATH变量,Go从1.1版本到1.7必须设置这个变量,而且不能和Go的安装目录一样,这个目录用来存放Go源码,Go的可运行文件,以及相应的编译之后的包文件。所以这个目录下面有三个子目录:src、bin、pkg
|
||||
|
||||
从go 1.8开始,GOPATH环境变量现在有一个默认值,如果它没有被设置。 它在Unix上默认为$HOME/go,在Windows上默认为%USERPROFILE%/go。
|
||||
## GOPATH设置
|
||||
go 命令依赖一个重要的环境变量:$GOPATH
|
||||
|
||||
Windows系统中环境变量的形式为`%GOPATH%`,本书主要使用Unix形式,Windows用户请自行替换。
|
||||
|
||||
*(注:这个不是Go安装目录。下面以笔者的工作目录为示例,如果你想不一样请把GOPATH替换成你的工作目录。)*
|
||||
|
||||
在类 Unix 环境下大概这样设置:
|
||||
```sh
|
||||
export GOPATH=/home/apple/mygo
|
||||
```
|
||||
为了方便,应该新建以上文件夹,并且上一行加入到 `.bashrc` 或者 `.zshrc` 或者自己的 `sh` 的配置文件中。
|
||||
|
||||
Windows 设置如下,新建一个环境变量名称叫做GOPATH:
|
||||
```sh
|
||||
GOPATH=c:\mygo
|
||||
```
|
||||
GOPATH允许多个目录,当有多个目录时,请注意分隔符,多个目录的时候Windows是分号,Linux系统是冒号,当有多个GOPATH时,默认会将go get的内容放在第一个目录下。
|
||||
|
||||
|
||||
以上 $GOPATH 目录约定有三个子目录:
|
||||
|
||||
- src 存放源代码(比如:.go .c .h .s等)
|
||||
- pkg 编译后生成的文件(比如:.a)
|
||||
- bin 编译后生成的可执行文件(为了方便,可以把此目录加入到 $PATH 变量中,如果有多个gopath,那么使用`${GOPATH//://bin:}/bin`添加所有的bin目录)
|
||||
|
||||
以后我所有的例子都是以mygo作为我的gopath目录
|
||||
|
||||
|
||||
## 代码目录结构规划
|
||||
GOPATH下的src目录就是接下来开发程序的主要目录,所有的源码都是放在这个目录下面,那么一般我们的做法就是一个目录一个项目,例如: $GOPATH/src/mymath 表示mymath这个应用包或者可执行应用,这个根据package是main还是其他来决定,main的话就是可执行应用,其他的话就是应用包,这个会在后续详细介绍package。
|
||||
|
||||
|
||||
所以当新建应用或者一个代码包时都是在src目录下新建一个文件夹,文件夹名称一般是代码包名称,当然也允许多级目录,例如在src下面新建了目录$GOPATH/src/github.com/astaxie/beedb 那么这个包路径就是"github.com/astaxie/beedb",包名称是最后一个目录beedb
|
||||
|
||||
下面我就以mymath为例来讲述如何编写应用包,执行如下代码
|
||||
```sh
|
||||
cd $GOPATH/src
|
||||
mkdir mymath
|
||||
```
|
||||
|
||||
新建文件sqrt.go,内容如下
|
||||
```go
|
||||
// $GOPATH/src/mymath/sqrt.go源码如下:
|
||||
package mymath
|
||||
|
||||
func Sqrt(x float64) float64 {
|
||||
z := 0.0
|
||||
for i := 0; i < 1000; i++ {
|
||||
z -= (z*z - x) / (2 * x)
|
||||
}
|
||||
return z
|
||||
}
|
||||
```
|
||||
这样我的应用包目录和代码已经新建完毕,注意:一般建议package的名称和目录名保持一致
|
||||
|
||||
## 编译应用
|
||||
上面我们已经建立了自己的应用包,如何进行编译安装呢?有两种方式可以进行安装
|
||||
|
||||
1、只要进入对应的应用包目录,然后执行`go install`,就可以安装了
|
||||
|
||||
2、在任意的目录执行如下代码`go install mymath`
|
||||
|
||||
安装完之后,我们可以进入如下目录
|
||||
```sh
|
||||
cd $GOPATH/pkg/${GOOS}_${GOARCH}
|
||||
//可以看到如下文件
|
||||
mymath.a
|
||||
```
|
||||
这个.a文件是应用包,那么我们如何进行调用呢?
|
||||
|
||||
接下来我们新建一个应用程序来调用这个应用包
|
||||
|
||||
新建应用包mathapp
|
||||
```sh
|
||||
cd $GOPATH/src
|
||||
mkdir mathapp
|
||||
cd mathapp
|
||||
vim main.go
|
||||
```
|
||||
|
||||
`$GOPATH/src/mathapp/main.go`源码:
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"mymath"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Hello, world. Sqrt(2) = %v\n", mymath.Sqrt(2))
|
||||
}
|
||||
```
|
||||
|
||||
可以看到这个的package是`main`,import里面调用的包是`mymath`,这个就是相对于`$GOPATH/src`的路径,如果是多级目录,就在import里面引入多级目录,如果你有多个GOPATH,也是一样,Go会自动在多个`$GOPATH/src`中寻找。
|
||||
|
||||
如何编译程序呢?进入该应用目录,然后执行`go build`,那么在该目录下面会生成一个mathapp的可执行文件
|
||||
```sh
|
||||
./mathapp
|
||||
```
|
||||
|
||||
输出如下内容
|
||||
```sh
|
||||
Hello, world. Sqrt(2) = 1.414213562373095
|
||||
```
|
||||
|
||||
如何安装该应用,进入该目录执行`go install`,那么在$GOPATH/bin/下增加了一个可执行文件mathapp, 还记得前面我们把`$GOPATH/bin`加到我们的PATH里面了,这样可以在命令行输入如下命令就可以执行
|
||||
|
||||
```sh
|
||||
mathapp
|
||||
```
|
||||
|
||||
也是输出如下内容
|
||||
|
||||
Hello, world. Sqrt(2) = 1.414213562373095
|
||||
|
||||
这里我们展示如何编译和安装一个可运行的应用,以及如何设计我们的目录结构。
|
||||
|
||||
## 获取远程包
|
||||
go语言有一个获取远程包的工具就是`go get`,目前go get支持多数开源社区(例如:github、googlecode、bitbucket、Launchpad)
|
||||
|
||||
go get github.com/astaxie/beedb
|
||||
|
||||
>go get -u 参数可以自动更新包,而且当go get的时候会自动获取该包依赖的其他第三方包
|
||||
|
||||
通过这个命令可以获取相应的源码,对应的开源平台采用不同的源码控制工具,例如github采用git、googlecode采用hg,所以要想获取这些源码,必须先安装相应的源码控制工具
|
||||
|
||||
通过上面获取的代码在我们本地的源码相应的代码结构如下
|
||||
|
||||
$GOPATH
|
||||
src
|
||||
|--github.com
|
||||
|-astaxie
|
||||
|-beedb
|
||||
pkg
|
||||
|--相应平台
|
||||
|-github.com
|
||||
|--astaxie
|
||||
|beedb.a
|
||||
|
||||
go get本质上可以理解为首先第一步是通过源码工具clone代码到src下面,然后执行`go install`
|
||||
|
||||
在代码中如何使用远程包,很简单的就是和使用本地包一样,只要在开头import相应的路径就可以
|
||||
|
||||
import "github.com/astaxie/beedb"
|
||||
|
||||
## 程序的整体结构
|
||||
通过上面建立的我本地的mygo的目录结构如下所示
|
||||
|
||||
bin/
|
||||
mathapp
|
||||
pkg/
|
||||
平台名/ 如:darwin_amd64、linux_amd64
|
||||
mymath.a
|
||||
github.com/
|
||||
astaxie/
|
||||
beedb.a
|
||||
src/
|
||||
mathapp
|
||||
main.go
|
||||
mymath/
|
||||
sqrt.go
|
||||
github.com/
|
||||
astaxie/
|
||||
beedb/
|
||||
beedb.go
|
||||
util.go
|
||||
|
||||
从上面的结构我们可以很清晰的看到,bin目录下面存的是编译之后可执行的文件,pkg下面存放的是应用包,src下面保存的是应用源代码
|
||||
|
||||
|
||||
## links
|
||||
* [目录](<preface.md>)
|
||||
* 上一节: [安装Go](<01.1.md>)
|
||||
* 下一节: [GO 命令](<01.3.md>)
|
||||
# 1.2 GOPATH与工作空间
|
||||
|
||||
前面我们在安装Go的时候看到需要设置GOPATH变量,Go从1.1版本到1.7必须设置这个变量,而且不能和Go的安装目录一样,这个目录用来存放Go源码,Go的可运行文件,以及相应的编译之后的包文件。所以这个目录下面有三个子目录:src、bin、pkg
|
||||
|
||||
从go 1.8开始,GOPATH环境变量现在有一个默认值,如果它没有被设置。 它在Unix上默认为$HOME/go,在Windows上默认为%USERPROFILE%/go。
|
||||
## GOPATH设置
|
||||
go 命令依赖一个重要的环境变量:$GOPATH
|
||||
|
||||
Windows系统中环境变量的形式为`%GOPATH%`,本书主要使用Unix形式,Windows用户请自行替换。
|
||||
|
||||
*(注:这个不是Go安装目录。下面以笔者的工作目录为示例,如果你想不一样请把GOPATH替换成你的工作目录。)*
|
||||
|
||||
在类 Unix 环境下大概这样设置:
|
||||
```sh
|
||||
export GOPATH=/home/apple/mygo
|
||||
```
|
||||
为了方便,应该新建以上文件夹,并且上一行加入到 `.bashrc` 或者 `.zshrc` 或者自己的 `sh` 的配置文件中。
|
||||
|
||||
Windows 设置如下,新建一个环境变量名称叫做GOPATH:
|
||||
```sh
|
||||
GOPATH=c:\mygo
|
||||
```
|
||||
GOPATH允许多个目录,当有多个目录时,请注意分隔符,多个目录的时候Windows是分号,Linux系统是冒号,当有多个GOPATH时,默认会将go get的内容放在第一个目录下。
|
||||
|
||||
|
||||
以上 $GOPATH 目录约定有三个子目录:
|
||||
|
||||
- src 存放源代码(比如:.go .c .h .s等)
|
||||
- pkg 编译后生成的文件(比如:.a)
|
||||
- bin 编译后生成的可执行文件(为了方便,可以把此目录加入到 $PATH 变量中,如果有多个gopath,那么使用`${GOPATH//://bin:}/bin`添加所有的bin目录)
|
||||
|
||||
以后我所有的例子都是以mygo作为我的gopath目录
|
||||
|
||||
|
||||
## 代码目录结构规划
|
||||
GOPATH下的src目录就是接下来开发程序的主要目录,所有的源码都是放在这个目录下面,那么一般我们的做法就是一个目录一个项目,例如: $GOPATH/src/mymath 表示mymath这个应用包或者可执行应用,这个根据package是main还是其他来决定,main的话就是可执行应用,其他的话就是应用包,这个会在后续详细介绍package。
|
||||
|
||||
|
||||
所以当新建应用或者一个代码包时都是在src目录下新建一个文件夹,文件夹名称一般是代码包名称,当然也允许多级目录,例如在src下面新建了目录$GOPATH/src/github.com/astaxie/beedb 那么这个包路径就是"github.com/astaxie/beedb",包名称是最后一个目录beedb
|
||||
|
||||
下面我就以mymath为例来讲述如何编写应用包,执行如下代码
|
||||
```sh
|
||||
cd $GOPATH/src
|
||||
mkdir mymath
|
||||
```
|
||||
|
||||
新建文件sqrt.go,内容如下
|
||||
```go
|
||||
// $GOPATH/src/mymath/sqrt.go源码如下:
|
||||
package mymath
|
||||
|
||||
func Sqrt(x float64) float64 {
|
||||
z := 0.0
|
||||
for i := 0; i < 1000; i++ {
|
||||
z -= (z*z - x) / (2 * x)
|
||||
}
|
||||
return z
|
||||
}
|
||||
```
|
||||
这样我的应用包目录和代码已经新建完毕,注意:一般建议package的名称和目录名保持一致
|
||||
|
||||
## 编译应用
|
||||
上面我们已经建立了自己的应用包,如何进行编译安装呢?有两种方式可以进行安装
|
||||
|
||||
1、只要进入对应的应用包目录,然后执行`go install`,就可以安装了
|
||||
|
||||
2、在任意的目录执行如下代码`go install mymath`
|
||||
|
||||
安装完之后,我们可以进入如下目录
|
||||
```sh
|
||||
cd $GOPATH/pkg/${GOOS}_${GOARCH}
|
||||
//可以看到如下文件
|
||||
mymath.a
|
||||
```
|
||||
这个.a文件是应用包,那么我们如何进行调用呢?
|
||||
|
||||
接下来我们新建一个应用程序来调用这个应用包
|
||||
|
||||
新建应用包mathapp
|
||||
```sh
|
||||
cd $GOPATH/src
|
||||
mkdir mathapp
|
||||
cd mathapp
|
||||
vim main.go
|
||||
```
|
||||
|
||||
`$GOPATH/src/mathapp/main.go`源码:
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"mymath"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Hello, world. Sqrt(2) = %v\n", mymath.Sqrt(2))
|
||||
}
|
||||
```
|
||||
|
||||
可以看到这个的package是`main`,import里面调用的包是`mymath`,这个就是相对于`$GOPATH/src`的路径,如果是多级目录,就在import里面引入多级目录,如果你有多个GOPATH,也是一样,Go会自动在多个`$GOPATH/src`中寻找。
|
||||
|
||||
如何编译程序呢?进入该应用目录,然后执行`go build`,那么在该目录下面会生成一个mathapp的可执行文件
|
||||
```sh
|
||||
./mathapp
|
||||
```
|
||||
|
||||
输出如下内容
|
||||
```sh
|
||||
Hello, world. Sqrt(2) = 1.414213562373095
|
||||
```
|
||||
|
||||
如何安装该应用,进入该目录执行`go install`,那么在$GOPATH/bin/下增加了一个可执行文件mathapp, 还记得前面我们把`$GOPATH/bin`加到我们的PATH里面了,这样可以在命令行输入如下命令就可以执行
|
||||
|
||||
```sh
|
||||
mathapp
|
||||
```
|
||||
|
||||
也是输出如下内容
|
||||
|
||||
Hello, world. Sqrt(2) = 1.414213562373095
|
||||
|
||||
这里我们展示如何编译和安装一个可运行的应用,以及如何设计我们的目录结构。
|
||||
|
||||
## 获取远程包
|
||||
go语言有一个获取远程包的工具就是`go get`,目前go get支持多数开源社区(例如:GitHub、googlecode、bitbucket、Launchpad)
|
||||
|
||||
go get github.com/astaxie/beedb
|
||||
|
||||
>go get -u 参数可以自动更新包,而且当go get的时候会自动获取该包依赖的其他第三方包
|
||||
|
||||
通过这个命令可以获取相应的源码,对应的开源平台采用不同的源码控制工具,例如GitHub采用git、googlecode采用hg,所以要想获取这些源码,必须先安装相应的源码控制工具
|
||||
|
||||
通过上面获取的代码在我们本地的源码相应的代码结构如下
|
||||
|
||||
$GOPATH
|
||||
src
|
||||
|--github.com
|
||||
|-astaxie
|
||||
|-beedb
|
||||
pkg
|
||||
|--相应平台
|
||||
|-github.com
|
||||
|--astaxie
|
||||
|beedb.a
|
||||
|
||||
go get本质上可以理解为首先第一步是通过源码工具clone代码到src下面,然后执行`go install`
|
||||
|
||||
在代码中如何使用远程包,很简单的就是和使用本地包一样,只要在开头import相应的路径就可以
|
||||
|
||||
import "github.com/astaxie/beedb"
|
||||
|
||||
## 程序的整体结构
|
||||
通过上面建立的我本地的mygo的目录结构如下所示
|
||||
|
||||
bin/
|
||||
mathapp
|
||||
pkg/
|
||||
平台名/ 如:darwin_amd64、linux_amd64
|
||||
mymath.a
|
||||
github.com/
|
||||
astaxie/
|
||||
beedb.a
|
||||
src/
|
||||
mathapp
|
||||
main.go
|
||||
mymath/
|
||||
sqrt.go
|
||||
github.com/
|
||||
astaxie/
|
||||
beedb/
|
||||
beedb.go
|
||||
util.go
|
||||
|
||||
从上面的结构我们可以很清晰的看到,bin目录下面存的是编译之后可执行的文件,pkg下面存放的是应用包,src下面保存的是应用源代码
|
||||
|
||||
|
||||
## links
|
||||
* [目录](<preface.md>)
|
||||
* 上一节: [安装Go](<01.1.md>)
|
||||
* 下一节: [GO 命令](<01.3.md>)
|
||||
|
||||
408
zh/01.3.md
408
zh/01.3.md
@@ -1,204 +1,204 @@
|
||||
# 1.3 Go 命令
|
||||
|
||||
## Go 命令
|
||||
|
||||
Go语言自带有一套完整的命令操作工具,你可以通过在命令行中执行`go`来查看它们:
|
||||
|
||||

|
||||
|
||||
图1.3 Go命令显示详细的信息
|
||||
|
||||
这些命令对于我们平时编写的代码非常有用,接下来就让我们了解一些常用的命令。
|
||||
|
||||
## go build
|
||||
|
||||
这个命令主要用于编译代码。在包的编译过程中,若有必要,会同时编译与之相关联的包。
|
||||
|
||||
- 如果是普通包,就像我们在1.2节中编写的`mymath`包那样,当你执行`go build`之后,它不会产生任何文件。如果你需要在`$GOPATH/pkg`下生成相应的文件,那就得执行`go install`。
|
||||
|
||||
- 如果是`main`包,当你执行`go build`之后,它就会在当前目录下生成一个可执行文件。如果你需要在`$GOPATH/bin`下生成相应的文件,需要执行`go install`,或者使用`go build -o 路径/a.exe`。
|
||||
|
||||
- 如果某个项目文件夹下有多个文件,而你只想编译某个文件,就可在`go build`之后加上文件名,例如`go build a.go`;`go build`命令默认会编译当前目录下的所有go文件。
|
||||
|
||||
- 你也可以指定编译输出的文件名。例如1.2节中的`mathapp`应用,我们可以指定`go build -o astaxie.exe`,默认情况是你的package名(非main包),或者是第一个源文件的文件名(main包)。
|
||||
|
||||
(注:实际上,package名在[Go语言规范](https://golang.org/ref/spec)中指代码中“package”后使用的名称,此名称可以与文件夹名不同。默认生成的可执行文件名是文件夹名。)
|
||||
|
||||
- go build会忽略目录下以“_”或“.”开头的go文件。
|
||||
|
||||
- 如果你的源代码针对不同的操作系统需要不同的处理,那么你可以根据不同的操作系统后缀来命名文件。例如有一个读取数组的程序,它对于不同的操作系统可能有如下几个源文件:
|
||||
|
||||
array_linux.go
|
||||
array_darwin.go
|
||||
array_windows.go
|
||||
array_freebsd.go
|
||||
|
||||
`go build`的时候会选择性地编译以系统名结尾的文件(Linux、Darwin、Windows、Freebsd)。例如Linux系统下面编译只会选择array_linux.go文件,其它系统命名后缀文件全部忽略。
|
||||
|
||||
参数的介绍
|
||||
|
||||
- `-o` 指定输出的文件名,可以带上路径,例如 `go build -o a/b/c`
|
||||
- `-i` 安装相应的包,编译+`go install`
|
||||
- `-a` 更新全部已经是最新的包的,但是对标准包不适用
|
||||
- `-n` 把需要执行的编译命令打印出来,但是不执行,这样就可以很容易的知道底层是如何运行的
|
||||
- `-p n` 指定可以并行可运行的编译数目,默认是CPU数目
|
||||
- `-race` 开启编译的时候自动检测数据竞争的情况,目前只支持64位的机器
|
||||
- `-v` 打印出来我们正在编译的包名
|
||||
- `-work` 打印出来编译时候的临时文件夹名称,并且如果已经存在的话就不要删除
|
||||
- `-x` 打印出来执行的命令,其实就是和`-n`的结果类似,只是这个会执行
|
||||
- `-ccflags 'arg list'` 传递参数给5c, 6c, 8c 调用
|
||||
- `-compiler name` 指定相应的编译器,gccgo还是gc
|
||||
- `-gccgoflags 'arg list'` 传递参数给gccgo编译连接调用
|
||||
- `-gcflags 'arg list'` 传递参数给5g, 6g, 8g 调用
|
||||
- `-installsuffix suffix` 为了和默认的安装包区别开来,采用这个前缀来重新安装那些依赖的包,`-race`的时候默认已经是`-installsuffix race`,大家可以通过`-n`命令来验证
|
||||
- `-ldflags 'flag list'` 传递参数给5l, 6l, 8l 调用
|
||||
- `-tags 'tag list'` 设置在编译的时候可以适配的那些tag,详细的tag限制参考里面的 [Build Constraints](http://golang.org/pkg/go/build/)
|
||||
|
||||
## go clean
|
||||
|
||||
这个命令是用来移除当前源码包和关联源码包里面编译生成的文件。这些文件包括
|
||||
|
||||
_obj/ 旧的object目录,由Makefiles遗留
|
||||
_test/ 旧的test目录,由Makefiles遗留
|
||||
_testmain.go 旧的gotest文件,由Makefiles遗留
|
||||
test.out 旧的test记录,由Makefiles遗留
|
||||
build.out 旧的test记录,由Makefiles遗留
|
||||
*.[568ao] object文件,由Makefiles遗留
|
||||
|
||||
DIR(.exe) 由go build产生
|
||||
DIR.test(.exe) 由go test -c产生
|
||||
MAINFILE(.exe) 由go build MAINFILE.go产生
|
||||
*.so 由 SWIG 产生
|
||||
|
||||
我一般都是利用这个命令清除编译文件,然后github递交源码,在本机测试的时候这些编译文件都是和系统相关的,但是对于源码管理来说没必要。
|
||||
|
||||
$ go clean -i -n
|
||||
cd /Users/astaxie/develop/gopath/src/mathapp
|
||||
rm -f mathapp mathapp.exe mathapp.test mathapp.test.exe app app.exe
|
||||
rm -f /Users/astaxie/develop/gopath/bin/mathapp
|
||||
|
||||
参数介绍
|
||||
|
||||
- `-i` 清除关联的安装的包和可运行文件,也就是通过go install安装的文件
|
||||
- `-n` 把需要执行的清除命令打印出来,但是不执行,这样就可以很容易的知道底层是如何运行的
|
||||
- `-r` 循环的清除在import中引入的包
|
||||
- `-x` 打印出来执行的详细命令,其实就是`-n`打印的执行版本
|
||||
|
||||
## go fmt
|
||||
|
||||
有过C/C++经验的读者会知道,一些人经常为代码采取K&R风格还是ANSI风格而争论不休。在go中,代码则有标准的风格。由于之前已经有的一些习惯或其它的原因我们常将代码写成ANSI风格或者其它更合适自己的格式,这将为人们在阅读别人的代码时添加不必要的负担,所以go强制了代码格式(比如左大括号必须放在行尾),不按照此格式的代码将不能编译通过,为了减少浪费在排版上的时间,go工具集中提供了一个`go fmt`命令 它可以帮你格式化你写好的代码文件,使你写代码的时候不需要关心格式,你只需要在写完之后执行`go fmt <文件名>.go`,你的代码就被修改成了标准格式,但是我平常很少用到这个命令,因为开发工具里面一般都带了保存时候自动格式化功能,这个功能其实在底层就是调用了`go fmt`。接下来的一节我将讲述两个工具,这两个工具都自带了保存文件时自动化`go fmt`功能。
|
||||
|
||||
使用go fmt命令,其实是调用了gofmt,而且需要参数-w,否则格式化结果不会写入文件。gofmt -w -l src,可以格式化整个项目。
|
||||
|
||||
所以go fmt是gofmt的上层一个包装的命令,我们想要更多的个性化的格式化可以参考 [gofmt](http://golang.org/cmd/gofmt/)
|
||||
|
||||
gofmt的参数介绍
|
||||
|
||||
- `-l` 显示那些需要格式化的文件
|
||||
- `-w` 把改写后的内容直接写入到文件中,而不是作为结果打印到标准输出。
|
||||
- `-r` 添加形如“a[b:len(a)] -> a[b:]”的重写规则,方便我们做批量替换
|
||||
- `-s` 简化文件中的代码
|
||||
- `-d` 显示格式化前后的diff而不是写入文件,默认是false
|
||||
- `-e` 打印所有的语法错误到标准输出。如果不使用此标记,则只会打印不同行的前10个错误。
|
||||
- `-cpuprofile` 支持调试模式,写入相应的cpufile到指定的文件
|
||||
|
||||
## go get
|
||||
|
||||
这个命令是用来动态获取远程代码包的,目前支持的有BitBucket、GitHub、Google Code和Launchpad。这个命令在内部实际上分成了两步操作:第一步是下载源码包,第二步是执行`go install`。下载源码包的go工具会自动根据不同的域名调用不同的源码工具,对应关系如下:
|
||||
|
||||
BitBucket (Mercurial Git)
|
||||
GitHub (Git)
|
||||
Google Code Project Hosting (Git, Mercurial, Subversion)
|
||||
Launchpad (Bazaar)
|
||||
|
||||
所以为了`go get` 能正常工作,你必须确保安装了合适的源码管理工具,并同时把这些命令加入你的PATH中。其实`go get`支持自定义域名的功能,具体参见`go help remote`。
|
||||
|
||||
参数介绍:
|
||||
|
||||
- `-d` 只下载不安装
|
||||
- `-f` 只有在你包含了`-u`参数的时候才有效,不让`-u`去验证import中的每一个都已经获取了,这对于本地fork的包特别有用
|
||||
- `-fix` 在获取源码之后先运行fix,然后再去做其他的事情
|
||||
- `-t` 同时也下载需要为运行测试所需要的包
|
||||
- `-u` 强制使用网络去更新包和它的依赖包
|
||||
- `-v` 显示执行的命令
|
||||
|
||||
## go install
|
||||
|
||||
这个命令在内部实际上分成了两步操作:第一步是生成结果文件(可执行文件或者.a包),第二步会把编译好的结果移到`$GOPATH/pkg`或者`$GOPATH/bin`。
|
||||
|
||||
参数支持`go build`的编译参数。大家只要记住一个参数`-v`就好了,这个随时随地的可以查看底层的执行信息。
|
||||
|
||||
## go test
|
||||
|
||||
执行这个命令,会自动读取源码目录下面名为`*_test.go`的文件,生成并运行测试用的可执行文件。输出的信息类似
|
||||
|
||||
ok archive/tar 0.011s
|
||||
FAIL archive/zip 0.022s
|
||||
ok compress/gzip 0.033s
|
||||
...
|
||||
|
||||
默认的情况下,不需要任何的参数,它会自动把你源码包下面所有test文件测试完毕,当然你也可以带上参数,详情请参考`go help testflag`
|
||||
|
||||
这里我介绍几个我们常用的参数:
|
||||
|
||||
- `-bench regexp` 执行相应的benchmarks,例如 `-bench=.`
|
||||
- `-cover` 开启测试覆盖率
|
||||
- `-run regexp` 只运行regexp匹配的函数,例如 `-run=Array` 那么就执行包含有Array开头的函数
|
||||
- `-v` 显示测试的详细命令
|
||||
|
||||
## go tool
|
||||
`go tool`下面下载聚集了很多命令,这里我们只介绍两个,fix和vet
|
||||
|
||||
- `go tool fix .` 用来修复以前老版本的代码到新版本,例如go1之前老版本的代码转化到go1,例如API的变化
|
||||
- `go tool vet directory|files` 用来分析当前目录的代码是否都是正确的代码,例如是不是调用fmt.Printf里面的参数不正确,例如函数里面提前return了然后出现了无用代码之类的。
|
||||
|
||||
## go generate
|
||||
这个命令是从Go1.4开始才设计的,用于在编译前自动化生成某类代码。`go generate`和`go build`是完全不一样的命令,通过分析源码中特殊的注释,然后执行相应的命令。这些命令都是很明确的,没有任何的依赖在里面。而且大家在用这个之前心里面一定要有一个理念,这个`go generate`是给你用的,不是给使用你这个包的人用的,是方便你来生成一些代码的。
|
||||
|
||||
这里我们来举一个简单的例子,例如我们经常会使用`yacc`来生成代码,那么我们常用这样的命令:
|
||||
|
||||
go tool yacc -o gopher.go -p parser gopher.y
|
||||
|
||||
-o 指定了输出的文件名, -p指定了package的名称,这是一个单独的命令,如果我们想让`go generate`来触发这个命令,那么就可以在当前目录的任意一个`xxx.go`文件里面的任意位置增加一行如下的注释:
|
||||
|
||||
//go:generate go tool yacc -o gopher.go -p parser gopher.y
|
||||
|
||||
这里我们注意了,`//go:generate`是没有任何空格的,这其实就是一个固定的格式,在扫描源码文件的时候就是根据这个来判断的。
|
||||
|
||||
所以我们可以通过如下的命令来生成,编译,测试。如果`gopher.y`文件有修改,那么就重新执行`go generate`重新生成文件就好。
|
||||
|
||||
$ go generate
|
||||
$ go build
|
||||
$ go test
|
||||
|
||||
|
||||
## godoc
|
||||
|
||||
在Go1.2版本之前还支持`go doc`命令,但是之后全部移到了godoc这个命令下,需要这样安装`go get golang.org/x/tools/cmd/godoc`
|
||||
|
||||
很多人说go不需要任何的第三方文档,例如chm手册之类的(其实我已经做了一个了,[chm手册](https://github.com/astaxie/godoc)),因为它内部就有一个很强大的文档工具。
|
||||
|
||||
如何查看相应package的文档呢?
|
||||
例如builtin包,那么执行`godoc builtin`
|
||||
如果是http包,那么执行`godoc net/http`
|
||||
查看某一个包里面的函数,那么执行`godoc fmt Printf`
|
||||
也可以查看相应的代码,执行`godoc -src fmt Printf`
|
||||
|
||||
通过命令在命令行执行 godoc -http=:端口号 比如`godoc -http=:8080`。然后在浏览器中打开`127.0.0.1:8080`,你将会看到一个golang.org的本地copy版本,通过它你可以查询pkg文档等其它内容。如果你设置了GOPATH,在pkg分类下,不但会列出标准包的文档,还会列出你本地`GOPATH`中所有项目的相关文档,这对于经常被墙的用户来说是一个不错的选择。
|
||||
|
||||
## 其它命令
|
||||
|
||||
go还提供了其它很多的工具,例如下面的这些工具
|
||||
|
||||
go version 查看go当前的版本
|
||||
go env 查看当前go的环境变量
|
||||
go list 列出当前全部安装的package
|
||||
go run 编译并运行Go程序
|
||||
|
||||
以上这些工具还有很多参数没有一一介绍,用户可以使用`go help 命令`获取更详细的帮助信息。
|
||||
|
||||
|
||||
## links
|
||||
* [目录](<preface.md>)
|
||||
* 上一节: [GOPATH与工作空间](<01.2.md>)
|
||||
* 下一节: [Go开发工具](<01.4.md>)
|
||||
# 1.3 Go 命令
|
||||
|
||||
## Go 命令
|
||||
|
||||
Go语言自带有一套完整的命令操作工具,你可以通过在命令行中执行`go`来查看它们:
|
||||
|
||||

|
||||
|
||||
图1.3 Go命令显示详细的信息
|
||||
|
||||
这些命令对于我们平时编写的代码非常有用,接下来就让我们了解一些常用的命令。
|
||||
|
||||
## go build
|
||||
|
||||
这个命令主要用于编译代码。在包的编译过程中,若有必要,会同时编译与之相关联的包。
|
||||
|
||||
- 如果是普通包,就像我们在1.2节中编写的`mymath`包那样,当你执行`go build`之后,它不会产生任何文件。如果你需要在`$GOPATH/pkg`下生成相应的文件,那就得执行`go install`。
|
||||
|
||||
- 如果是`main`包,当你执行`go build`之后,它就会在当前目录下生成一个可执行文件。如果你需要在`$GOPATH/bin`下生成相应的文件,需要执行`go install`,或者使用`go build -o 路径/a.exe`。
|
||||
|
||||
- 如果某个项目文件夹下有多个文件,而你只想编译某个文件,就可在`go build`之后加上文件名,例如`go build a.go`;`go build`命令默认会编译当前目录下的所有go文件。
|
||||
|
||||
- 你也可以指定编译输出的文件名。例如1.2节中的`mathapp`应用,我们可以指定`go build -o astaxie.exe`,默认情况是你的package名(非main包),或者是第一个源文件的文件名(main包)。
|
||||
|
||||
(注:实际上,package名在[Go语言规范](https://golang.org/ref/spec)中指代码中“package”后使用的名称,此名称可以与文件夹名不同。默认生成的可执行文件名是文件夹名。)
|
||||
|
||||
- go build会忽略目录下以“_”或“.”开头的go文件。
|
||||
|
||||
- 如果你的源代码针对不同的操作系统需要不同的处理,那么你可以根据不同的操作系统后缀来命名文件。例如有一个读取数组的程序,它对于不同的操作系统可能有如下几个源文件:
|
||||
|
||||
array_linux.go
|
||||
array_darwin.go
|
||||
array_windows.go
|
||||
array_freebsd.go
|
||||
|
||||
`go build`的时候会选择性地编译以系统名结尾的文件(Linux、Darwin、Windows、Freebsd)。例如Linux系统下面编译只会选择array_linux.go文件,其它系统命名后缀文件全部忽略。
|
||||
|
||||
参数的介绍
|
||||
|
||||
- `-o` 指定输出的文件名,可以带上路径,例如 `go build -o a/b/c`
|
||||
- `-i` 安装相应的包,编译+`go install`
|
||||
- `-a` 更新全部已经是最新的包的,但是对标准包不适用
|
||||
- `-n` 把需要执行的编译命令打印出来,但是不执行,这样就可以很容易的知道底层是如何运行的
|
||||
- `-p n` 指定可以并行可运行的编译数目,默认是CPU数目
|
||||
- `-race` 开启编译的时候自动检测数据竞争的情况,目前只支持64位的机器
|
||||
- `-v` 打印出来我们正在编译的包名
|
||||
- `-work` 打印出来编译时候的临时文件夹名称,并且如果已经存在的话就不要删除
|
||||
- `-x` 打印出来执行的命令,其实就是和`-n`的结果类似,只是这个会执行
|
||||
- `-ccflags 'arg list'` 传递参数给5c, 6c, 8c 调用
|
||||
- `-compiler name` 指定相应的编译器,gccgo还是gc
|
||||
- `-gccgoflags 'arg list'` 传递参数给gccgo编译连接调用
|
||||
- `-gcflags 'arg list'` 传递参数给5g, 6g, 8g 调用
|
||||
- `-installsuffix suffix` 为了和默认的安装包区别开来,采用这个前缀来重新安装那些依赖的包,`-race`的时候默认已经是`-installsuffix race`,大家可以通过`-n`命令来验证
|
||||
- `-ldflags 'flag list'` 传递参数给5l, 6l, 8l 调用
|
||||
- `-tags 'tag list'` 设置在编译的时候可以适配的那些tag,详细的tag限制参考里面的 [Build Constraints](http://golang.org/pkg/go/build/)
|
||||
|
||||
## go clean
|
||||
|
||||
这个命令是用来移除当前源码包和关联源码包里面编译生成的文件。这些文件包括
|
||||
|
||||
_obj/ 旧的object目录,由Makefiles遗留
|
||||
_test/ 旧的test目录,由Makefiles遗留
|
||||
_testmain.go 旧的gotest文件,由Makefiles遗留
|
||||
test.out 旧的test记录,由Makefiles遗留
|
||||
build.out 旧的test记录,由Makefiles遗留
|
||||
*.[568ao] object文件,由Makefiles遗留
|
||||
|
||||
DIR(.exe) 由go build产生
|
||||
DIR.test(.exe) 由go test -c产生
|
||||
MAINFILE(.exe) 由go build MAINFILE.go产生
|
||||
*.so 由 SWIG 产生
|
||||
|
||||
我一般都是利用这个命令清除编译文件,然后GitHub递交源码,在本机测试的时候这些编译文件都是和系统相关的,但是对于源码管理来说没必要。
|
||||
|
||||
$ go clean -i -n
|
||||
cd /Users/astaxie/develop/gopath/src/mathapp
|
||||
rm -f mathapp mathapp.exe mathapp.test mathapp.test.exe app app.exe
|
||||
rm -f /Users/astaxie/develop/gopath/bin/mathapp
|
||||
|
||||
参数介绍
|
||||
|
||||
- `-i` 清除关联的安装的包和可运行文件,也就是通过go install安装的文件
|
||||
- `-n` 把需要执行的清除命令打印出来,但是不执行,这样就可以很容易的知道底层是如何运行的
|
||||
- `-r` 循环的清除在import中引入的包
|
||||
- `-x` 打印出来执行的详细命令,其实就是`-n`打印的执行版本
|
||||
|
||||
## go fmt
|
||||
|
||||
有过C/C++经验的读者会知道,一些人经常为代码采取K&R风格还是ANSI风格而争论不休。在go中,代码则有标准的风格。由于之前已经有的一些习惯或其它的原因我们常将代码写成ANSI风格或者其它更合适自己的格式,这将为人们在阅读别人的代码时添加不必要的负担,所以go强制了代码格式(比如左大括号必须放在行尾),不按照此格式的代码将不能编译通过,为了减少浪费在排版上的时间,go工具集中提供了一个`go fmt`命令 它可以帮你格式化你写好的代码文件,使你写代码的时候不需要关心格式,你只需要在写完之后执行`go fmt <文件名>.go`,你的代码就被修改成了标准格式,但是我平常很少用到这个命令,因为开发工具里面一般都带了保存时候自动格式化功能,这个功能其实在底层就是调用了`go fmt`。接下来的一节我将讲述两个工具,这两个工具都自带了保存文件时自动化`go fmt`功能。
|
||||
|
||||
使用go fmt命令,其实是调用了gofmt,而且需要参数-w,否则格式化结果不会写入文件。gofmt -w -l src,可以格式化整个项目。
|
||||
|
||||
所以go fmt是gofmt的上层一个包装的命令,我们想要更多的个性化的格式化可以参考 [gofmt](http://golang.org/cmd/gofmt/)
|
||||
|
||||
gofmt的参数介绍
|
||||
|
||||
- `-l` 显示那些需要格式化的文件
|
||||
- `-w` 把改写后的内容直接写入到文件中,而不是作为结果打印到标准输出。
|
||||
- `-r` 添加形如“a[b:len(a)] -> a[b:]”的重写规则,方便我们做批量替换
|
||||
- `-s` 简化文件中的代码
|
||||
- `-d` 显示格式化前后的diff而不是写入文件,默认是false
|
||||
- `-e` 打印所有的语法错误到标准输出。如果不使用此标记,则只会打印不同行的前10个错误。
|
||||
- `-cpuprofile` 支持调试模式,写入相应的cpufile到指定的文件
|
||||
|
||||
## go get
|
||||
|
||||
这个命令是用来动态获取远程代码包的,目前支持的有BitBucket、GitHub、Google Code和Launchpad。这个命令在内部实际上分成了两步操作:第一步是下载源码包,第二步是执行`go install`。下载源码包的go工具会自动根据不同的域名调用不同的源码工具,对应关系如下:
|
||||
|
||||
BitBucket (Mercurial Git)
|
||||
GitHub (Git)
|
||||
Google Code Project Hosting (Git, Mercurial, Subversion)
|
||||
Launchpad (Bazaar)
|
||||
|
||||
所以为了`go get` 能正常工作,你必须确保安装了合适的源码管理工具,并同时把这些命令加入你的PATH中。其实`go get`支持自定义域名的功能,具体参见`go help remote`。
|
||||
|
||||
参数介绍:
|
||||
|
||||
- `-d` 只下载不安装
|
||||
- `-f` 只有在你包含了`-u`参数的时候才有效,不让`-u`去验证import中的每一个都已经获取了,这对于本地fork的包特别有用
|
||||
- `-fix` 在获取源码之后先运行fix,然后再去做其他的事情
|
||||
- `-t` 同时也下载需要为运行测试所需要的包
|
||||
- `-u` 强制使用网络去更新包和它的依赖包
|
||||
- `-v` 显示执行的命令
|
||||
|
||||
## go install
|
||||
|
||||
这个命令在内部实际上分成了两步操作:第一步是生成结果文件(可执行文件或者.a包),第二步会把编译好的结果移到`$GOPATH/pkg`或者`$GOPATH/bin`。
|
||||
|
||||
参数支持`go build`的编译参数。大家只要记住一个参数`-v`就好了,这个随时随地的可以查看底层的执行信息。
|
||||
|
||||
## go test
|
||||
|
||||
执行这个命令,会自动读取源码目录下面名为`*_test.go`的文件,生成并运行测试用的可执行文件。输出的信息类似
|
||||
|
||||
ok archive/tar 0.011s
|
||||
FAIL archive/zip 0.022s
|
||||
ok compress/gzip 0.033s
|
||||
...
|
||||
|
||||
默认的情况下,不需要任何的参数,它会自动把你源码包下面所有test文件测试完毕,当然你也可以带上参数,详情请参考`go help testflag`
|
||||
|
||||
这里我介绍几个我们常用的参数:
|
||||
|
||||
- `-bench regexp` 执行相应的benchmarks,例如 `-bench=.`
|
||||
- `-cover` 开启测试覆盖率
|
||||
- `-run regexp` 只运行regexp匹配的函数,例如 `-run=Array` 那么就执行包含有Array开头的函数
|
||||
- `-v` 显示测试的详细命令
|
||||
|
||||
## go tool
|
||||
`go tool`下面下载聚集了很多命令,这里我们只介绍两个,fix和vet
|
||||
|
||||
- `go tool fix .` 用来修复以前老版本的代码到新版本,例如go1之前老版本的代码转化到go1,例如API的变化
|
||||
- `go tool vet directory|files` 用来分析当前目录的代码是否都是正确的代码,例如是不是调用fmt.Printf里面的参数不正确,例如函数里面提前return了然后出现了无用代码之类的。
|
||||
|
||||
## go generate
|
||||
这个命令是从Go1.4开始才设计的,用于在编译前自动化生成某类代码。`go generate`和`go build`是完全不一样的命令,通过分析源码中特殊的注释,然后执行相应的命令。这些命令都是很明确的,没有任何的依赖在里面。而且大家在用这个之前心里面一定要有一个理念,这个`go generate`是给你用的,不是给使用你这个包的人用的,是方便你来生成一些代码的。
|
||||
|
||||
这里我们来举一个简单的例子,例如我们经常会使用`yacc`来生成代码,那么我们常用这样的命令:
|
||||
|
||||
go tool yacc -o gopher.go -p parser gopher.y
|
||||
|
||||
-o 指定了输出的文件名, -p指定了package的名称,这是一个单独的命令,如果我们想让`go generate`来触发这个命令,那么就可以在当前目录的任意一个`xxx.go`文件里面的任意位置增加一行如下的注释:
|
||||
|
||||
//go:generate go tool yacc -o gopher.go -p parser gopher.y
|
||||
|
||||
这里我们注意了,`//go:generate`是没有任何空格的,这其实就是一个固定的格式,在扫描源码文件的时候就是根据这个来判断的。
|
||||
|
||||
所以我们可以通过如下的命令来生成,编译,测试。如果`gopher.y`文件有修改,那么就重新执行`go generate`重新生成文件就好。
|
||||
|
||||
$ go generate
|
||||
$ go build
|
||||
$ go test
|
||||
|
||||
|
||||
## godoc
|
||||
|
||||
在Go1.2版本之前还支持`go doc`命令,但是之后全部移到了godoc这个命令下,需要这样安装`go get golang.org/x/tools/cmd/godoc`
|
||||
|
||||
很多人说go不需要任何的第三方文档,例如chm手册之类的(其实我已经做了一个了,[chm手册](https://github.com/astaxie/godoc)),因为它内部就有一个很强大的文档工具。
|
||||
|
||||
如何查看相应package的文档呢?
|
||||
例如builtin包,那么执行`godoc builtin`
|
||||
如果是http包,那么执行`godoc net/http`
|
||||
查看某一个包里面的函数,那么执行`godoc fmt Printf`
|
||||
也可以查看相应的代码,执行`godoc -src fmt Printf`
|
||||
|
||||
通过命令在命令行执行 godoc -http=:端口号 比如`godoc -http=:8080`。然后在浏览器中打开`127.0.0.1:8080`,你将会看到一个golang.org的本地copy版本,通过它你可以查询pkg文档等其它内容。如果你设置了GOPATH,在pkg分类下,不但会列出标准包的文档,还会列出你本地`GOPATH`中所有项目的相关文档,这对于经常被墙的用户来说是一个不错的选择。
|
||||
|
||||
## 其它命令
|
||||
|
||||
go还提供了其它很多的工具,例如下面的这些工具
|
||||
|
||||
go version 查看go当前的版本
|
||||
go env 查看当前go的环境变量
|
||||
go list 列出当前全部安装的package
|
||||
go run 编译并运行Go程序
|
||||
|
||||
以上这些工具还有很多参数没有一一介绍,用户可以使用`go help 命令`获取更详细的帮助信息。
|
||||
|
||||
|
||||
## links
|
||||
* [目录](<preface.md>)
|
||||
* 上一节: [GOPATH与工作空间](<01.2.md>)
|
||||
* 下一节: [Go开发工具](<01.4.md>)
|
||||
|
||||
1272
zh/01.4.md
1272
zh/01.4.md
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@ Go实现的支持PostgreSQL的驱动也很多,因为国外很多人在开发
|
||||
- https://github.com/jbarham/gopgsqldriver 支持database/sql驱动,纯Go写的
|
||||
- https://github.com/lxn/go-pgsql 支持database/sql驱动,纯Go写的
|
||||
|
||||
在下面的示例中我采用了第一个驱动,因为它目前使用的人最多,在github上也比较活跃。
|
||||
在下面的示例中我采用了第一个驱动,因为它目前使用的人最多,在GitHub上也比较活跃。
|
||||
|
||||
## 实例代码
|
||||
数据库建表语句:
|
||||
|
||||
14
zh/13.6.md
14
zh/13.6.md
@@ -1,7 +1,7 @@
|
||||
# 13.6 小结
|
||||
这一章我们主要介绍了如何实现一个基础的Go语言框架,框架包含有路由设计,由于Go内置的http包中路由的一些不足点,我们设计了动态路由规则,然后介绍了MVC模式中的Controller设计,controller实现了REST的实现,这个主要思路来源于tornado框架,然后设计实现了模板的layout以及自动化渲染等技术,主要采用了Go内置的模板引擎,最后我们介绍了一些辅助的日志、配置等信息的设计,通过这些设计我们实现了一个基础的框架beego,目前该框架已经开源在github,最后我们通过beego实现了一个博客系统,通过实例代码详细的展现了如何快速的开发一个站点。
|
||||
|
||||
## links
|
||||
* [目录](<preface.md>)
|
||||
* 上一章: [实现博客的增删改](<13.5.md>)
|
||||
* 下一节: [扩展Web框架](<14.0.md>)
|
||||
# 13.6 小结
|
||||
这一章我们主要介绍了如何实现一个基础的Go语言框架,框架包含有路由设计,由于Go内置的http包中路由的一些不足点,我们设计了动态路由规则,然后介绍了MVC模式中的Controller设计,controller实现了REST的实现,这个主要思路来源于tornado框架,然后设计实现了模板的layout以及自动化渲染等技术,主要采用了Go内置的模板引擎,最后我们介绍了一些辅助的日志、配置等信息的设计,通过这些设计我们实现了一个基础的框架beego,目前该框架已经开源在GitHub,最后我们通过beego实现了一个博客系统,通过实例代码详细的展现了如何快速的开发一个站点。
|
||||
|
||||
## links
|
||||
* [目录](<preface.md>)
|
||||
* 上一章: [实现博客的增删改](<13.5.md>)
|
||||
* 下一节: [扩展Web框架](<14.0.md>)
|
||||
|
||||
530
zh/14.4.md
530
zh/14.4.md
@@ -1,265 +1,265 @@
|
||||
# 14.4 用户认证
|
||||
在开发Web应用过程中,用户认证是开发者经常遇到的问题,用户登录、注册、登出等操作,而一般认证也分为三个方面的认证
|
||||
|
||||
- HTTP Basic和 HTTP Digest认证
|
||||
- 第三方集成认证:QQ、微博、豆瓣、OPENID、google、github、facebook和twitter等
|
||||
- 自定义的用户登录、注册、登出,一般都是基于session、cookie认证
|
||||
|
||||
beego目前没有针对这三种方式进行任何形式的集成,但是可以充分的利用第三方开源库来实现上面的三种方式的用户认证,不过后续beego会对前面两种认证逐步集成。
|
||||
|
||||
## HTTP Basic和 HTTP Digest认证
|
||||
这两个认证是一些应用采用的比较简单的认证,目前已经有开源的第三方库支持这两个认证:
|
||||
```Go
|
||||
|
||||
github.com/abbot/go-http-auth
|
||||
```
|
||||
下面代码演示了如何把这个库引入beego中从而实现认证:
|
||||
```Go
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/abbot/go-http-auth"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
func Secret(user, realm string) string {
|
||||
if user == "john" {
|
||||
// password is "hello"
|
||||
return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type MainController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *MainController) Prepare() {
|
||||
a := auth.NewBasicAuthenticator("example.com", Secret)
|
||||
if username := a.CheckAuth(this.Ctx.Request); username == "" {
|
||||
a.RequireAuth(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *MainController) Get() {
|
||||
this.Data["Username"] = "astaxie"
|
||||
this.Data["Email"] = "astaxie@gmail.com"
|
||||
this.TplNames = "index.tpl"
|
||||
}
|
||||
```
|
||||
上面代码利用了beego的prepare函数,在执行正常逻辑之前调用了认证函数,这样就非常简单的实现了http auth,digest的认证也是同样的原理。
|
||||
|
||||
## oauth和oauth2的认证
|
||||
oauth和oauth2是目前比较流行的两种认证方式,还好第三方有一个库实现了这个认证,但是是国外实现的,并没有QQ、微博之类的国内应用认证集成:
|
||||
```Go
|
||||
|
||||
github.com/bradrydzewski/go.auth
|
||||
```
|
||||
下面代码演示了如何把该库引入beego中从而实现oauth的认证,这里以github为例演示:
|
||||
|
||||
1. 添加两条路由
|
||||
```Go
|
||||
|
||||
beego.RegisterController("/auth/login", &controllers.GithubController{})
|
||||
beego.RegisterController("/mainpage", &controllers.PageController{})
|
||||
```
|
||||
2. 然后我们处理GithubController登陆的页面:
|
||||
```Go
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/bradrydzewski/go.auth"
|
||||
)
|
||||
|
||||
const (
|
||||
githubClientKey = "a0864ea791ce7e7bd0df"
|
||||
githubSecretKey = "a0ec09a647a688a64a28f6190b5a0d2705df56ca"
|
||||
)
|
||||
|
||||
type GithubController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *GithubController) Get() {
|
||||
// set the auth parameters
|
||||
auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV")
|
||||
auth.Config.LoginSuccessRedirect = "/mainpage"
|
||||
auth.Config.CookieSecure = false
|
||||
|
||||
githubHandler := auth.Github(githubClientKey, githubSecretKey)
|
||||
|
||||
githubHandler.ServeHTTP(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
}
|
||||
|
||||
```
|
||||
3. 处理登陆成功之后的页面
|
||||
```Go
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/bradrydzewski/go.auth"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type PageController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *PageController) Get() {
|
||||
// set the auth parameters
|
||||
auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV")
|
||||
auth.Config.LoginSuccessRedirect = "/mainpage"
|
||||
auth.Config.CookieSecure = false
|
||||
|
||||
user, err := auth.GetUserCookie(this.Ctx.Request)
|
||||
|
||||
//if no active user session then authorize user
|
||||
if err != nil || user.Id() == "" {
|
||||
http.Redirect(this.Ctx.ResponseWriter, this.Ctx.Request, auth.Config.LoginRedirect, http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
//else, add the user to the URL and continue
|
||||
this.Ctx.Request.URL.User = url.User(user.Id())
|
||||
this.Data["pic"] = user.Picture()
|
||||
this.Data["id"] = user.Id()
|
||||
this.Data["name"] = user.Name()
|
||||
this.TplNames = "home.tpl"
|
||||
}
|
||||
|
||||
```
|
||||
整个的流程如下,首先打开浏览器输入地址:
|
||||
|
||||

|
||||
|
||||
图14.4 显示带有登录按钮的首页
|
||||
|
||||
然后点击链接出现如下界面:
|
||||
|
||||

|
||||
|
||||
图14.5 点击登录按钮后显示github的授权页
|
||||
|
||||
然后点击Authorize app就出现如下界面:
|
||||
|
||||

|
||||
|
||||
图14.6 授权登录之后显示的获取到的github信息页
|
||||
|
||||
## 自定义认证
|
||||
自定义的认证一般都是和session结合验证的,如下代码来源于一个基于beego的开源博客:
|
||||
```Go
|
||||
|
||||
//登陆处理
|
||||
func (this *LoginController) Post() {
|
||||
this.TplNames = "login.tpl"
|
||||
this.Ctx.Request.ParseForm()
|
||||
username := this.Ctx.Request.Form.Get("username")
|
||||
password := this.Ctx.Request.Form.Get("password")
|
||||
md5Password := md5.New()
|
||||
io.WriteString(md5Password, password)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
fmt.Fprintf(buffer, "%x", md5Password.Sum(nil))
|
||||
newPass := buffer.String()
|
||||
|
||||
now := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
userInfo := models.GetUserInfo(username)
|
||||
if userInfo.Password == newPass {
|
||||
var users models.User
|
||||
users.Last_logintime = now
|
||||
models.UpdateUserInfo(users)
|
||||
|
||||
//登录成功设置session
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess.Set("uid", userInfo.Id)
|
||||
sess.Set("uname", userInfo.Username)
|
||||
|
||||
this.Ctx.Redirect(302, "/")
|
||||
}
|
||||
}
|
||||
|
||||
//注册处理
|
||||
func (this *RegController) Post() {
|
||||
this.TplNames = "reg.tpl"
|
||||
this.Ctx.Request.ParseForm()
|
||||
username := this.Ctx.Request.Form.Get("username")
|
||||
password := this.Ctx.Request.Form.Get("password")
|
||||
usererr := checkUsername(username)
|
||||
fmt.Println(usererr)
|
||||
if usererr == false {
|
||||
this.Data["UsernameErr"] = "Username error, Please to again"
|
||||
return
|
||||
}
|
||||
|
||||
passerr := checkPassword(password)
|
||||
if passerr == false {
|
||||
this.Data["PasswordErr"] = "Password error, Please to again"
|
||||
return
|
||||
}
|
||||
|
||||
md5Password := md5.New()
|
||||
io.WriteString(md5Password, password)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
fmt.Fprintf(buffer, "%x", md5Password.Sum(nil))
|
||||
newPass := buffer.String()
|
||||
|
||||
now := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
userInfo := models.GetUserInfo(username)
|
||||
|
||||
if userInfo.Username == "" {
|
||||
var users models.User
|
||||
users.Username = username
|
||||
users.Password = newPass
|
||||
users.Created = now
|
||||
users.Last_logintime = now
|
||||
models.AddUser(users)
|
||||
|
||||
//登录成功设置session
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess.Set("uid", userInfo.Id)
|
||||
sess.Set("uname", userInfo.Username)
|
||||
this.Ctx.Redirect(302, "/")
|
||||
} else {
|
||||
this.Data["UsernameErr"] = "User already exists"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func checkPassword(password string) (b bool) {
|
||||
if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", password); !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func checkUsername(username string) (b bool) {
|
||||
if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", username); !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
```
|
||||
有了用户登陆和注册之后,其他模块的地方可以增加如下这样的用户是否登陆的判断:
|
||||
```Go
|
||||
|
||||
func (this *AddBlogController) Prepare() {
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess_uid := sess.Get("userid")
|
||||
sess_username := sess.Get("username")
|
||||
if sess_uid == nil {
|
||||
this.Ctx.Redirect(302, "/admin/login")
|
||||
return
|
||||
}
|
||||
this.Data["Username"] = sess_username
|
||||
}
|
||||
```
|
||||
## links
|
||||
* [目录](<preface.md>)
|
||||
* 上一节: [表单及验证支持](<14.3.md>)
|
||||
* 下一节: [多语言支持](<14.5.md>)
|
||||
# 14.4 用户认证
|
||||
在开发Web应用过程中,用户认证是开发者经常遇到的问题,用户登录、注册、登出等操作,而一般认证也分为三个方面的认证
|
||||
|
||||
- HTTP Basic和 HTTP Digest认证
|
||||
- 第三方集成认证:QQ、微博、豆瓣、OPENID、google、GitHub、facebook和twitter等
|
||||
- 自定义的用户登录、注册、登出,一般都是基于session、cookie认证
|
||||
|
||||
beego目前没有针对这三种方式进行任何形式的集成,但是可以充分的利用第三方开源库来实现上面的三种方式的用户认证,不过后续beego会对前面两种认证逐步集成。
|
||||
|
||||
## HTTP Basic和 HTTP Digest认证
|
||||
这两个认证是一些应用采用的比较简单的认证,目前已经有开源的第三方库支持这两个认证:
|
||||
```Go
|
||||
|
||||
github.com/abbot/go-http-auth
|
||||
```
|
||||
下面代码演示了如何把这个库引入beego中从而实现认证:
|
||||
```Go
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/abbot/go-http-auth"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
func Secret(user, realm string) string {
|
||||
if user == "john" {
|
||||
// password is "hello"
|
||||
return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type MainController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *MainController) Prepare() {
|
||||
a := auth.NewBasicAuthenticator("example.com", Secret)
|
||||
if username := a.CheckAuth(this.Ctx.Request); username == "" {
|
||||
a.RequireAuth(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *MainController) Get() {
|
||||
this.Data["Username"] = "astaxie"
|
||||
this.Data["Email"] = "astaxie@gmail.com"
|
||||
this.TplNames = "index.tpl"
|
||||
}
|
||||
```
|
||||
上面代码利用了beego的prepare函数,在执行正常逻辑之前调用了认证函数,这样就非常简单的实现了http auth,digest的认证也是同样的原理。
|
||||
|
||||
## oauth和oauth2的认证
|
||||
oauth和oauth2是目前比较流行的两种认证方式,还好第三方有一个库实现了这个认证,但是是国外实现的,并没有QQ、微博之类的国内应用认证集成:
|
||||
```Go
|
||||
|
||||
github.com/bradrydzewski/go.auth
|
||||
```
|
||||
下面代码演示了如何把该库引入beego中从而实现oauth的认证,这里以GitHub为例演示:
|
||||
|
||||
1. 添加两条路由
|
||||
```Go
|
||||
|
||||
beego.RegisterController("/auth/login", &controllers.GithubController{})
|
||||
beego.RegisterController("/mainpage", &controllers.PageController{})
|
||||
```
|
||||
2. 然后我们处理GithubController登陆的页面:
|
||||
```Go
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/bradrydzewski/go.auth"
|
||||
)
|
||||
|
||||
const (
|
||||
githubClientKey = "a0864ea791ce7e7bd0df"
|
||||
githubSecretKey = "a0ec09a647a688a64a28f6190b5a0d2705df56ca"
|
||||
)
|
||||
|
||||
type GithubController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *GithubController) Get() {
|
||||
// set the auth parameters
|
||||
auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV")
|
||||
auth.Config.LoginSuccessRedirect = "/mainpage"
|
||||
auth.Config.CookieSecure = false
|
||||
|
||||
githubHandler := auth.Github(githubClientKey, githubSecretKey)
|
||||
|
||||
githubHandler.ServeHTTP(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
}
|
||||
|
||||
```
|
||||
3. 处理登陆成功之后的页面
|
||||
```Go
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/bradrydzewski/go.auth"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type PageController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *PageController) Get() {
|
||||
// set the auth parameters
|
||||
auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV")
|
||||
auth.Config.LoginSuccessRedirect = "/mainpage"
|
||||
auth.Config.CookieSecure = false
|
||||
|
||||
user, err := auth.GetUserCookie(this.Ctx.Request)
|
||||
|
||||
//if no active user session then authorize user
|
||||
if err != nil || user.Id() == "" {
|
||||
http.Redirect(this.Ctx.ResponseWriter, this.Ctx.Request, auth.Config.LoginRedirect, http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
//else, add the user to the URL and continue
|
||||
this.Ctx.Request.URL.User = url.User(user.Id())
|
||||
this.Data["pic"] = user.Picture()
|
||||
this.Data["id"] = user.Id()
|
||||
this.Data["name"] = user.Name()
|
||||
this.TplNames = "home.tpl"
|
||||
}
|
||||
|
||||
```
|
||||
整个的流程如下,首先打开浏览器输入地址:
|
||||
|
||||

|
||||
|
||||
图14.4 显示带有登录按钮的首页
|
||||
|
||||
然后点击链接出现如下界面:
|
||||
|
||||

|
||||
|
||||
图14.5 点击登录按钮后显示GitHub的授权页
|
||||
|
||||
然后点击Authorize app就出现如下界面:
|
||||
|
||||

|
||||
|
||||
图14.6 授权登录之后显示的获取到的GitHub信息页
|
||||
|
||||
## 自定义认证
|
||||
自定义的认证一般都是和session结合验证的,如下代码来源于一个基于beego的开源博客:
|
||||
```Go
|
||||
|
||||
//登陆处理
|
||||
func (this *LoginController) Post() {
|
||||
this.TplNames = "login.tpl"
|
||||
this.Ctx.Request.ParseForm()
|
||||
username := this.Ctx.Request.Form.Get("username")
|
||||
password := this.Ctx.Request.Form.Get("password")
|
||||
md5Password := md5.New()
|
||||
io.WriteString(md5Password, password)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
fmt.Fprintf(buffer, "%x", md5Password.Sum(nil))
|
||||
newPass := buffer.String()
|
||||
|
||||
now := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
userInfo := models.GetUserInfo(username)
|
||||
if userInfo.Password == newPass {
|
||||
var users models.User
|
||||
users.Last_logintime = now
|
||||
models.UpdateUserInfo(users)
|
||||
|
||||
//登录成功设置session
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess.Set("uid", userInfo.Id)
|
||||
sess.Set("uname", userInfo.Username)
|
||||
|
||||
this.Ctx.Redirect(302, "/")
|
||||
}
|
||||
}
|
||||
|
||||
//注册处理
|
||||
func (this *RegController) Post() {
|
||||
this.TplNames = "reg.tpl"
|
||||
this.Ctx.Request.ParseForm()
|
||||
username := this.Ctx.Request.Form.Get("username")
|
||||
password := this.Ctx.Request.Form.Get("password")
|
||||
usererr := checkUsername(username)
|
||||
fmt.Println(usererr)
|
||||
if usererr == false {
|
||||
this.Data["UsernameErr"] = "Username error, Please to again"
|
||||
return
|
||||
}
|
||||
|
||||
passerr := checkPassword(password)
|
||||
if passerr == false {
|
||||
this.Data["PasswordErr"] = "Password error, Please to again"
|
||||
return
|
||||
}
|
||||
|
||||
md5Password := md5.New()
|
||||
io.WriteString(md5Password, password)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
fmt.Fprintf(buffer, "%x", md5Password.Sum(nil))
|
||||
newPass := buffer.String()
|
||||
|
||||
now := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
userInfo := models.GetUserInfo(username)
|
||||
|
||||
if userInfo.Username == "" {
|
||||
var users models.User
|
||||
users.Username = username
|
||||
users.Password = newPass
|
||||
users.Created = now
|
||||
users.Last_logintime = now
|
||||
models.AddUser(users)
|
||||
|
||||
//登录成功设置session
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess.Set("uid", userInfo.Id)
|
||||
sess.Set("uname", userInfo.Username)
|
||||
this.Ctx.Redirect(302, "/")
|
||||
} else {
|
||||
this.Data["UsernameErr"] = "User already exists"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func checkPassword(password string) (b bool) {
|
||||
if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", password); !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func checkUsername(username string) (b bool) {
|
||||
if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", username); !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
```
|
||||
有了用户登陆和注册之后,其他模块的地方可以增加如下这样的用户是否登陆的判断:
|
||||
```Go
|
||||
|
||||
func (this *AddBlogController) Prepare() {
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess_uid := sess.Get("userid")
|
||||
sess_username := sess.Get("username")
|
||||
if sess_uid == nil {
|
||||
this.Ctx.Redirect(302, "/admin/login")
|
||||
return
|
||||
}
|
||||
this.Data["Username"] = sess_username
|
||||
}
|
||||
```
|
||||
## links
|
||||
* [目录](<preface.md>)
|
||||
* 上一节: [表单及验证支持](<14.3.md>)
|
||||
* 下一节: [多语言支持](<14.5.md>)
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 开发者 github token
|
||||
// 开发者 GitHub token
|
||||
const token = ""
|
||||
|
||||
// 定义一个访问者结构体
|
||||
|
||||
Reference in New Issue
Block a user