はじめに
2026-02-10にGo1.26がリリースされました!今回、個人的に激アツだったのが「new()関数が式を受け取れる」ことです。1.25以前だとpointerの場合、一度変数に書き出すorヘルパー関数を用意する必要がありました!
これがGoの標準パッケージに組み込まれ、new()関数で扱えるようになっています!!Mock作る時にヘルパー関数を用意していたので、これは個人的には激アツでした!!なので、記事にして共有しようと思います!!
従来(Go 1.25以前)のnew()
// new()はゼロ値で初期化のみ
age := new(int) // *age = 0
// 初期値を設定したい場合、一時変数が必要
tempAge := 30
agePtr := &tempAge
Go 1.26の新しいnew()
// new()に式を渡せる!
age := new(30) // *age = 30
// 関数の戻り値も使える
age := new(calculateAge(1990))
// リテラル、関数、演算、なんでもOK
count := new(len(items))
total := new(price * quantity)
実用例
1. 構造体のオプショナルフィールド
Go 1.25以前:
type Person struct {
Name string
Age *int // nilの場合は年齢不明
}
// 年齢を設定する場合、一時変数が必要
age := 30
p := Person{
Name: "太郎",
Age: &age,
}
Go 1.26:
// new()で直接初期化!
p := Person{
Name: "太郎",
Age: new(30), // シンプル!
}
2. JSON/Protocol Buffersでの活用
JSONやProtocol Buffersでは、オプショナルフィールドをポインタで表現します。
公式リリースノートの例:
import "encoding/json"
type Person struct {
Name string `json:"name"`
Age *int `json:"age"` // 年齢が不明の場合はnil
}
func personJSON(name string, born time.Time) ([]byte, error) {
return json.Marshal(Person{
Name: name,
Age: new(yearsSince(born)), // 関数を直接渡せる!
})
}
func yearsSince(t time.Time) int {
return int(time.Since(t).Hours() / (365.25 * 24))
}
Go 1.25でのコード(比較):
func personJSON(name string, born time.Time) ([]byte, error) {
// 一時変数が必要で冗長
age := yearsSince(born)
return json.Marshal(Person{
Name: name,
Age: &age,
})
}
3. 実際の動作例
package main
import (
"fmt"
"time"
)
type Person struct {
Name string
Age *int
City string
}
func calculateAge(birthYear int) int {
return time.Now().Year() - birthYear
}
func main() {
// Go 1.26の新機能
person := Person{
Name: "太郎",
Age: new(calculateAge(1990)), // 関数結果で初期化
City: "東京",
}
fmt.Printf("%s: %d歳\n", person.Name, *person.Age)
// 出力: 太郎: 36歳
}
どんな式が使えるか
| 式の種類 | 例 | 説明 |
|---|---|---|
| リテラル | new(42) |
数値、文字列などの定数 |
| 関数呼び出し | new(calc()) |
関数の戻り値 |
| 演算 | new(x + y) |
計算結果 |
| 型変換 | new(int(3.14)) |
型変換の結果 |
| 任意の式 | new(items[0]) |
評価可能な式ならなんでも |
重要: 式が返す型とnew()の型パラメータは一致している必要があります。
Go 1.25 vs Go 1.26 コード比較
パターン1: オプショナルなint値
Go 1.25:
age := 30
person := &Person{Age: &age} // 一時変数が必要
Go 1.26:
person := &Person{Age: new(30)} // 1行で完結
パターン2: 計算結果をポインタで保持
Go 1.25:
result := expensive_calculation()
ptr := &result
use(ptr)
Go 1.26:
ptr := new(expensive_calculation()) // シンプル
use(ptr)
パターン3: JSONマーシャリング
Go 1.25:
// 構造体を作る際に一時変数だらけ
count := len(items)
total := calculateTotal(items)
data := ResponseData{
Count: &count,
Total: &total,
}
Go 1.26:
// スッキリ!
data := ResponseData{
Count: new(len(items)),
Total: new(calculateTotal(items)),
}
なぜこの変更が重要か
1. コードの可読性向上
一時変数が減り、意図が明確になります。
2. JSONやgRPCでの利便性
オプショナルフィールド(*int, *stringなど)を簡潔に設定できます。
3. ボイラープレートの削減
ポインタを作るための定型コードが不要になります。
4. 関数型プログラミング的アプローチ
式を直接書けるため、より宣言的なコードが書けます。
実行してみる
package main
import (
"fmt"
"time"
)
type Person struct {
Name string
Age *int // ポインタ型
City string
}
// 年齢を計算する関数
func calculateAge(birthYear int) int {
return time.Now().Year() - birthYear
}
// 年数を計算する関数
func yearsSince(t time.Time) int {
return int(time.Since(t).Hours() / (365.25 * 24))
}
func main() {
fmt.Println("=== Go 1.26のnew()の新機能 ===\n")
// Go 1.26の新機能:new()に式を渡せる
fmt.Println("1. new()に式を渡す:")
age := new(calculateAge(1995))
fmt.Printf(" 年齢ポインタ: %d\n", *age)
// オプショナルフィールドでの活用例
fmt.Println("\n2. 構造体のオプショナルフィールド:")
person1 := Person{
Name: "太郎",
Age: new(calculateAge(1990)), // 式の結果で初期化
City: "東京",
}
fmt.Printf(" %s: %d歳\n", person1.Name, *person1.Age)
// 時刻からの計算
fmt.Println("\n3. 時刻から年数を計算:")
born := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)
person2 := Person{
Name: "花子",
Age: new(yearsSince(born)),
City: "大阪",
}
fmt.Printf(" %s: %d歳\n", person2.Name, *person2.Age)
// リテラル値
fmt.Println("\n4. リテラル値での初期化:")
person3 := Person{
Name: "次郎",
Age: new(25), // リテラル値も式
City: "福岡",
}
fmt.Printf(" %s: %d歳\n", person3.Name, *person3.Age)
// Go 1.25以前の方法との比較
fmt.Println("\n【Go 1.25以前の方法】")
oldAge := calculateAge(1990)
person4 := Person{
Name: "三郎",
Age: &oldAge, // 変数を作ってアドレスを取得
City: "名古屋",
}
fmt.Printf(" %s: %d歳\n", person4.Name, *person4.Age)
fmt.Println("\n=== まとめ ===")
fmt.Println("Go 1.26では new(式) が可能になりました!")
fmt.Println("• new(calculateAge(1995)) → 関数の戻り値で初期化")
fmt.Println("• new(25) → リテラル値で初期化")
fmt.Println("• より簡潔にポインタを初期化できます")
}
# main.goを実行
go run main.go
期待される出力:
~/develop/go_126$ go run main.go
=== Go 1.26のnew()の新機能 ===
1. new()に式を渡す:
年齢ポインタ: 31
2. 構造体のオプショナルフィールド:
太郎: 36歳
3. 時刻から年数を計算:
花子: 26歳
4. リテラル値での初期化:
次郎: 25歳
【Go 1.25以前の方法】
三郎: 36歳
=== まとめ ===
Go 1.26では new(式) が可能になりました!
• new(calculateAge(1995)) → 関数の戻り値で初期化
• new(25) → リテラル値で初期化
• より簡潔にポインタを初期化できます
まとめ
Go 1.26のnew()まとめ
| 項目 | Go 1.25以前 | Go 1.26 |
|---|---|---|
| 基本 | new(Type) |
new(expression) |
| 初期値 | 常にゼロ値 | 式の評価結果 |
| 使用例 |
new(int) → 0へのポインタ |
new(42) → 42へのポインタ |
| 一時変数 | 必要 | 不要 |
| コード行数 | 多い | 少ない |
この機能を使うべきケース
✅ JSONやProtocol Buffersのオプショナルフィールド
✅ 関数の結果をポインタで返したい時
✅ リテラル値のポインタが必要な時
✅ 一時変数を減らしてコードを簡潔にしたい時
従来の方法も有効
もちろん、従来の&variableや&Type{...}も引き続き使えます。状況に応じて使い分けましょう。