- 投稿日:2020-09-25T17:08:22+09:00
Golangの言語仕様を全部読んでまとめる
https://golang.org/ref/spec の和訳摘要です. 完全性はないです.
Version of Jan 14, 2020
ソースコードの表現
ソースコードはUTF-8である.
文字
改行 = LF unicode文字 = Unicodeの"Letter" unicode数字 = Unicodeの"Number, decimal digit"文字と数字
文字 = unicode文字と"_"字句要素
コメント
プログラム // 行コメント /* 複数行 コメント */トークン
トークンは5種類
- 識別子
- キーワード
- 演算子
- 約物(句読点)
- リテラル
空白(スペース, タブ, CR, LF)は無視される
セミコロン
セミコロンは文の終りを示す
一行に複数文を書きたいときのみ, 明示的にセミコロンを必要とする識別子
識別子は文字始まり, 文字+unicode数字が続く
キーワード
break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var演算子と約物
+ & += &= && == != ( ) - | -= |= || < <= [ ] * ^ *= ^= <- > >= { } / << /= <<= ++ = := , ; % >> %= >>= -- ! ... . : &^ &^=整数リテラル
_を区切り文字として使える.123_456
0bで2進,0oで8進,0xで16進を示す小数リテラル
.が1つ含まれる数字
1e+01: 指数表記0x_1: 16進0x_1P-16: 16進+指数表記虚数リテラル
整数, 小数の最後に
iをつけると虚数Runeリテラル
'Rune'はUnicodeのコードポイント.
'ä'はUTF-8では0xc3 0xa4だが, RuneではU+00E4 -'\377''\x07''\xff''\u12e4'文字列リテラル
"バックスラッシュエスケープされる文字列\n"`エスケープされない文字列`定数
- リテラルは定数
unsafe.Sizeof(式)は定数cap(式)len(式)は定数のことがあるreal(複素定数)imag(複素定数)は数値定数truefalse真偽値定数iota整数定数型名を省略したときのデフォルトは
bool,rune,int,float64,complex128,string変数
変数は静的型付けされる
interface{}型は任意の値を代入できる型
型は配列,構造体,ポインタ,関数,インターフェース,スライス,マップ,チャンネル
メソッド集合
型はメソッドを持つ
- インターフェースは,そのインターフェスをメソッドとして持つ
- 型
Tは,Tをレシーバにするメソッドを持つ- 型
*Tは,*TかTをレシーバにするメソッドを持つ- 構造体が埋め込みフィールドを含む場合,そのメソッドも持つ
真偽値型
型
boolは
trueかfalseゼロ値は
false
==による比較可能数値型
uint8 非負8-bit (0 to 255) uint16 非負16-bit (0 to 65535) uint32 非負32-bit (0 to 4294967295) uint64 非負64-bit (0 to 18446744073709551615) int8 8-bit (-128 to 127) int16 16-bit (-32768 to 32767) int32 32-bit (-2147483648 to 2147483647) int64 64-bit (-9223372036854775808 to 9223372036854775807) float32 IEEE-754 32-bit 浮動小数点 float64 IEEE-754 64-bit 浮動小数点 complex64 float32 複素数 complex128 float64 複素数 byte uint8のエイリアス rune int32のエイリアス uint 32-bit or 64-bit int uintと同じ大きさ uintptr ポインタを格納できる大きさゼロ値は
0
==による比較<などによる順序比較可能文字列型
文字列の長さ
len(文字列)はバイト列の長さ
文字列は変更できない
文字列[添字]でバイト列を参照する
&文字列[添字]は不可
文字列[添字] = 文字は不可
文字列[low : high]は部分文字列を返すゼロ値は
""
nilにならない
==による比較が可能<などによる順序比較可能
byte列による辞書順で比較される配列型
配列
[要素数]型Tは,型Tを要素数個格納できる型
要素数は静的に決定
[1][2][3]intは[1]([2]([3]int))
make([要素数]型)ゼロ初期化された配列
len(配列), cap(配列)は要素数
[要素数]型{要素0, 要素1, …}配列の合成リテラル
[...]型{要素0, 要素1, …}要素数は...とすると要素数となる
指定された要素数に対して要素が足りなければ要素はゼロ値となる
配列[添字]により要素が得られる
配列[low : high]によりスライスが得られる
得られたスライスは元の配列と要素を共有している
スライスを書き換えると配列も書き換わるゼロ値はそれぞれの要素がゼロ値となる
==による比較が可能 個別の要素を比較するスライス型
スライス
[]型Tは,型Tを格納する列の型
要素数が動的に決定
len(スライス)は要素数
cap(スライス)で予備を含めたスライスの大きさ=キャパシティーを得られる
make(スライス型, 長さ, キャパシティー)キャパシティーを与えてゼロ初期化されたスライス
new([キャパシティー]スライス型)[0:長さ]は上と等価
[]型{要素0, 要素1, …}スライスの合成リテラル. キャパシティーは指定できない.
スライス[low : high]によりスライスが得られる
得られたスライスはもとのスライスと要素を共有している
スライスを書き換えるともとのスライスも書き換わるゼロ値はnil
スライス型のnilは要素数0のスライスのように振る舞う
==による比較ができない構造体
struct {複数のフィールド}
は構造体型は名前付きフィールド (
変数0, 変数1, … 型x int,x, y int)
型だけ書くと埋め込みフィールドとなり, フィールド名は型と同じ
_ 型はパディング
型{キー: 値…}合成リテラル
キーを省略した場合,structの順番となる
値が足りないときはゼロ値となる構造体Sに型Tを埋め込むと,型Tのフィールドとメソッドは構造体Sでも参照できる
type T struct { X int } type S struct { T // Tを埋め込む } func main() { s := S{T{1}} // s.X は S.T.X と同じ fmt.Printf("%#+v: %v === %v", s, s.X, s.T.X) // main.S{T:main.T{X:1}}: 1 === 1 }フィールドは文字列のタグを持つ
タグが未指定の場合,空文字列のタグを持つリフレクションで参照できる
struct { microsec uint64 `protobuf:"1"` serverIP6 uint64 `protobuf:"2"` }ゼロ値はそれぞれのフィールドをゼロ値で初期化する
==による比較可能 個別のフィールドを比較するポインタ型
*TはTのポインタ型
&値によりポインタが得られる
*ポインタにより値を参照するゼロ値はnil
nilを参照すると実行時パニック
==による比較可能関数型
func(引数) 返り値は関数型ゼロ値はnil
nilを呼び出すと実行時パニック
==による比較不可能インターフェース型
interface{複数のシグネチャ}はインターフェース型
シグネチャはメソッド名(引数)返り値インターフェースIのすべてのシグネチャが型Tのメソッドの時, 型TはインターフェースIを実装していると言う
interface{}は要求するメソッドが無いので, 全ての型が実装しているインターフェースは他のインターフェースを埋め込める
埋め込まれたインターフェースのシグネチャを取り込む
ReadWriterはReadとWriteとCloseを持つtype Reader interface { Read(p []byte) (n int, err error) Close() error } type Writer interface { Write(p []byte) (n int, err error) Close() error type ReadWriter interface { Reader Writer }ゼロ値はnil
==による比較可能 元の型として比較するマップ型
map[キー型]値型はマップ型
make(map[キー型]値型, キャパシティー)でキャパシティー付きのマップが作られる
map[キー型]値型{キー0: 値0, キー1: 値1, …}
len(マップ)は要素数
マップ[キー]は値とその存在を返す
+ キーが存在するとき,その値とtrue
+ 存在しないとき,ゼロ値とfalse
v, ok = m[0]ゼロ値はnil
nilはキーが存在しないマップとして振る舞う
==による比較不可能チャンネル型
スレッドセーフなキュー
chan 型Tは 型Tを送受信するチャンネル型
chan <- 型Tは 型Tを送信するチャンネル型
<- chan 型Tは 型Tを受信するチャンネル型
make(chan 型T, キャパシティー)はチャンネルを作る唯一の方法
キャパシティーはチャンネルのキューの大きさを示す
len(チャンネル)はキュー内の要素数
cap(チャンネル)はキューの大きさバッファーに要素があるとき, 受信は成功する
バッファーに要素がないとき, 受信は送信されるまでブロックする
バッファーが足りているとき, 送信は成功する
バッファーの要素がいっぱいのとき, 送信は受信されるまでブロックするゼロ値はnil
チャンネル型のnilは何も送受信されない
close(チャンネル)によりチャンネルをクローズできる
==による比較可能 同じmake()によって生み出されたか判定する型と値の性質
型の同一性
- 異なるパッケージの非公開名前は区別される
- シグネチャの引数や返り値の名前は無視される
- キャパシティーは無視される
- エイリアスは同一の型となる
代入可能
値xが型Tに代入可能である とは 次のいずれかを満たすことである:
- xの型VがTと同一である
- xの型VとTが同一の基底型を持ち, VとTの少なくともどちらかがDefined型ではない
- Tがインターフェース型であり, xがTを実装している
- x が送受信チャンネルでTがチャンネル型であり, VとTが同一の要素型をもち, VとTの少なくともどちらかがDefined型ではない
- xがnilであり,Tがポインタ,関数,スライス,マップ,チャンネル,インターフェースである
- xが定数であり,Tの値として表現可能
Defined型は,
type 型名 型で定義された型名の型のこと
type T1 T,type T2 Tのとき,
Tの値はT1, T2に代入できるが, T1の値をT2に代入することはできない表現可能
定数xが型Tの値として表現可能であるとは,
要するに,定数がその型として扱えるということブロック
ブロックは文のリスト
{文; 文; …}暗黙的にブロックが生成される
- すべてのGoのソースコード全体=宇宙ブロック
- それぞれのパッケージのソースコード全体
- ファイル全体
if,for,switchswitch,selectのブランチブロックによってスコープが規定される
宣言とスコープ
宣言は, 定数, 型, 変数の3種類
トップレベル宣言は, 宣言に加えて関数宣言とメソッド宣言の5種類boolなどの事前宣言識別子は宇宙ブロックのスコープに属する
トップレベルの宣言はパッケージのスコープに属する
インポートしたパッケージはファイルのスコープに属する他の名前は最も内側のブロックのスコープに属する
ラベルのスコープ
定義されたラベルは用いる必要がある
ラベルは関数のブロックのスコープに属する. ラベル以外の識別子とは衝突しないブランク識別子
_はブランク識別子として特別な意味を持つ事前宣言識別子
Types: bool byte complex64 complex128 error float32 float64 int int8 int16 int32 int64 rune string uint uint8 uint16 uint32 uint64 uintptr Constants: true false iota Zero value: nil Functions: append cap close complex copy delete imag len make new panic print println real recoverエクスポートされる識別子
識別子の初めの文字がUnicodeの大文字クラス("Lu")であり,
パッケージブロックで宣言された名前である時その識別子はエクスポートされる
識別子の唯一性
同じスコープに同じ識別子は持てない
定数定義
const 定数名 = 定義により定数を定義できる
const 定数名 型 = 定義により型を指定できる
iotaはconst()の中で宣言ごとに0から1ずつ増える特別な値である.const ( Sunday = iota Monday Tuesday Wednesday Thursday Friday Partyday numberOfDays // this constant is not exported )Iota
1つの宣言の中では
iotaは同じ値となるconst ( bit0, mask0 = 1 << iota, 1<<iota - 1 // bit0 == 1, mask0 == 0 (iota == 0) bit1, mask1 // bit1 == 2, mask1 == 1 (iota == 1) _, _ // (iota == 2, unused) bit3, mask3 // bit3 == 8, mask3 == 7 (iota == 3) )型宣言
エイリアス型宣言
type エイリアス名 = 型エイリアスは元の型と同一の型である
型宣言
type 型名N 型T基底型をTとして新しい型を型名Nとして作る.
型名NはDefined型となる.すなわち,
type TimeZone intはintと異なる振る舞いをする
また,Defined型はメソッドを持つことができる.type TimeZone int const ( EST TimeZone = -(5 + iota) CST MST PST ) func (tz TimeZone) String() string { return fmt.Sprintf("GMT%+dh", tz) }変数宣言
var 変数名 型 = 値で変数宣言
型と値は省略可能参照されない変数はエラーとなる
_により値を捨てることができるvar _, found = entries[name]短縮変数宣言
変数名 := 値はvar 変数名 = 値の省略としてほとんど振る舞う
ただしvarと異なり, 一部の変数への代入が可能
少なくとも1つは新しい変数を定義する必要がある関数定義
func 識別子 シグネチャ ブロックにより関数が定義される返り値を返すならばブロックの最後のreturnを省略できない
ただし, if-elseと条件のないforのあるときは省略できることがある(see 終端文)関数のブロックを省略した場合,アセンブリルーチンなどでGo以外の外部から定義が与えられることを想定される
メソッド宣言
func (レシーバ変数 レシーバ型) 識別子 シグネチャによりメソッドが定義されるレシーバ型(*T, T)はTがDefined型である必要がある
メソッドの型は
func (レシーバ型, メソッドの型...) メソッドの返り値式
被演算子
被演算子はすべてのリテラルと識別子と修飾識別子と
(式)である修飾識別子
識別子にパッケージ名をつけることで別のパッケージの識別子を参照できる
パッケージ名.識別子合成リテラル
チャンネル以外の型には
{}によるリテラルがある合成リテラルの例はそれぞれの型の節に移動した
複数の型が合成された型のとき, 内側の型名を省略できる
次の2つは同じ:
golang
map[string]Point{"orig": {0, 0}}
map[string]Point{"orig": Point{0, 0}}
関数リテラル
func シグネチャ 関数本体は関数であり,クロージャを作る
外側の変数を参照するための環境を持つ
()で呼び出すことができる基本式
セレクタ
x.fはxのフィールドかメソッドを返す
xが埋め込みフィールドを持つ場合, 幅優先で再帰的に探索する
- xの型(T, *T)でTがポインタでもインターフェースでもない
- 探索時に最も浅いところのfを返す
- 同じ深さに同じfがあるならば不正
- xの型がインターフェースI
- xの動的な実際の型のfを返す.
- fがインターフェースIのメソッドでないならば不正
- xがポインタ型 (例外)
- xの実体である
(*x).fが不正でないならx.fはP(*x).fの短縮となる- xがポインタ型でnil
- 実行時パニック
- xがインターフェースでnil
- x.fを評価もしくは呼び出した時に実行時パニック
メソッド式
型.メソッドや(*型).メソッドにより関数が得られるメソッド値
値.メソッドにより関数が得られる添字式
値a[添字i]
- 値aがポインタのとき,
(*値a)[添字i]と等価- マップ,配列,スライス,文字列のとき それぞれの型のところで示した
スライス式
値a[low:higth]は部分文字列やスライスを返す
値aがポインタのとき,(*値a)[low:high]と等価
lowを省略すると0,highを省略するとlen(値a)となる型アサーション
値x.(型T)により実行時に型変換ができる
- 型Tがインターフェースのとき,xはTを実装している必要がある
- 型Tがインターフェースでないとき,Tはxの型を実装している必要がある
そうでなければ実行時パニックを起こす
ただし
v, ok := x.(T)の形で呼び出した場合は, 実行時パニックを起こさない
かわりにvがゼロ値, okがfalseとなる呼び出し
関数は複数の値を返すことができる
返した複数の値は次のどれかを行う必要がある
- 分割代入する:
x, y := f()- returnする:
return f()- 合成する:
g(f())多引数関数 ...引数
who ...string)
関数の最後の引数を
...型にできる.
渡した引数がスライスとして渡されるfunc Greeting(prefix string, who ...string) Greeting("nobody") Greeting("hello:", "Joe", "Anna", "Eileen")
スライス...で...引数に渡すことができるs := []string{"James", "Jasmine"} Greeting("goodbye:", s...)演算子
数値演算
- 数値
+-*/%- ビット
|^<<>>&&^- 単項演算子
+-^
&^はbit clear(AND NOT)
存在理由→stack overflowオーバーフローしてもパニックではなくwrap-aroundする
x < x+1が常にtrueとは限らない小数の演算は積和演算(FMA)などの丸めで結果が異なることがある
文字列は
+で結合できる
ただし, 多くの文字列を結合するならばstrings.Builderを用いるべき比較演算
- 比較
==!=- 順序
<<=>>=比較する2値は互いに代入可能である必要がある
スライス,マップ,関数は比較できない
- 真偽値,整数,小数 比較可能かつ順序付け可能
- 複素数 real→imagの辞書順比較で順序付けされる
- 文字列 bit列での辞書順比較で順序付けされる
- ポインタ 比較可能. 大きさゼロの要素のポインタ値は異なることがある
- チャンネル makeで作られた同じチャンネルであるか比較する
- インターフェース 同じ型で同じ値か比較する
- 構造体 すべてのフィールドの値が同じか比較する
- 配列 すべての要素が同じか比較する
論理演算子
- 短絡演算
||&&- 単項演算子
!アドレス演算
- 参照
&x- 参照先の値を得る
*x受信演算
- 受信
<-ch受信する.
バッファーが無いときは送信があるまでブロックする
x, ok = <-chのとき, 受信に成功したかクローズしたかを返す
受信に成功すればok=trueとなるコンバージョン
型T(値x)
コンパイル時に検査される型変換xが定数の時 値xが型Tとして表現可能でなければ不正
xが定数でない時 次のどれかを満たす
- xがTに代入可能
- 構造体のタグを無視して, xの型がTの基底型と同一
- 構造体のタグを無視して, xの型とTのポインター型がDefined型ではなく,それらの基底型が同一
- xが整数か小数で,Tが整数型か小数型
- xが複素数で,Tが複素数型
- xが整数か[]byteか[]runeで,Tが文字列
- xが文字列で, Tが[]byteか[]rune
すなわち,次のキャストが可能
- 構造体のタグを無視するキャスト
- 数値のキャスト
- 文字列とスライスのキャスト
定数式
定数の演算は定数式になる
評価順
関数の引数の評価は左から右に行われる
文
終端文
return以外でも終了文がある
-returngotopanic
-if-elseforswitchselect(条件あり)空文
空文は何もしない
ラベル付き文
ラベル: 文式文
式は文である
送信文
チャンネルに値を送信する
golang
ch <- 3
インクリメント・デクリメント文
x++ x--代入
x = 1 x += 1 a, b = b, aIf文
if x := f(); x < y { return x } else if x > z { return z } else { return y }Switch文
式Switch文
switch tag { default: s3() case 0, 1, 2, 3: s1() case 4, 5, 6, 7: s2() } switch { // switch trueと等価 case x < y: f1() case x < z: f2() case x == 4: f3() }型Switch文
switch 変数 := 変数.(type)
順番に型アサーションを試し,成功したブランチを実行するswitch i := x.(type) { case nil: print("x is nil") case int: print(i+1) }For文
1条件For
for a < b { a *= 2 } for { // for trueと等価 if a < b { break } }3条件For
for i := 0; i < 10; i++ { f(i) }range For
for i, v := range a { print(i, v) }
- aが配列,スライスの時 iは添字, vは要素
- aが文字列の時 iはUTF-8での添字,vはRune
- aがマップの時 iはキー,vは要素 順序不定 ループ中の要素追加は不定
- aがチャンネルの時 1要素 チャンネルがCloseするまで受信ループ
Go文
最後の関数適用がゴルーチンとして並列に実行される
go Server() go func(ch chan<- bool) { for { sleep(10); ch <- true }} (c)Select文
実行できる受信/送信を1つ当確率にランダムに実行する.
すべての受信/送信がブロックした場合,defaultがあればdefaultを実行するselect { case <- c1: case x := <- c2: default: // ブロックしない } // 0,1をランダムに送信し続ける for { select { case c <- 0: case c <- 1: } }Return文
名前付き返り値を用いることができる
func complexF3() (re float64, im float64) { re = 7.0 im = 4.0 return }Break文
一番内側の
forswitchselectを抜ける
もしくは指定したラベルまで抜けるContinue文
forに戻る
もしくは指定したラベルのforに戻るGoto文
指定したラベルに処理を移す
Fallthrough文
switch内で次のブランチも実行するDefer文
最後の関数呼び出しを,現在の関数から抜ける
returnやpanicのタイミングで実行する
deferの実行は文の順番と逆に行われる組み込み関数
Close
チャンネルを閉じる
次の時実行時パニック
- 閉じたチャンネルを閉じる
- 閉じたチャンネルに送信する
- nilを閉じる長さとキャパシティ len/cap
それぞれの型の説明で説明済み
確保 new
new(T)は型のゼロ値を返す
ほとんどの場合T{}と等価スライス,マップ,チャンネルの生成
make(型, 要素数 キャパシティ)を指定できるスライスへの追加とコピー append/copy
appendでスライスの末尾に複数要素を追加できる
appendの第1引数は使い回され変更を受けることがあるb := append(a, 1, 2) b := append(a, c...)copyはsrcの要素をdstに代入する
copy(dst, src []T) intマップからキーを削除 delete
キーが存在しない場合は何もしない
golang
delete(m, k)
複素数演算 complex/real/imag
complex(realPart, imaginaryPart floatT) complexT real(complexT) floatT imag(complexT) floatTパニックとリカバリ panic/recover
panicは直ちにすべての関数を抜けようとする
func panic(interface{}) func recover() interface{}deferでrecover()を呼ぶとパニックの送出が止まる
パニックしたときの引数が得られるfunc protect(g func()) { defer func() { log.Println("done") // Println executes normally even if there is a panic if x := recover(); x != nil { log.Printf("run time panic: %v", x) } }() log.Println("start") g() }ブートストラッピング print/println
デバッグ出力, 標準エラー出力に出ることが多い
print("Hello") println("World")パッケージ
Goのビルド単位
ソースファイル
Goのソースファイルは
package パッケージ名 複数のインポート宣言から始まる
インポート宣言
パッケージをインポートするときは,
パッケージ名に別名をつけることや
現在のパッケージと名前空間を共有することができるパッケージ名は実装依存
import "lib/math" → math.Sin import m "lib/math" → m.Sin import . "lib/math" → Sinプログラムの初期化と実行
ゼロ値
確保された変数は初期値がない場合,ゼロ値になる.
false0""nilのいずれかパッケージの初期化
パッケージグローバルの変数は依存の解決されたものから上から順番に初期化される.
パッケージの
init()が呼ばれる.
init()は何回でも定義できる.
init()はプログラムの他の場所から参照できない.インポートされたパッケージが先に初期化される.
複数回インポートされるパッケージは1回だけ初期化される.
パッケージ間の循環参照は起こせない.プログラムの実行
mainパッケージの
main()が実行される,エラー error
error型はインターフェースである.type error interface { Error() string }nilはエラーのないことを示す.
実行時パニック panic
panic関数はerror型を受け取り,実行時パニックを起こすシステム関係
unsafeパッケージ
package unsafe type ArbitraryType int // shorthand for an arbitrary Go type; it is not a real type type Pointer *ArbitraryType func Alignof(variable ArbitraryType) uintptr func Offsetof(selector ArbitraryType) uintptr func Sizeof(variable ArbitraryType) uintptrOffsetofは要素のオフセットを返す
uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f) == uintptr(unsafe.Pointer(&s.f))Alignof(x)はアライメントを返す
uintptr(unsafe.Pointer(&x)) % unsafe.Alignof(x) == 0大きさとアライメントの保証
数値型は固定サイズである.
type size in bytes byte, uint8, int8 1 uint16, int16 2 uint32, int32, float32 4 uint64, int64, float64, complex64 8 complex128 16structのアライメントは要の最大のアライメントと等しい.
arrayのアライメントは要素のアライメントと等しいゼロ要素のstructやarrayは0より大きい大きさを持つことがある.
ゼロ要素の異なる変数が同じメモリに配置されることがある.
- 投稿日:2020-09-25T13:42:39+09:00
Angular+Golang(gin)でSPAを作る
目標
Angularで作成したSPA(シングルページアプリケーション)に対して、GolangのWebフレームワークであるginを使ってHTTPアクセスできるようにします。
なぜginを使うか。
- ログがわかりやすいから。
- 記事が見当たらなかったから
前提
「Angularのチュートリアル」を通していること。
チュートリアル程度のAngular CLIが使えること。
既に、ご自身で作成されたAngularプロジェクトがあることを想定しています。
ご自身で作成されたAngularプロジェクトがない場合:
後述する「プロジェクトをコピー」の手順を無視して進めてください。
デフォルトで生成されるSPAを表示することができます。手順
プロジェクト作成
始めのプロジェクト構成は以下のようにしています。
go-angular └── main.go
go-angularディレクトリに移動して、Angularプロジェクトを作成します。UHNaKZ:go-angular $ ng new view ? Would you like to add Angular routing? Yes // Yesを入力 ? Which stylesheet format would you like to use? CSS // CSSを選択
プロジェクトの構成が以下のようになります。
go-angular ├── main.go └── view ├── README.md ├── angular.json ├── e2e ├── karma.conf.js ├── node_modules ├── package-lock.json ├── package.json ├── src ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.spec.json └── tslint.jsonプロジェクトをコピー
注意! 上記の「プロジェクト作成」で生成したプロジェクト以外に、ご自身で作成されたAngularプロジェクトがない場合は無視してください
ここで、生成された
viewディレクトリ配下のsrcディレクトリを、既に作成済みのプロジェクトのsrcディレクトリに置き換えます。Angularプロジェクトをビルド
viewディレクトリへ移動してビルドします。UHNaKZ:go-angular $ cd ./view UHNaKZ:go-angular/view $ ng buildすると、
go-angular ├── main.go └── view ├── README.md ├── angular.json ├── dist // NEW!! ├── e2e ├── karma.conf.js ├── node_modules ├── package-lock.json ├── package.json ├── src ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.spec.json └── tslint.jsonのようになったかと思います。
Goビルド
go-angular/main.goを以下のように修正します。go-angular/main.gopackage main import( "github.com/gin-gonic/gin" ) func main(){ router := gin.Default() router.Static("/", "./view/dist/view") router.Run() }
修正できたらビルドします。UHNaKZ:go-angular $ go build最後に、生成されたバイナリファイルを実行します。
UHNaKZ:go-angular $ ./go-angular
localhost:8080にアクセスすれば、Angularで作ったSPAが動いているのが分かると思います。ginを使わずに標準パッケージだけで書いたコード
main.gopackage main import ( "net/http" ) func main(){ ang := http.FileServer(http.Dir("./view/dist/view")) http.Handle("/",ang) http.ListenAndServe(":8080",nil) }ログが出ないです。
ログが出るようにすると少し長くなる。main.goimport ( "net/http" "fmt" "time" ) func main(){ http.HandleFunc("/",angSF) fmt.Println(" Your Angular application is runnning.") http.ListenAndServe(":8080",nil) } func angSF(w http.ResponseWriter, r *http.Request){ t := time.Now().Format("Mon Jan 2 15:04:05 -0700 MST 2006") fmt.Println(fmt.Sprintf("%s Status:%v Method:%s URL:%s",t,http.StatusOK,r.Method,r.URL)) http.ServeFile(w,r,"./view/dist/view") }ログこんな感じで作れば良いんかな。(ステータスは面倒なので200しか返さないです。)
まとめ
ginが楽。
- 投稿日:2020-09-25T13:42:39+09:00
Angular+ginでSPAを作る
目標
Angularで作ったSPA(シングルページアプリケーション)をginを使ってサーブします。
なぜginを使うか。
- ログがわかりやすいから。
- 記事が見当たらなかったから
前提
Angularのチュートリアルを通していること。
チュートリアル程度のAngular CLIが使えること。
既に、ご自身で作成されたAngularのプロジェクトがあるとします。
ご自身で作成されたAngularプロジェクトがない場合:
Angularプロジェクトをコピーを無視して進めてください。
デフォルトで生成されるSPAを表示することができます。手順
プロジェクト作成
始めのプロジェクト構成は以下のようにしています。
go-angular └── main.go
go-angularディレクトリに移動して、Angularプロジェクトを作成します。UHNaKZ:go-angular $ ng new view ? Would you like to add Angular routing? Yes // Yesを入力 ? Which stylesheet format would you like to use? CSS // CSSを選択
プロジェクトの構成が以下のようになります。
go-angular ├── main.go └── view ├── README.md ├── angular.json ├── e2e ├── karma.conf.js ├── node_modules ├── package-lock.json ├── package.json ├── src ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.spec.json └── tslint.jsonAngularプロジェクトをコピー
注意! ご自身で作成されたAngularプロジェクトがない場合は無視してください
ここで、生成された
viewディレクトリ配下のsrcディレクトリを、既に作成済みのプロジェクトのsrcディレクトリに置き換えます。Angularプロジェクトをビルド
viewディレクトリへ移動してビルドします。UHNaKZ:go-angular $ cd ./view UHNaKZ:go-angular/view $ ng buildすると、
go-angular ├── main.go └── view ├── README.md ├── angular.json ├── dist // NEW!! ├── e2e ├── karma.conf.js ├── node_modules ├── package-lock.json ├── package.json ├── src ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.spec.json └── tslint.jsonのようになったかと思います。
Goビルド
go-angular/main.goを以下のように修正します。go-angular/main.gopackage main import( "github.com/gin-gonic/gin" ) func main(){ router := gin.Default() router.Static("/", "./view/dist/view") router.Run() }
修正できたらビルドします。UHNaKZ:go-angular $ go build最後に、生成されたバイナリファイルを実行します。
UHNaKZ:go-angular $ ./go-angular
localhost:8080にアクセスすれば、Angularで作ったSPAが動いているのが分かると思います。ginを使わずに標準パッケージだけで書いたコード
main.gopackage main import ( "net/http" ) func main(){ ang := http.FileServer(http.Dir("./view/dist/view")) http.Handle("/",ang) http.ListenAndServe(":8080",nil) }ログが出ないです。
ログが出るようにすると少し長くなる。main.goimport ( "net/http" "fmt" "time" ) func main(){ http.HandleFunc("/",angSF) fmt.Println(" Your Angular application is runnning.") http.ListenAndServe(":8080",nil) } func angSF(w http.ResponseWriter, r *http.Request){ t := time.Now().Format("Mon Jan 2 15:04:05 -0700 MST 2006") fmt.Println(fmt.Sprintf("%s Status:%v Method:%s URL:%s",t,http.StatusOK,r.Method,r.URL)) http.ServeFile(w,r,"./view/dist/view") }ログこんな感じで作れば良いんかな。(ステータスは面倒なので200しか返さないです。)
まとめ
ginが楽。
- 投稿日:2020-09-25T01:07:24+09:00
go/mysqlで値が上手く取れない
go/gorm/mysql
で値が上手く取れない現象が起きたので備忘録がてら例えばこのようなテーブルを作成し、CREATE TABLE dataids ( id INT, titleid INT, titleid2 INT );以下のように、insertしときます。
INSERT INTO collectq_db.dataids (id, titleid, titleid2) VALUES (1,1,1),(2,1,2),(3,1,3);そしてgormで取得しようと以下のようにしました
type Dataid struct { id int titleid int titleid2 int } func GetAllDataids(db *gorm.DB) []Dataid { var dataids []Dataid db.Find(&dataids) fmt.Println("確認!!", dataids) return dataidsとすると、以下のように、
fmt.Println上では
[{0 } {0 } {0 }]
googlechrome上では、
`[{},{},{}]
と表示されます。解決策
構造体の中身の変数名さえ頭文字大文字にしなければ、反応gormのFindで
反応してくれない。
(errではなくよくわからないのが帰ってくる(まあ対応する変数がないので、代入されないだけだと思うけど))type Dataid struct { Id int Titleid int Titleid2 int }
