Golangでx-www-form-urlencodedのリクエストを投げる

やりたいことはタイトルそのままです。 parameter=hogeをhttpでPOSTする方法は以下です。

form := url.Values{}
form.Add("paramter", "hoge")

body := strings.NewReader(form.Encode())

req, err := http.NewRequest("POST", "https://example.com", body)
if err != nil {
    log.Fatal(err)
}

req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

References

Golangのnew()とmake()の違い

この記事は Go (その3) Advent Calendar 2017 の5日目の記事です。

本記事では、変数の宣言に用いられる組み込み関数new()make()の違いについてまとめます。

まとめ

さっそくですが、違いを表にまとめます。

new(T) make(T)
対象 任意の型 slice, map, channelのみ
初期化 初期化しない(ゼロ値になる) 初期化する
返り値 *T T

対象と初期化について

new()make()で、初期化しない/するの違いは、 slice, map, channelが、内部にデータ構造を持つことからきています。

以下にruntimeパッケージで、それぞれ型が定義されている箇所を引用します。 一番理解しやすいのが、sliceです。array(実データ), len, capを初期化してあげる必要があるため、make()が用意されています。

slice

type slice struct {
      array unsafe.Pointer
      len   int
      cap   int
  }

https://golang.org/src/runtime/slice.go#L11-15

map

type hmap struct {
      // Note: the format of the Hmap is encoded in ../../cmd/internal/gc/reflect.go and
      // ../reflect/type.go. Don't change this structure without also changing that code!
      count     int // # live cells == size of map.  Must be first (used by len() builtin)
      flags     uint8
      B         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
      noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
      hash0     uint32 // hash seed
  
      buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
      oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
      nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)
  
      extra *mapextra // optional fields
  }

https://golang.org/src/runtime/hashmap.go#L106-120

channel

type hchan struct {
      qcount   uint           // total data in the queue
      dataqsiz uint           // size of the circular queue
      buf      unsafe.Pointer // points to an array of dataqsiz elements
      elemsize uint16
      closed   uint32
      elemtype *_type // element type
      sendx    uint   // send index
      recvx    uint   // receive index
      recvq    waitq  // list of recv waiters
      sendq    waitq  // list of send waiters
  
      // lock protects all fields in hchan, as well as several
      // fields in sudogs blocked on this channel.
      //
      // Do not change another G's status while holding this lock
      // (in particular, do not ready a G), as this can deadlock
      // with stack shrinking.
      lock mutex
  }

https://golang.org/src/runtime/chan.go#L31-50

初期化について補足

Effective Goでは、new()では初期化が行われない、つまりゼロ値となることについて、helpfulであると述べられています。 これはゼロ値自体が意味を持つ場合には、初期化しているのと同じだけの意味があるということです。

Effective Goで述べられている例ですが、sync.Mutexでは以下のようにゼロ値自身がunlockなstateを表現します。

// A Mutex is a mutual exclusion lock.
// The zero value for a Mutex is an unlocked mutex.
//
// A Mutex must not be copied after first use.
type Mutex struct {
  state int32
    sema  uint32
}

自身で型を定義する際には、NewMyType()のようなコンストラクタを用意する場合が多いでしょう。このときにゼロ値自身に意味を持たせ、new()と組み合わせることでよい設計となると思います。

最後に

自分自身もあまりnew()make()の違いを認識できていなかったので、調べてまとめることができてよかったです。あといつか読もう読もうと思って着手できていなかったruntimeパッケージを読むきっかけにもなったので、思いの外収穫が多かったです。Goはソースコードにドキュメントレベルでコメントが書いてあるので、読むだけでなるほどと思うことが多く、とても勉強になります。

Githubの履歴を確認したらちょうどGoを書き始めてから1年が経過しました。書けば書くほど好きになっていくので、まだまだ書きますよー!

あぁ。水色gopherくんぬいぐるみ欲しいなぁ。。。

References

go tool compileの使い方

少し試したものの、忘れそうなのでメモ書きとして残します。

サンプルコード

package main

import "fmt"

func main() {
    fmt.Println("hello world")
}

オブジェクトファイルの生成

-Sが1つだと標準出力のみです。2つだと.oファイルが生成されます。

$ go tool compile -S -S main.go
"".main STEXT size=120 args=0x0 locals=0x48
    0x0000 00000 (main.go:5)    TEXT    "".main(SB), $72-0
  (中略)
    0x0000 65 48 8b 0c 25 00 00 00 00 48 3b 61 10 76 62 48  eH..%....H;a.vbH
    0x0010 83 ec 48 48 89 6c 24 40 48 8d 6c 24 40 48 c7 44  ..HH.l$@H.l$@H.D
    0x0020 24 30 00 00 00 00 48 c7 44 24 38 00 00 00 00 48  $0....H.D$8....H
    0x0030 8d 05 00 00 00 00 48 89 44 24 30 48 8d 05 00 00  ......H.D$0H....
    0x0040 00 00 48 89 44 24 38 48 8d 44 24 30 48 89 04 24  ..H.D$8H.D$0H..$
    0x0050 48 c7 44 24 08 01 00 00 00 48 c7 44 24 10 01 00  H.D$.....H.D$...
    0x0060 00 00 e8 00 00 00 00 48 8b 6c 24 40 48 83 c4 48  .......H.l$@H..H
    0x0070 c3 e8 00 00 00 00 eb 88                          ........
    rel 5+4 t=16 TLS+0
    rel 50+4 t=15 type.string+0
    rel 62+4 t=15 "".statictmp_0+0
    rel 99+4 t=8 fmt.Println+0
    rel 114+4 t=8 runtime.morestack_noctxt+0
  (中略)
type..importpath.fmt. SRODATA dupok size=6
    0x0000 00 00 03 66 6d 74                                ...fmt
gclocals·69c1753bd5f81501d95132d08af04464 SRODATA dupok size=8
    0x0000 02 00 00 00 00 00 00 00                          ........
gclocals·e226d4ae4a7cad8835311c6a4683c14f SRODATA dupok size=10
    0x0000 02 00 00 00 02 00 00 00 00 03                    ..........
gclocals·33cdeccccebe80329f1fdbee7f5874cb SRODATA dupok size=8
    0x0000 01 00 00 00 00 00 00 00                          ........

オブジェクトファイルから実行コードを生成

$ go tool link main.o

$ ls
a.out   main.go main.o

$ ./a.out
hello world

オブジェクトファイルに定義されているシンボルの表示

$ go tool nm main.o
         U
     44c T %22%22.init
     517 B %22%22.initdone·
     3b5 T %22%22.main
     507 R %22%22.statictmp_0
         U fmt.Println
         U fmt.init
     6de R gclocals·33cdeccccebe80329f1fdbee7f5874cb
     6cc R gclocals·69c1753bd5f81501d95132d08af04464
     6d4 R gclocals·e226d4ae4a7cad8835311c6a4683c14f
     4ea ? go.info.%22%22.init
     4cd ? go.info.%22%22.main
     507 ? go.range.%22%22.init
     4ea ? go.range.%22%22.main
     4c2 R go.string."hello world"
         U runtime.algarray
     517 R runtime.gcbits.01
     560 R runtime.gcbits.03
         U runtime.morestack_noctxt
         U runtime.throwinit
     646 R type.*[1]interface {}
     5c3 R type.*[]interface {}
     528 R type.*interface {}
     6c6 R type..importpath.fmt.
     633 R type..namedata.*[1]interface {}-
     5b1 R type..namedata.*[]interface {}-
     518 R type..namedata.*interface {}-
     67e R type.[1]interface {}
     5fb R type.[]interface {}
     561 R type.interface {}
         U type.string

実行コードの逆アセンブリ

$ go tool objdump a.out

(略)

References

Golangで主成分分析する

前回の記事では、 多次元正規分布から乱数を生成する方法を書きました。 今回は、このデータを使って主成分分析(PCA)を行っていきます。

PCAの詳細については、書籍や他の記事などで十分存在していると思うので、そちらを探してみてください。 分散を最大化する方向に軸を取るのか、射影誤差の最小化を行うのかなど複数の解釈が同じ数式に帰着するのも面白いですね。結局は、共分散行列の固有値問題に帰着するのですが。

まず、今回の対象データですが、  \Sigma = \begin{bmatrix}
3.0  \ \ 0.5 \\
0.5  \ \ 1.0
\end{bmatrix}
の共分散行列を用いて生成した擬似乱数(2次元×10000個)を使用します。 散布図を書くと以下のようになります。

f:id:cipepser:20171030224226p:plain

Golangstatパッケージでは、PCAを行ってくれるPrincipalComponentsメソッドがあるので、こちらを利用します。

コード

まず擬似乱数の生成です。のちほど使うPrincipalComponentsの引数がmat.Matrixなので、 mat.NewDenseで生成した*mat.Dense型のyに乱数を格納していきます。 ちなみに*mat.Dense型はmat.Matrix型のinterfaceを満たします。

y := mat.NewDense(N, d, nil)
for i := 0; i < N; i++ {
  rnd, _ := MultiNorm(mat.NewVecDense(d, []float64{0.0, 0.0}),
    mat.NewSymDense(d, []float64{3.0, 0.5, 0.5, 1.0}),
  )

  y.SetRow(i, mat.Col(nil, 0, rnd))
}

次にPCAの実行です。stat.PC型がPCA用の型となります。

var pc stat.PC
ok := pc.PrincipalComponents(y, nil)

PCAのあとはデータを射影していきます。次元削減を目的とする場合はkで残したい次元数を指定できます。

k := 2
var proj mat.Dense
proj.Mul(y, pc.VectorsTo(nil).Slice(0, d, 0, k))

以上をまとめたコード全体は次のようになります。

giste8f284fa0ed27fa4802ebe0867a795aa

PCA後の散布図は以下のようになりました。

f:id:cipepser:20171030224230p:plain

References

Golangで多次元正規分布を生成する

前回の記事も書きましたが、 Golangrandパッケージでは、 一次元正規分布の乱数生成が可能です。 今回は、多次元正規分布から乱数を生成する方法についてまとめます。

どうやって生成するか

まずPRMLから引用します。

平均 \boldsymbol{\mu} ,共分散 \boldsymbol{\Sigma} を持つ多変量ガウス分布に従うベクトル値の変数を生成するには,  \boldsymbol{\Sigma} = \boldsymbol{LL}^{T}の形を取るコレスキー分解(Cholesky decomposition)を用いればよい(Press et al., 1992). このとき, もし \boldsymbol{z}がベクトル値の確率変数であり, その各要素が独立で, 平均0, 分散1のガウス分布に従うとすれば,  \boldsymbol{y} = \boldsymbol{\mu} + \boldsymbol{Lz}は平均  \boldsymbol{\mu}, 共分散 \boldsymbol{\Sigma}ガウス分布に従う.

rand.NormFloat64()は、まさに平均0、分散1の一次元正規分布の乱数を生成してくれるので、 与えられた \boldsymbol{\Sigma}をコレスキー分解すれば多次元正規分布からの乱数生成ができます。

gonumのmatパッケージでは、Cholesky型のFactorizeメソッドでコレスキー分解ができるので、こちらを使って多次元正規分布からの乱数を生成します。

コード

実装は以下です。MultiNorm関数として実装しています。 散布図を描くコードも含んでいるので、少し長いです。。。

gist3609a47a7f572bd8e479ef120dae3f0e

実行結果

f:id:cipepser:20171029222325p:plain

References

インフラ/ネットワークエンジニアのためのネットワーク・デザインパターン 実務で使えるネットワーク構成の最適解27を読んだ

前作であるインフラ/ネットワークエンジニアのためのネットワーク技術&設計入門を読んでから、少し間が空いてしまいましたが、続編となるインフラ/ネットワークエンジニアのためのネットワーク・デザインパターン 実務で使えるネットワーク構成の最適解27 - みやた ひろしを読みました。

感想

まず、読んでいて一番の感想は、本自体の構成も設計されている ということです。 ネットワークを設計するにあたって、ネットワークを以下の4つに分類し、それぞれについて述べる形で整理された構成となっています。

  • Trustゾーン
  • Untrustゾーン
  • DMZゾーン1
  • WANゾーン

さらに各ゾーンを大中小の3規模にわけ、それぞれ2つずつデザインパターンを述べる構成となってています。 各ゾーンの説明が小さい順に記載されており、設計の考え方自体は一貫しているので、大規模ネットワークになっても理解しやすかったです。

さらに各節の中でも項目が一貫しており、以下のようになっています。

  • 物理構成、論理構成
  • 機器構成設計、物理構成設計、VLAN設計、IPアドレス設計、ルーティング設計
  • 障害設計
  • 運用設計

これに加えて各構成で独自に必要な設計(負荷分散設計やSTP設計など)は個別に述べられています。

各構成で考え方が一貫している一方で、同じ話が何度か登場します。 内容が重複してしまうのは一長一短ですが、個人的には、何回も同じトピックが出るので理解が染み込んでくる点、あとで読み返す際にその節だけ読めばいい点で、丁度よいと感じました。

個人的にヒットしたところ

LAGを使ってSTP構成を組む場合に、物理ポート障害が発生するとSTPの再計算となる話が載っています。
STPの仕組みとしてコストがあり、このコストに応じてL2ループが発生しないようになっていることはわかっていたのですが、障害時に余計な再計算をさせないように値を設定する、といった意識できていなかった話が載っており、学びが多かったです。

こういう人におすすめ

ネットワーク設計に多少の経験があるので、デザインパターンを体系的に整理したいという方におすすめです。

一方で、OSPFやBGP、IPsecなど各種の設定で注意すべき設定などは書かれているものの基本的な仕組みなどの記載は少ないので、ネットワーク技術の知識に不安がある場合は、本書の前に前作のインフラ/ネットワークエンジニアのためのネットワーク技術&設計入門を読むのがいいと思います。

どちらも構成がわかりやすいのと簡潔にまとめられているので数日あれば十分読めると思います。 本書に関しては、ページを捲る手が止まらず実質2日くらいで読み切ってしまいました。

インフラ/ネットワークエンジニアのためのネットワーク・デザインパターン 実務で使えるネットワーク構成の最適解27 - みやた ひろし

いつもはkindle派な自分ですが、データフローを正常時と障害時で見比べたりしながら読むと理解が深まるので紙の書籍がおすすめです。


  1. 余談ですが、よくDMZゾーンって言葉を耳にするときに、頭痛が痛いになってるなぁと思っていたのですが、本書ではわかりやすさを優先し、DMZゾーンと記載すると書いてあり、すっきりしました。