20210906のGoに関する記事は5件です。

[Go] Singletonパターン -Goで学ぶデザインパターン-

Singletonパターンとは 一言で言うと インスタンスが1個しか存在しないことを保証するパターンのこと どういうときに使うのか 次の条件を満たす - 状態を持たないこと - ポリモーフィズムが絡む (抽象クラスまたはインタフェースを実装している) こと 「このクラスのインスタンスはたった一つしか作らないし、作りたくない」というときに使う。 Goで実装してみる config.go package config import "sync" type Config interface { PutString(key string, value string) GetString(key string) (string, bool) } type config struct { stringValue map[string]string } func newConfig() *config { ret := new(config) ret.stringValue = make(map[string]string) return ret } var once sync.Once var instance *config func GetConfig() Config { // 新しいconfigインスタンスを生成する // instance = newConfig() // インスタンス生成を関数化してonce.Doに渡すことで、 // 1回のみ実行される処理になる once.Do( func() { instance = newConfig() }) // 簡単に次のようにしてもよい // if instance == nil { // instance = newConfig() // } return instance } func (c *config) PutString(key string, value string) { c.stringValue[key] = value } func (c *config) GetString(key string) (string, bool) { val, ok := c.stringValue[key] return val, ok } main.go package main import ( "Singleton/config" "fmt" ) func main() { config1 := config.GetConfig() config1.PutString("key1", "test1") fmt.Println(config1.GetString("key1")) config2 := config.GetConfig() // config2も中身は同じインスタンスであり、既にkey1を持っている fmt.Println(config2.GetString("key1")) } ビルドして実行 結果は以下の通り /go/src/app/Singleton # go build /go/src/app/Singleton # ./Singleton test1 true test1 true 解説 Singletonパターンでない場合、GetConfigで毎回新しくインスタンス(*config)が生成され、新しいインスタンスへのポインタが返される。 Singletonパターンである場合、一度インスタンスを生成していれば、その後は新しくインスタンスを生成せず、最初のインスタンスへのポインタが返される。 感想 条件の意味があまりわかっていないので、使いどころをもう少し調べてみる必要がありそう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Go】xormの使い方 その②

はじめに 前回に続いて、xorm使い方その②です。 前回の続きですので、xormの導入などは終わっている程で話を進めます。 今回はいろんなメソッドを解説しようと思います。 今回解説するのは、以下の通りです。 目次 Table Select Sum, SumInt Where, And, Or OrderBy, Asc, Desc SQL, Query 環境 go 1.15 github.com/go-sql-driver/mysql v1.6.0 xorm.io/xorm v1.2.3 DBのデータ 今回はこちらのデータを使用します。 enginの用意 package main import ( "fmt" "log" "time" _ "github.com/go-sql-driver/mysql" "xorm.io/xorm" ) type User struct { Id int64 `xorm:"id"` Name string Age int Password string `xorm:"password"` Created time.Time `xorm:"created"` Updated time.Time `xorm:"updated"` } func main() { engine, err := xorm.NewEngine("mysql", "root:root@tcp([127.0.0.1]:3306)/sample_db?charset=utf8mb4&parseTime=true") if err != nil { log.Fatal(err) } err = engine.Sync2(new(User)) if err != nil { log.Fatal(err) } // メソッドを実行します // Table(*engine) // Select(*engine) // SetID(*engine) // Sum(*engine) // SumsInt(*engine) // WhereAnd(*engine) // WhereOr(*engine) // OrderBy(*engine) // Asc(*engine) // Desc(*engine) // SQL(*engine) // Query(*engine) } これでenginの用意が整いました。 以下は、main.goにメソッドを作成したら、こうなるというのを解説していきます。 Table これは操作するテーブルを指定するだけです。 簡単です。 func Table(engine xorm.Engine) { user := User{} // ここでテーブルをユーザーテーブルを指定します。 session := engine.Table("user") _, err := session.Where("id = ?", 1).Get(&user) if err != nil { log.Fatal(err) } fmt.Println("user:", user) } 出力結果 user: {1 花子 30 パスワード 2021-08-29 16:47:24 +0900 JST 2021-08-29 16:47:24 +0900 JST} テーブルを指定して、sessionに入れます。 それをWhereで条件を指定し、Getでマッピングします。 Tableでテーブルを指定しなくても、構造体から勝手に判断してくれます。 前回やった下記のコードでも同じように取得出来ます。 func Get(engine xorm.Engine) { user := User{} _, err := engine.Where("id = ?", 1).Get(&user) if err != nil { log.Fatal(err) } fmt.Println("user:", user) } 結果は同じですが、Tableを使った方が明示的で分かりやすいです。 Select SQLのSELECTと同じです。カラム名を指定します。 func Select(engine xorm.Engine) { user := User{} // ここでテーブルをユーザーテーブルを指定します。 session := engine.Table("user") result, err := session.Select("name").Get(&user) if err != nil { log.Fatal(err) } fmt.Println("user:", user) fmt.Println("result:", result) } 出力結果 user: {0 花子 0 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC} result: true カラムを指定しても、Getの返り値resultはtrueかfalseです。 構造体Userにはnameのカラムだけ入るので、結果は名前だけ更新されています。 Sum, SumInt 指定したカラムの値を合計します。 カラムの数を数えるのではないのでご注意ください。 func Sum(engine xorm.Engine) { user := User{} sumFloat64, _ := engine.Sum(user, "id") print(" sumFloat64: ", sumFloat64) } func SumsInt(engine xorm.Engine) { user := User{} sumInt, _ := engine.SumInt(user, "id") print(" sumInt: ", sumInt) } 出力結果 sumFloat64: +6.000000e+000 sumInt: 6 普通のSumはFloat64が返ってきます。 intで返して欲しい場合は、SumIntを使います。 Where, And, Or この3つはSQLと同じように使います。 func WhereAnd(engine xorm.Engine) { users := []User{} session := engine.Table("user") err := session.Where("id > ?", 1).And("age = ?", 30).Find(&users) if err != nil { log.Fatal(err) } fmt.Println("whereAndUsers:", users) } func WhereOr(engine xorm.Engine) { users := []User{} session := engine.Table("user") err := session.Where("id > ?", 1).Or("age = ?", 30).Find(&users) if err != nil { log.Fatal(err) } fmt.Println("whereOrUsers:", users) } WhereAndはidが1より大きく、かつ、ageが30のユーザーを取得します。 WhereOrはidが1より大きい、もしくは、ageが30のユーザーを取得します。 出力結果 whereAndUsers: [{2 たけし 30 パスワード 2021-08-29 16:48:42 +0900 JST 2021-08-29 16:48:42 +0900 JST}] whereOrUsers: [{1 花子 30 パスワード 2021-08-29 16:47:24 +0900 JST 2021-08-29 16:47:24 +0900 JST} {2 たけし 30 パスワード 2021-08-29 16:48:42 +0900 JST 2021-08-29 16:48:42 +0900 JST} {3 太郎 20 パスワード 2021-08-29 16:49:35 +0900 JST 2021-08-29 16:49:35 +0900 JST}] OrderBy, Asc, Desc これも基本的には、ほとんどSQLと同じです。 func OrderBy(engine xorm.Engine) { users := []User{} session := engine.Table("user") err := session.OrderBy("id DESC").Find(&users) if err != nil { log.Fatal(err) } fmt.Println("users:", users) } 出力結果 users: [{3 太郎 20 パスワード 2021-08-29 16:49:35 +0900 JST 2021-08-29 16:49:35 +0900 JST} {2 たけし 30 パスワード 2021-08-29 16:48:42 +0900 JST 2021-08-29 16:48:42 +0900 JST} {1 花子 30 パスワード 2021-08-29 16:47:24 +0900 JST 2021-08-29 16:47:24 +0900 JST}] func Asc(engine xorm.Engine) { users := []User{} session := engine.Table("user") err := session.Asc("id").Find(&users) if err != nil { log.Fatal(err) } fmt.Println("AscUsers:", users) } 出力結果 AscUsers: [{1 花子 30 パスワード 2021-08-29 16:47:24 +0900 JST 2021-08-29 16:47:24 +0900 JST} {2 たけし 30 パスワード 2021-08-29 16:48:42 +0900 JST 2021-08-29 16:48:42 +0900 JST} {3 太郎 20 パスワード 2021-08-29 16:49:35 +0900 JST 2021-08-29 16:49:35 +0900 JST}] func Desc(engine xorm.Engine) { users := []User{} session := engine.Table("user") err := session.Desc("id").Find(&users) if err != nil { log.Fatal(err) } fmt.Println("DescUsers:", users) } 出力結果 DescUsers: [{3 太郎 20 パスワード 2021-08-29 16:49:35 +0900 JST 2021-08-29 16:49:35 +0900 JST} {2 たけし 30 パスワード 2021-08-29 16:48:42 +0900 JST 2021-08-29 16:48:42 +0900 JST} {1 花子 30 パスワード 2021-08-29 16:47:24 +0900 JST 2021-08-29 16:47:24 +0900 JST}] .OrderByでidだけを指定すると、ASCになります。 .OrderByのidの後ろのDESCはDescでもdesc大丈夫です。 ただ単に昇順や降順にするだけなら、.Ascか.Descを使った方が分かりやすいですね。 SQL, Query xormは生のSQLのQueryも実行出来ます。 func SQL(engine xorm.Engine) { users := []User{} err := engine.SQL("select * from user").Find(&users) if err != nil { log.Fatal(err) } fmt.Println("users:", users) } 出力結果 users: [{1 花子 30 パスワード 2021-08-29 16:47:24 +0900 JST 2021-08-29 16:47:24 +0900 JST} {2 たけし 30 パスワード 2021-08-29 16:48:42 +0900 JST 2021-08-29 16:48:42 +0900 JST} {3 太郎 20 パスワード 2021-08-29 16:49:35 +0900 JST 2021-08-29 16:49:35 +0900 JST}] func Query(engine xorm.Engine) { results, err := engine.Query("select * from user") if err != nil { log.Fatal(err) } fmt.Println("results:", results) } 出力結果 results: [map[age:[51 48] created:[50 48 50 49 45 48 56 45 50 57 84 49 54 58 52 55 58 50 52 90] id:[49] name:[232 138 177 229 173 144] password:[227 131 145 227 130 185 227 131 175 227 131 188 227 131 137] updated:[50 48 50 49 45 48 56 45 50 57 84 49 54 58 52 55 58 50 52 90]] map[age:[51 48] created:[50 48 50 49 45 48 56 45 50 57 84 49 54 58 52 56 58 52 50 90] id:[50] name:[227 129 159 227 129 145 227 129 151] password:[227 131 145 227 130 185 227 131 175 227 131 188 227 131 137] updated:[50 48 50 49 45 48 56 45 50 57 84 49 54 58 52 56 58 52 50 90]] map[age:[50 48] created:[50 48 50 49 45 48 56 45 50 57 84 49 54 58 52 57 58 51 53 90] id:[51] name:[229 164 170 233 131 142] password:[227 131 145 227 130 185 227 131 175 227 131 188 227 131 137] updated:[50 48 50 49 45 48 56 45 50 57 84 49 54 58 52 57 58 51 53 90]]] SQLもQueryもどちらも生のSQL文を使えますが、Queryはbyteで返って来ます。 SQLの方が使いやすそうです。 さいごに 他にも色々ありますが、今回はこの辺で。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Go】xormの使い方 その①(CRUD)

はじめに 業務でxormを使ったのですが、参考にする記事が少なかった印象なので、 初学者への参考になればと記事にしてみました。 今回は基本的なCRUDのみです。 xormとは Go言語で使えるORMです。 Go 1.6以降で利用可能です。 環境 go 1.15 github.com/go-sql-driver/mysql v1.6.0 xorm.io/xorm v1.2.3 xormで出来ること DBのテーブルと、Goの構造体のマッピングが出来ます。 このテーブルと この構造体 type User struct { Id int64 Name string Age int Password string `xorm:"password"` Created time.Time `xorm:"created"` Updated time.Time `xorm:"updated"` } をマッピングします。 後で出てくるGetやFindのメソッドで構造体を指定するだけで勝手にマッピングしてくれます。 便利ですね。 xormのマッピングは先頭が大文字か小文字かは勝手に判断してくれて、いい具合にマッピングしてくれます。 構造体の「Id」は先頭が大文字ですが、DBのカラムは「id」と先頭小文字ですが、マッピングしてくれます。 ただ、構造体を「ID」とすると、マッピングされません。 うまいことやってくれるのは、先頭の文字だけです。 2021/08/29 22:54:28 Error 1075: Incorrect table definition; there can be only one auto column and it must be defined as a key exit status 1 こんなエラーが出ます。 そういう構造体のフィールド名とDBのカラム名が違う場合は、xormタグで、カラム名を指定するとマッピングしてくれます。 type User struct { ID int64 `xorm:"id"` } エンジンの作成 まず初めに、xormを使う為に、engineを作成します。 今回はmySQLを利用しています。 NewEngineの引数は人によって違うと思いますので、参考程度にご確認ください。 私はDockerで立てたsample_dbというDBを使用しています。 func main() { engine, err := xorm.NewEngine("mysql", "root:root@tcp([127.0.0.1]:3306)/sample_db?charset=utf8mb4&parseTime=true") if err != nil { log.Fatal(err) } err = engine.Sync2(new(User)) if err != nil { log.Fatal(err) } } CRUD CRUDのメソッドを説明していきます。 Insert CRUDでいうCREATEに当たるInsertです。 // Insert func Insert(engine xorm.Engine) { user := User{ Name: "太郎", Password: "パスワード", Age: 20, } _, err := engine.Table("user").Insert(user) if err != nil { log.Fatal(err) } } .Table(引数)でDBのテーブル名を指定します。 .Insertの引数にUser構造体を渡すと、User構造体で代入したName:太郎などが、DBに登録されます。 Get CRUDのREADです。 xormにはGetとFindがあり、 Getは単体取得(1レコードの取得) Findは全件取得(複数レコードの取得) です。 Insertと同じように、Getメソッドの引数に構造体を渡します。 User構造体をuserという名前で作成し、それをGetメソッドの引数に渡すことで、そのuserの中にDBのデータを取得する事が出来ます。 取得出来た場合は、返り値にboolでtrueが返ってきます。 //Get 単体取得(1レコードを取得) func Get(engine xorm.Engine) { user := User{} result, err := engine.Where("id = ?", 1).Get(&user) if err != nil { log.Fatal(err) } if !result { log.Fatal("Not Found") } fmt.Println("user:", user) } この上の例は userテーブルから、idが1のレコードを習得しています。 出力結果 user: {1 太郎 20 パスワード 2021-08-29 16:32:18 +0900 JST 2021-08-29 17:48:14 +0900 JST} Find Findは全件取得です。 複数のレコードが返ってくる為、構造体の配列を定義し、それをFindメソッドに引数として渡します。 この例では、ageが20歳のレコードを全件取得します。 // Find 複数取得(複数レコードを取得) func Find(engine xorm.Engine) { users := []User{} // ageが20のuserを全件取得します err := engine.Where("age = ?", 20).Find(&users) if err != nil { log.Fatal(err) } fmt.Println("users:", users) } 出力結果 users: [{1 太郎 20 パスワード 2021-08-29 16:32:18 +0900 JST 2021-08-29 17:48:14 +0900 JST} {6 花子 20 パスワード 2021-08-29 16:49:35 +0900 JST 2021-08-29 16:49:35 +0900 JST}] Count Countはレコードの数を取得します。 // Count レコードの数を取得 func Count(engine xorm.Engine) { user := User{} count, err := engine.Count(&user) if err != nil { log.Println(err) } fmt.Println("レコード数:", count) } 出力結果 レコード数: 3 Update UpdateはDBのデータをUpdateします。 更新したいデータを構造体のフィールドに入力し、それをUpdateメソッドの引数に渡す事で、DBのレコードが書き変わります。 返り値に更新した数が返ってきます。 下記の例では、idが1のレコードを更新します。 // Update func Update(engine xorm.Engine) { user := User{ Name: "更新した名前", Password: "更新したパスワード", Age: 30, } result, err := engine.Where("id =?", 1).Update(&user) if err != nil { log.Println(err) } if result == 0 { log.Fatal("Not Found") } fmt.Println("user:", user) } 出力結果 user: {0 更新した名前 30 更新したパスワード 0001-01-01 00:00:00 +0000 UTC 2021-08-29 23:52:06.220637 +0900 JST} Delete 最後はDeleteです。 下記の例ではidが1のレコードを削除します。 返り値に削除した数が返ってきます。 // Delete func Delete(engine xorm.Engine) { user := User{} result, err := engine.Where("id=?", 1).Delete(&user) if err != nil { log.Println(err) } if result == 0 { log.Fatal("Not Found") } fmt.Println("user:", user) } 出力結果 user: {0 0 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC} さいごに xormもっと色々出来ますが、今回はこの辺にしておきます。 その②もよかったら見てください。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【備忘】Go 言語のデータ型と型変換

備忘として、Go 言語の「データ型」と「型変換(キャスト)」についてまとめておきます。 1.Go 言語データ型一覧 データ型 サイズ 説明 値の範囲 uint8 1byte 符号無し整数 0 ~ 255 uint16 2byte 符号無し整数 0 ~ 65535 uint32 4byte 符号無し整数 0 ~ 4294967295 uint64 8byte 符号無し整数 0 ~ 18446744073709551615 int8 1byte 符号付き整数 -128 ~ 127 int16 2byte 符号付き整数 -32768 ~ 32767 int32 4byte 符号付き整数 -2147483648 ~ 2147483647 int64 8byte 符号付き整数 -9223372036854775808 ~ 9223372036854775807 float32 4byte 単精度浮動小数点数 有効桁数6桁の実数 float64 8byte 倍精度浮動小数点数 有効桁数14桁の実数 complex64 8byte 複素数 float32の実数部と虚数部を持つ複素数 complex128 16byte 複素数 float64の実数部と虚数部を持つ複素数 uint 4byte8byte 符号無し整数 uint32 または uint64 と同じ int 4byte8byte 符号付き整数 int32 または int64 と同じ uintptr (8byte) ポインタ型 PC環境により異なる byte 1byte uint8のエイリアス 0 ~ 255 rune 4byte int32のエイリアス Unicodeのコードポイント1文字分を格納 string - 文字列型 bool 1byte 論理値型 true / false <出典> The Go Programming Language Specification (サイズについての補足) データ型に bit 数が表示されているもについては、サイズは自明です。 それ以外のデータ型のサイズを、手元の環境(Windows 64bit)で確認した結果は次のとおりでした。 main.go package main import ( "fmt" "unsafe" ) func main() { var ui uint fmt.Printf("uint=%dbyte\n", unsafe.Sizeof(ui)) var i int fmt.Printf("int=%dbyte\n", unsafe.Sizeof(i)) var p uintptr fmt.Printf("uintptr=%dbyte\n", unsafe.Sizeof(p)) var r rune fmt.Printf("rune=%dbyte\n", unsafe.Sizeof(r)) var b bool fmt.Printf("bool=%dbyte\n", unsafe.Sizeof(b)) } ターミナル(コマンドプロンプト) C:\golang\sample>go build main.go C:\golang\sample>.\main uint=8byte int=8byte uintptr=8byte rune=4byte bool=1byte 今は、ほとんどの PC が 64bit なので、大体同じ結果になるものと思います。 2.Go 言語のキャスト キャストも簡単です。 int32 にキャストする場合は int32(キャストする変数) float32 にキャストする場合は float32(キャストする変数) というルールで書きます。 実際にコードで確認すると次のような感じです。 main.go package main import "fmt" func main() { // int64 → int32 var num64 int64 = 2147483647 var num32 int32 = int32(num64) fmt.Printf("%T, %d\n", num32, num32) // int32, 2147483647 // uint16 → uint64 var unum16 uint16 = 65535 var unum64 uint64 = uint64(unum16) fmt.Printf("%T, %d\n", unum64, unum64) // uint64, 65535 // float64 → float32 var f64 float64 = 123456.789876 var f32 float32 = float32(f64) fmt.Printf("%T, %f\n", f32, f32) // float32, 123456.789062 } ターミナル(コマンドプロンプト) C:\golang\sample>go build main.go C:\golang\sample>.\main int32, 2147483647 uint64, 65535 float32, 123456.789062 float64 から float32 にキャストすると、123456.789876 という数値が 123456.789062 というように、精度が落ちていることが確認できます。 2-1. 浮動小数点数から整数へのキャスト 浮動小数点数から整数型にキャストすると、小数点以下は切捨てとなるようです(以下のとおり)。 main.go package main import "fmt" func main() { // float32 → int32 var d32 float32 = 123.789 var num32 int32 = int32(d32) fmt.Printf("%T, %d\n", num32, num32) // int32, 123 } ターミナル(コマンドプロンプト) C:\golang\sample>go build main.go C:\golang\sample>.\main int32, 123 2-2. 符号あり変数と符号無し変数間のキャスト uint8(符号無し整数)の値の範囲は 0 ~ 255 です。 int8(符号付き整数)の値の範囲は -128 ~ 127 です。 範囲の重複する 0 ~ 127 であれば、問題なくキャストできます。 範囲が重複しない 255 という数値が変数に格納されている場合に、キャストをすると次のようになります。 main.go package main import "fmt" func main() { // uint8 → int8 var unum8 uint8 = 255 var num8 int8 = int8(unum8) fmt.Printf("%T, %d\n", num8, num8) // int8, -1 } ターミナル(コマンドプロンプト) C:\golang\sample>go build main.go C:\golang\sample>.\main int8, -1 uint8 型の変数に入れている 255 という数値は、本来 int8 ではオーバーフローになるはずですが、エラーは起きず -1 という値で出力されています。 255 と -1 は値は見た目は違いますが、2進数にするとどちらも 11111111 を表しているため値自体は同一ということになります。 細かい説明は省略しますが、コンピュータで負の数を表す場合には、以下のように、その数値(2進数)に対応する2の補数が使用されるため、-1 は2進数で 11111111 と表現されるためです。 <-1 を二進数で表示する> 0000 0001 : 二進数で[1]を表示する 1111 1110 : 0000 0001 の1の補数 1111 1111 : 0000 0001 の2の補数(これが[-1]を表す) <-5 を二進数で表示する> 0000 0101 : 二進数で[5]を表示する 1111 1010 : 0000 0101 の1の補数 1111 1011 : 0000 0101 の2の補数(これが[-5]を表す) 2-3. オーバーフローする場合のキャスト 元のサイズよりも小さいサイズのデータ型にキャストする場合には、オーバーフローとなる場合があります。 しかし、この場合もエラーは生じません。 main.go package main import "fmt" func main() { // uint16 → uint8 var unum16 uint16 = 258 var unum8 uint8 = uint8(unum16) fmt.Printf("%T, %d\n", unum8, unum8) // uint8, 2 } ターミナル(コマンドプロンプト) C:\golang\sample>go build main.go C:\golang\sample>.\main uint8, 2 uint16 では 258 であった変数を、uint8 にキャストすると 2 となります。 これは、キャストの結果により、下8桁分だけの値が取得されているためです。 <uint16に格納された値> 0000 0001 0000 0010 : 二進数で[258]を表示 <uint8に格納された値> 0000 0010 : uint8 へのキャストにより下8桁(8bit分)のみ取得される 結果として[2]が表示される。 3.文字列と数値の相互変換 「文字列から数値に変換する場合」及び「数値から文字列に変換する場合」は、strconv ライブラリを使用します。 3-1. 文字列から数値への変換 3-1-1. 一般的な変換 文字列から数値への変換は、Atoi 関数を使用します(atoi とは「ASCII to Integer」の意です)。 コードを書くと、次のようになります。 main.go package main import ( "fmt" "strconv" ) func main() { var numStr1 string = "2468" i, err := strconv.Atoi(numStr1) fmt.Println(i) // 2468 fmt.Println(err) // <nil> var numStr2 string = "2468yen" // 数字以外の文字が混じっている場合 j, err := strconv.Atoi(numStr2) fmt.Println(j) // 0 fmt.Println(err) // strconv.Atoi: parsing "2468yen": invalid syntax } ターミナル(コマンドプロンプト) C:\golang\sample>go build main.go C:\golang\sample>.\main 2468 <nil> 0 strconv.Atoi: parsing "2468yen": invalid syntax Atoi 関数を使用すると2つの値が戻ってきます。 1つ目は、int 型で文字列を変換した数値が返されます。 2つ目は、エラーの内容が返されます。 数値以外の文字を変換しようとすると、エラーが生じます。 上記のコードで、"2468yen" という文字列を変換しようとすると、strconv.Atoi: parsing "2468yen": invalid syntax という構文エラーが表示され、数値としては 0 という値が返されています。 エラーの取得が不要な場合は、次のように err を _ に置き換えます。 main.go package main import ( "fmt" "strconv" ) func main() { var numStr string = "12345678" var n int // あらかじめ変数を指定する場合はint型 n, _ = strconv.Atoi(numStr) fmt.Println(n) // 12345678 } なお、数値は int 型で返されますので、あらかじめ変数を指定する場合は int 型の変数としておきます。 3-1-2. 詳細な変換指定 main.go package main import ( "fmt" "strconv" ) func main() { b, _ := strconv.ParseBool("true") fmt.Printf("%T, %t\n", b, b) // bool, true f, _ := strconv.ParseFloat("3.1415", 64) fmt.Printf("%T, %f\n", f, f) // float64, 3.141500 i, _ := strconv.ParseInt("-42", 10, 32) fmt.Printf("%T, %d\n", i, i) // int64, -42 u, _ := strconv.ParseUint("42", 10, 16) fmt.Printf("%T, %d\n", u, u) // uint64, 42 } ターミナル(コマンドプロンプト) C:\golang\sample>go build main.go C:\golang\sample>.\main bool, true float64, 3.141500 int64, -42 uint64, 42 bool 型への変換には ParseBool 関数を使用します。 float 型への変換には ParseFloat 関数を使用します。 1つ目の引数には変換したい文字列を指定し、2つ目の引数には変換後の bit 数を指定します(bit 数に関わらず取得されるデータ型は float64 になります)。 int 型への変換には ParseInt 関数を使用します。 1つ目の引数には変換したい文字列を指定し、2つ目の引数には変換文字列の進数を指定し、3つ目の引数には変換後の bit 数を指定します(bit 数に関わらず取得されるデータ型は int64 になります)。 uint 型への変換には ParseUint 関数を使用します。 1つ目の引数には変換したい文字列を指定し、2つ目の引数には変換文字列の進数を指定し、3つ目の引数には変換後の bit 数を指定します(bit 数に関わらず取得されるデータ型は uint64 になります)。 (2進数や 16 進数に変換する場合) 2進数や 16 進数に変換する場合は、次のようになります。 main.go package main import ( "fmt" "strconv" ) func main() { i, err := strconv.ParseInt("ffff", 16, 64) fmt.Printf("%T, %d\n", i, i) // int64, 65535 fmt.Println(err) // <nil> u, err := strconv.ParseUint("11111111", 2, 64) fmt.Printf("%T, %d\n", u, u) //uint64, 255 fmt.Println(err) // <nil> u2, err := strconv.ParseUint("42", 2, 64) fmt.Printf("%T, %d\n", u2, u2) // uint64, 0 fmt.Println(err) // strconv.ParseUint: parsing "42": invalid syntax } ターミナル(コマンドプロンプト) C:\golang\sample>go build main.go C:\golang\sample>.\main int64, 65535 <nil> uint64, 255 <nil> uint64, 0 strconv.ParseUint: parsing "42": invalid syntax 最後の例は、"42" という数字を2進数に変換しようとしたが、0、1 以外の数字が含まれているため、エラーが発生した場合です。 3-2. 数値から文字列への変換 3-2-1. 一般的な変換 数値から文字列への変換は、Itoa 関数を使用します(itoa とは「Integer to ASCII」の意です)。 コードを書くと、次のようになります。 main.go package main import ( "fmt" "strconv" ) func main() { var num int = 100 var str string = strconv.Itoa(num) fmt.Println(str) // 100 } ターミナル(コマンドプロンプト) C:\golang\sample>go build main.go C:\golang\sample>.\main 100 出力値の見た目は 100 ですが、文字列に変換されています。 3-2-2. 詳細な変換指定 main.go package main import ( "fmt" "strconv" ) func main() { s1 := strconv.FormatBool(true) fmt.Printf("%T, %s\n", s1, s1) // string, true s2 := strconv.FormatFloat(3.1415, 'E', -1, 64) fmt.Printf("%T, %s\n", s2, s2) // string, 3.1415E+00 s3 := strconv.FormatInt(-42, 16) fmt.Printf("%T, %s\n", s3, s3) // string, -2a s4 := strconv.FormatUint(42, 16) fmt.Printf("%T, %s\n", s4, s4) // string, 2a } ターミナル(コマンドプロンプト) C:\golang\sample>go build main.go C:\golang\sample>.\main string, true string, 3.1415E+00 string, -2a string, 2a bool 型から string 型への変換には FormatBool 関数を使用します。 float 型から string 型への変換には FormatFloat 関数を使用します。 1つ目の引数には変換したい実数を指定し、2つ目の引数には浮動小数点数の書式を表す指定子を指定し、3つ目の引数には変換後小数点の桁数を指定し(-1 は全て表示)、4つ目の引数には変換後の浮動小数点数の精度(bit 数)を指定します。 int 型から string 型への変換には FormatInt 関数を使用します。 1つ目の引数には変換したい整数を指定し、2つ目の引数には変換する数値の進数を指定します。 uint 型から string 型への変換には FormatUint 関数を使用します。 1つ目の引数には変換したい整数を指定し、2つ目の引数には変換する数値の進数を指定します。 詳しくは、下記のサイトが分りやすいです。 <参考> 【Go入門】strconvパッケージ ~ 文字列型と数値型・論理型の相互変換 さいごに Go を触り始めたばかりなので間違いもあるかと思います。 お気づきのことなどありましたら、ご指摘いただけると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Golang の構造体の初期値をnil にしたいときはポインタ型でフィールド変数で定義する

Golangの初期値 Golangはプリミティブ型にそれぞれ初期値を持っている。 string型 なら"" int型 なら0 など、ゼロ値という名前でそれぞれのプリミティブ型を定義した時になんの値が入っているかが既に決まっている。 しかし、フィールド変数の型をユーザ定義型にしている構造体を扱う場合、単純に構造体のインスタンスを生成してしまうと、ユーザ定義型を遡ってプリミティブ型のゼロ値を代入された構造体が生成され、特定のフィールドだけnil にすることができません。 こうしてしまうと、他のAPIからjson を読み込みたい時などに全てのフィールドに空文字が入ってしまったり、0 が入ってしまったりしてしまうため、あまり良いとは言えません。 解決策 フィールド定義を行う時にユーザ定義型のポインタ型にしましょう。 ポインタ型のゼロ値はnil なので、代入されていないフィールドが自動的にnil になって返却されます。 参考元
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む