0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Go1.26 new()関数が式を受け取れるように!

0
Posted at

はじめに

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. 関数型プログラミング的アプローチ

式を直接書けるため、より宣言的なコードが書けます。

実行してみる

main.go
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{...}も引き続き使えます。状況に応じて使い分けましょう。

参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?