Go 1.21.0 の新機能 min および max 組み込み関数分析

1 はじめに

Go 1.21.0 は Go 言語の最新バージョンで、2023 年 8 月にリリースされる予定で、言語とツールにいくつかの変更が加えられます。注目すべき変更の 1 つは、2 つの新しい組み込み関数 min と max の追加です。これらの関数は、同等の型に対して最小値と最大値の演算を実行するために使用されます。これは非常に一般的な要件であり、現在は組み込みの実装が用意されています。この記事では、これら 2 つの機能の背景、仕様、実装原理、使用例を紹介します。

1.1 これら 2 つの関数の背景を追加する

Go 言語では、並べ替え、統計、フィルター処理など、一連の値に対して最小限または最大限の操作を必要とする状況が数多くあります。ただし、Go 言語にはこの関数を実装するための直接的な方法が用意されていないため、開発者は独自のループを作成してこの関数を完了する必要があります。(標準ライブラリの math には対応する関数がありますが、float64 型の受け入れのみをサポートしています。)

しかし、これは実際には非常に一般的な要件です。この目的を達成するために、Go 1.21.0 では 2 つの新しい組み込み関数 min と max を導入しています。これらの関数は、ループを作成したりサードパーティ ライブラリを導入したりせずに、同等の型に対して最小または最大の操作を実行できます。

1.2 それはどのように見えますか?

Go の組み込みドキュメントによると、min と max の関数プロトタイプは次のとおりです。

// The max built-in function returns the largest value of a fixed number of
// arguments of [cmp.Ordered] types. There must be at least one argument.
// If T is a floating-point type and any of the arguments are NaNs,
// max will return NaN.
func max[T cmp.Ordered](x T, y ...T) T

// The min built-in function returns the smallest value of a fixed number of
// arguments of [cmp.Ordered] types. There must be at least one argument.
// If T is a floating-point type and any of the arguments are NaNs,
// min will return NaN.
func min[T cmp.Ordered](x T, y ...T) T

関数のプロトタイプからわかるように、min と max のパラメーターと戻り値は同じ型であり、整数、浮動小数点数、文字列など、比較可能な順序付けされた型である必要があります。パラメータが 1 つだけの場合、それは最小値または最大値です。複数のパラメーターがある場合、min と max は < 演算子に従ってサイズを比較し、最小値または最大値を返します。同一の最小値または最大値が複数ある場合、min は左端の値を返し、max は右端の値を返します。パラメーターがない場合、またはパラメーターが順序付けされた型ではない場合、min と max はコンパイルに失敗します。

2. この2つの機能の実現原理

min と max は組み込み関数であり、その実装は実行時ではなくコンパイラ レベルで行われます。具体的には、コンパイラの SSA (Static Single Assignment) ステージで変換され、min 呼び出しと max 呼び出しが対応するループ コードに変換されます。この利点は、新しいランタイム関数の導入を回避できることと、コンパイラーに最適化の余地を与えることもできることです。

特定の実装コードは src/cmd/compile/internal/types2/builtins.go にあります: (部分コード)

for i, a := range args {
    
    
    if a.mode == invalid {
    
    
        return
    }

    if !allOrdered(a.typ) {
    
    
        check.errorf(a, InvalidMinMaxOperand, invalidArg+"%s cannot be ordered", a)
        return
    }

    // The first argument is already in x and there's nothing left to do.
    if i > 0 {
    
    
        check.matchTypes(x, a)
        if x.mode == invalid {
    
    
            return
        }

        if !Identical(x.typ, a.typ) {
    
    
            check.errorf(a, MismatchedTypes, invalidArg+"mismatched types %s (previous argument) and %s (type of %s)", x.typ, a.typ, a.expr)
            return
        }

        if x.mode == constant_ && a.mode == constant_ {
    
    
            if constant.Compare(a.val, op, x.val) {
    
    
                *x = *a
            }
        } else {
    
    
            x.mode = value
        }
    }
}

ご覧のとおり、コンパイラーは min の呼び出しを 2 番目のパラメーターから開始してスライスを走査するループに変換し、サイズを最初のパラメーターと比較して、min/max 変数を更新します。

3. 使用例

min 関数と max 関数の使用は非常に簡単で、比較する値をパラメータとして渡すだけです。

使用例をいくつか示します: (オンライン実行アドレス https://go.dev/play/p/AQ6HD_gfame?v=gotip)

package main

import (
 "fmt"
 "math"
)

func main() {
    
    
 // 比较整数
 fmt.Println(min(1, 2, 3)) // 1
 fmt.Println(max(1, 2, 3)) // 3

 // 比较浮点数
 fmt.Println(min(1.5, 2.5, 3.5)) // 1.5
 fmt.Println(max(1.5, 2.5, 3.5)) // 3.5

 // 浮点数包含 NaN
 fmt.Println(min(1.5, math.NaN(), 3.5)) // NaN
 fmt.Println(max(1.5, math.NaN(), 3.5)) // NaN

 // 比较字符串
 fmt.Println(min("apple", "banana", "cherry")) // apple
 fmt.Println(max("apple", "banana", "cherry")) // cherry
}

出力結果:

1
3
1.5
3.5
NaN
NaN
apple
cherry

ご覧のとおり、min 関数と max 関数は、追加のコードを記述せずに、さまざまな種類の値に対して最小値と最大値の演算を実行するのに便利です。

4. まとめ

この記事では、Go 1.21.0 の 2 つの新しい組み込み関数 min および max を紹介します。これらの関数は、同等の型に対して最小および最大の操作を実行できます。現在、Go1.21.0 はリリースされておらず、具体的な実装は変更される可能性があります。

おすすめ

転載: blog.csdn.net/weixin_43114209/article/details/131518009