kurumi-bioの雑記帳

プログラミング、パソコン、ペット、 犬、お出かけ

初心者のGo言語 -19- go1.20とgo1.19のfmtパッケージの差異

こんにちは、kurumi-bioです。 2023年2月1日にGo言語のメジャーバージョンアップが行われてバージョンが1.20になりました。
今まで学習してきたfmtパッケージにも変更がありましたので調査しました。

環境

OSバージョン:Windows11 Home 22H2
Go言語のバージョン:

  1. go version go1.19.4 windows/amd64
  2. go version go1.20 windows/amd64

fmtパッケージの変更点

  1. Errorf 関数は、%w 形式の動詞の複数回の出現をサポートし、%w へのすべての引数のリストにアンラップするエラーを返します。
  2. 新しい FormatString 関数は、State に対応するフォーマット ディレクティブを復元します。これは Formatter で役立ちます。実装。

fmt.Errorf

func Errorf(format string, a ...any) error

Version: go1.19.4の説明

Errorf は、フォーマット指定子に従ってフォーマットし、エラーを満たす値として文字列を返します。

フォーマット指定子にエラー オペランドを持つ %w 動詞が含まれている場合、返されるエラーは、オペランドを返す Unwrap メソッドを実装します。複数の %w 動詞を含めたり、エラー インターフェイスを実装しないオペランドを指定したりすることは無効です。それ以外の場合、%w 動詞は %v の同義語です。

Version: go1.20の説明

Errorf は、フォーマット指定子に従ってフォーマットし、エラーを満たす値として文字列を返します。

フォーマット指定子にエラー オペランドを持つ %w 動詞が含まれている場合、返されるエラーは、オペランドを返す Unwrap メソッドを実装します。複数の %w 動詞がある場合、返されるエラーは Unwrap メソッドを実装し、引数に現れる順序ですべての %w オペランドを含む [] エラーを返します。エラー インターフェイスを実装しないオペランドを %w 動詞に指定することは無効です。それ以外の場合、%w 動詞は %v の同義語です。

説明が異なる箇所に色を付けました。
異なる点はgo1.19.4では複数の%wを使うことが禁止されていましたが、go1.20では、複数の%wの記載が可能となっています。
では、fmt.Errorfに2つの%wを指定すると、どうなるか試してみました。

<サンプルコード>ErrorfTest.go

package main

import (
    "fmt"
    "errors"
)

func main() {
    e1 := errors.New("error1")
    e2 := errors.New("error2")

    e := fmt.Errorf("%w %w", e1, e2)

    fmt.Println(e)
}

<実行結果>

go1.19.4では、二つ目の%wが表示されませんでしたが、
go1.20ですと、書式指定した通りに2つのerrorが表示されました。

<広告の下に記事が続きます。>

fmt.FormatString

func FormatString(state State, verb rune) string

FormatString は、State によってキャプチャされた完全修飾フォーマット ディレクティブを表す文字列を返し、その後に引数動詞が続きます。 (状態自体には動詞は含まれません。) 結果には先頭のパーセント記号があり、その後にフラグ、幅、および精度が続きます。欠落しているフラグ、幅、および精度は省略されています。この関数を使用すると、Formatter は、Format の呼び出しをトリガーする元のディレクティブを再構築できます。

go1.20で新規追加された関数です。
fmt.Stateがinterfaceで宣言されていて、これで正しいのかわからないのですが、 4桁の数値の書式設定を返すサンプルコードを作成しました。

<サンプルコード>FormatStringTest.go

package main

import (
    "fmt"
    "errors"
)

type FourDigit struct {}
func (f FourDigit) Write(b []byte)(int, error) {
    e := errors.New("Write error!")
    return 0, e
}
func (f FourDigit) Width()(int, bool){
    return 4, true
}
func (f FourDigit) Precision()(int ,bool){
    return 0, false
}
func (f FourDigit) Flag(c int) bool{
    return true
}

func main() {
    var f FourDigit

    var s fmt.State
    var v rune
    v = 'd'
    s = f
    fmt.Println(fmt.FormatString(s,v))
    fmt.Printf(fmt.FormatString(s,v),4)
}

<実行結果>

それっぽい書式設定文字列が返されて、fmt.Printfに渡すことができました。 こんな遠回りなことをしなくても、もっと簡単にできそうな気がしますので、 根本的に使い方が間違っている気がしました。

ちなみに、go1.19.4では「未定義」と表示されて実行不可でした。

最後までご覧いただきありがとうございます