目次
?中身は何ですか
?基本的な汎用プログラム
ホームページ バックエンド開発 Golang Go のジェネリックス: コードの再利用性を変革する

Go のジェネリックス: コードの再利用性を変革する

Jan 08, 2025 am 06:20 AM

Go 1.18 で導入されたジェネリックは、再利用可能でタ​​イプセーフなコードを記述する方法に革命をもたらしました。ジェネリックは Go のシンプルさの哲学を維持しながら、柔軟性とパワーをもたらします。ただし、ニュアンスや利点、ジェネリックと従来のアプローチ (interface{} など) との比較を理解するには、詳しく調べる必要があります。

ジェネリックの複雑さを調べ、制約を詳しく調べ、ジェネリックとインターフェースを比較して、実際のアプリケーションをデモンストレーションしましょう。{}パフォーマンスに関する考慮事項とバイナリ サイズへの影響についても触れます。飛び込んでみましょう!

ジェネリックとは何ですか?

開発者は、ジェネリックを使用して、型の安全性を維持しながら任意の型で動作できる関数とデータ構造を作成できます。実行時に型アサーションを必要とするインターフェース{}に依存する代わりに、ジェネリックを使用すると、型に対して許可される操作を指示する一連の制約を指定できます。

構文

func FunctionName[T TypeConstraint](parameterName T) ReturnType {
    // Function body using T
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

T: 型のプレースホルダーを表す型パラメーター。

TypeConstraint: T の型を特定の型または型のセットに制限します。

parameterName T: パラメーターはジェネリック型 T を使用します。

ReturnType: この関数は、型 T の値を返すこともできます。


func Sum[T int | float64](a, b T) T {
    return a + b
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

func Sum: 関数の名前 Sum

を宣言します。

[T int | float64]: 特定の型 (int または float64) に制限された、型パラメーターとして T を導入する型パラメーター リストを指定します。 Sum 関数は、int または float64 のいずれかのパラメーターのみを受け取り、組み合わせることはできません。両方とも int または float64 のいずれかでなければなりません。これについては、以下のセクションでさらに詳しく説明します。

(a, b T): 2 つのパラメーター a と b を宣言します。どちらも型 T (ジェネリック型) ).

T: 型パラメータ T に一致する関数の戻り型を指定します。

制約: ジェネリックの構成要素

制約は、ジェネリック型に対してどのような操作が有効であるかを定義します。 Go は、実験的な制約パッケージ (golang.org/x/exp/constraints) などの制約用の強力なツールを提供します。

組み込みの制約

Go では、型安全性を提供すると同時に、再利用可能なジェネリック コードを柔軟に定義できるように、ジェネリックを使用した組み込み制約を導入しました。これらの制約により、開発者はジェネリック関数または型で使用される型にルールを適用できます。

Go には以下の組み込み制約があります

  1. any: 任意の型を表します。これはインターフェースのエイリアスです。{}これは制約が必要ない場合に使用されます
func FunctionName[T TypeConstraint](parameterName T) ReturnType {
    // Function body using T
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
  1. comparable: 等価比較 (== および !=) をサポートする型を許可します。マップキー、重複検出、または等価性チェックに役立ちます。これらの型は直接比較をサポートしていないため、これはマップ、スライス、関数には使用できません。
func Sum[T int | float64](a, b T) T {
    return a + b
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

実験上の制約

  1. constraints.Complex: 複素数値型 (complex64 および complex128) を許可します。
  2. constraints.Float: float 数値型 (float32 および float64) を許可します
  3. constraints.Integer: 符号付きおよび符号なしの両方の整数を許可します (int8、int16、int32、int64、int、uint8、uint16、uint32、uint64、および uint)
  4. constraints.Signed: 任意の符号付き整数 (int8、int16、int32、int64、および int) を許可します
  5. constraints.Unsigned: 任意の符号なし整数 (uint8、uint16、uint32、uint64、および uint) を許可します。
  6. constraint.Ordered: 比較を許可する型 (<. <=、>、>=)、すべての数値型と文字列がサポートされます (int、float64、string など)。
func PrintValues[T any](values []T) {
    for _, v := range values {
        fmt.Println(v)
    }
}
ログイン後にコピー
ログイン後にコピー

カスタム制約

カスタム制約は、ジェネリック型パラメーターが満たさなければならない型または型の動作のセットを定義するインターフェイスです。独自の制約を作成することで、次のことが可能になります。

  • 数値型など、型を特定のサブセットに制限します。

  • 特定のメソッドまたは動作を実装するには型が必要です。

  • 汎用関数と型にさらに制御性と特異性を追加します。

構文

func CheckDuplicates[T comparable](items []T) []T {
    seen := make(map[T]bool)
    duplicates := []T{}
    for _, item := range items {
        if seen[item] {
            duplicates = append(duplicates, item)
        } else {
            seen[item] = true
        }
    }
    return duplicates
}
ログイン後にコピー
ログイン後にコピー


import (
     "golang.org/x/exp/constraints"
     "fmt"
)

func SortSlice[T constraints.Ordered](items []T) []T {
    sorted := append([]T{}, items...) // Copy slice
    sort.Slice(sorted, func(i, j int) bool {
        return sorted[i] < sorted[j]
    })
    return sorted
}

func main() {
    nums := []int{5, 2, 9, 1}
    fmt.Println(SortSlice(nums)) // Output: [1 2 5 9]

    words := []string{"banana", "apple", "cherry"}
    fmt.Println(SortSlice(words)) // Output: [apple banana cherry]
}
ログイン後にコピー
ログイン後にコピー

Sum 関数 は、int、int64、float64 パラメーターのみを使用して呼び出すことができます。

メソッド別の制約

型に特定のメソッドを実装する必要がある場合は、それらのメソッドを使用して型を定義できます。

type Numeric interface {
    int | float64 | uint
}
ログイン後にコピー
ログイン後にコピー

Formatter 制約では、T として使用される型には、文字列.

制約の結合

カスタム制約は型セットとメソッド要件を組み合わせることができます


type Number interface {
    int | int64 | float64
}

func Sum[T Number](a, b T) T {
    return a + b
}
ログイン後にコピー
この制約には両方の特定の型 (

int、float54) が含まれており、abs メソッドの存在が必要です。

ジェネリックとインターフェース{}

ジェネリックの導入前は、柔軟性を実現するためにインターフェイス{}が使用されていました。ただし、このアプローチには制限があります。

タイプセーフティ

  • インターフェース{}: 実行時の型アサーションに依存するため、実行時にエラーが発生する可能性が高くなります。

  • ジェネリック: コンパイル時の型安全性を提供し、開発中の早期にエラーをキャッチします。

パフォーマンス

  • インターフェース{}: 追加のランタイム型チェックにより速度が低下します。

  • ジェネリック: コンパイラーが型に固有の最適化されたコード パスを生成するため、高速になります。

コードの可読性

  • インターフェース{}: 多くの場合冗長で直感的ではないため、コードの保守が難しくなります。

  • ジェネリック: よりクリーンな構文により、コードがより直感的で保守しやすくなります。

バイナリサイズ

  • インターフェース{}: 異なるタイプのコードを複製しないため、バイナリが小さくなります。

  • ジェネリック: パフォーマンス向上のための型の特殊化により、バイナリ サイズがわずかに増加します。


func FunctionName[T TypeConstraint](parameterName T) ReturnType {
    // Function body using T
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

コードは正常に機能しますが、型アサーションはオーバーヘッドです。 Add 関数は任意の引数を指定して呼び出すことができます。a パラメータと b パラメータは両方とも異なる型にすることができますが、コードは実行時にクラッシュします。

func Sum[T int | float64](a, b T) T {
    return a + b
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

ジェネリックにより、不正な型アサーションによって引き起こされる実行時パニックのリスクが排除され、明確さが向上します。

パフォーマンス

ジェネリックは各タイプに特化したコードを生成するため、インターフェース{}と比較して実行時のパフォーマンスが向上します。

バイナリサイズ

トレードオフが存在します。ジェネリックスでは、型ごとにコードが重複するためバイナリ サイズが増加しますが、これは多くの場合、利点に比べれば無視できるものです。

Go ジェネリックの制限

制約の複雑さ:constraints.Ordered のような制約は一般的な使用例を単純化しますが、高度にカスタマイズされた制約の定義は冗長になる可能性があります。

構造体には型推論がありません: 関数とは異なり、構造体には型パラメーターを明示的に指定する必要があります。

func PrintValues[T any](values []T) {
    for _, v := range values {
        fmt.Println(v)
    }
}
ログイン後にコピー
ログイン後にコピー

コンパイル時の制約に限定: Go ジェネリックスはコンパイル時の安全性に焦点を当てていますが、Rust のような言語はライフタイムとトレイトを使用したより強力な制約を提供します。

ベンチマークをしましょう — 言うよりもやったほうが良い

インターフェースと汎用の両方を備えたシンプルなキューを実装し、結果をベンチマークします。

インターフェース{} キューの実装

func CheckDuplicates[T comparable](items []T) []T {
    seen := make(map[T]bool)
    duplicates := []T{}
    for _, item := range items {
        if seen[item] {
            duplicates = append(duplicates, item)
        } else {
            seen[item] = true
        }
    }
    return duplicates
}
ログイン後にコピー
ログイン後にコピー

汎用キューの実装

import (
     "golang.org/x/exp/constraints"
     "fmt"
)

func SortSlice[T constraints.Ordered](items []T) []T {
    sorted := append([]T{}, items...) // Copy slice
    sort.Slice(sorted, func(i, j int) bool {
        return sorted[i] < sorted[j]
    })
    return sorted
}

func main() {
    nums := []int{5, 2, 9, 1}
    fmt.Println(SortSlice(nums)) // Output: [1 2 5 9]

    words := []string{"banana", "apple", "cherry"}
    fmt.Println(SortSlice(words)) // Output: [apple banana cherry]
}
ログイン後にコピー
ログイン後にコピー
type Numeric interface {
    int | float64 | uint
}
ログイン後にコピー
ログイン後にコピー

結果の分析

  • 実行時間:
    汎用実装は、実行時の型アサーションを回避し、指定された型で直接動作するため、インターフェイス バージョンよりも約 63.64% 高速です。

  • 割り当て:
    インターフェースのバージョンでは、主に値の挿入および取得時のボックス化/ボックス化解除により、3 倍多くの割り当てが行われます。{}これにより、ガベージ コレクションにオーバーヘッドが追加されます。

100 万回のエンキュー/デキュー操作など、より大きなワークロードの場合、パフォーマンスのギャップは拡大します。高スループット要件を持つ現実世界のアプリケーション (メッセージ キュー、ジョブ スケジューラなど) は、ジェネリックから大きな恩恵を受けます。

最終的な考え

Go のジェネリックスは、パワーとシンプルさのバランスをとり、再利用可能でタ​​イプセーフなコードを作成するための実用的なソリューションを提供します。 Rust や C ほど機能が豊富ではありませんが、Go のミニマリスト哲学と完全に一致しています。 Constraints.Ordered などの制約を理解し、ジェネリックを効果的に活用することで、コードの品質と保守性を大幅に向上させることができます。

ジェネリックは進化し続けるため、Go のエコシステムで中心的な役割を果たすことになります。 Go プログラミングにおける型安全性と柔軟性の新時代を体験し、実験し、受け入れてください!

ジェネリックに関するいくつかのサンプルについては、github リポジトリをチェックアウトしてください。

GitHub logo サダナンドダワダカール / ゴージェネリクス

リポジトリには go ジェネリックの動作例が含まれています

Go Generics: 包括的なサンプル リポジトリ

Go ジェネリック リポジトリ へようこそ!このリポジトリは、バージョン 1.18 で導入された Go のジェネリックスを理解し、学習し、習得するためのワンストップ リソースです。ジェネリックは Go に型パラメーターの機能をもたらし、開発者がパフォーマンスや読みやすさを犠牲にすることなく、再利用可能で型安全なコードを作成できるようにします。

このリポジトリには、基本的な構文から高度なパターン、実用的な使用例まで、幅広いトピックをカバーする慎重に厳選された例が含まれています。初心者でも経験豊富な Go 開発者でも、このコレクションはプロジェクトでジェネリックを効果的に活用するのに役立ちます。


?中身は何ですか

?基本的な汎用プログラム

これらの例では、ジェネリックスの基本的な概念を紹介し、構文とコア機能を理解するのに役立ちます。

  1. GenericMap: 任意のタイプのスライスを変換する汎用マップ関数を示します。
  2. Swap: 2 つの値を一般的に交換する、シンプルかつ強力な例です。
  3. FilterSlice: フィルタリングする方法を示します…


GitHub で表示


以上がGo のジェネリックス: コードの再利用性を変革するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Golangの目的:効率的でスケーラブルなシステムの構築 Golangの目的:効率的でスケーラブルなシステムの構築 Apr 09, 2025 pm 05:17 PM

GO言語は、効率的でスケーラブルなシステムの構築においてうまく機能します。その利点には次のものがあります。1。高性能:マシンコードにコンパイルされ、速度速度が速い。 2。同時プログラミング:ゴルチンとチャネルを介してマルチタスクを簡素化します。 3。シンプルさ:簡潔な構文、学習コストとメンテナンスコストの削減。 4。クロスプラットフォーム:クロスプラットフォームのコンパイル、簡単な展開をサポートします。

Golang and C:Concurrency vs. Raw Speed Golang and C:Concurrency vs. Raw Speed Apr 21, 2025 am 12:16 AM

Golangは並行性がCよりも優れていますが、Cは生の速度ではGolangよりも優れています。 1)Golangは、GoroutineとChannelを通じて効率的な並行性を達成します。これは、多数の同時タスクの処理に適しています。 2)Cコンパイラの最適化と標準ライブラリを介して、極端な最適化を必要とするアプリケーションに適したハードウェアに近い高性能を提供します。

パフォーマンスレース:ゴラン対c パフォーマンスレース:ゴラン対c Apr 16, 2025 am 12:07 AM

GolangとCにはそれぞれパフォーマンス競争において独自の利点があります。1)Golangは、高い並行性と迅速な発展に適しており、2)Cはより高いパフォーマンスと微細な制御を提供します。選択は、プロジェクトの要件とチームテクノロジースタックに基づいている必要があります。

Golang vs. Python:パフォーマンスとスケーラビリティ Golang vs. Python:パフォーマンスとスケーラビリティ Apr 19, 2025 am 12:18 AM

Golangは、パフォーマンスとスケーラビリティの点でPythonよりも優れています。 1)Golangのコンピレーションタイプの特性と効率的な並行性モデルにより、高い並行性シナリオでうまく機能します。 2)Pythonは解釈された言語として、ゆっくりと実行されますが、Cythonなどのツールを介してパフォーマンスを最適化できます。

Golang vs. Python:重要な違​​いと類似点 Golang vs. Python:重要な違​​いと類似点 Apr 17, 2025 am 12:15 AM

GolangとPythonにはそれぞれ独自の利点があります。Golangは高性能と同時プログラミングに適していますが、PythonはデータサイエンスとWeb開発に適しています。 Golangは同時性モデルと効率的なパフォーマンスで知られていますが、Pythonは簡潔な構文とリッチライブラリエコシステムで知られています。

CとGolang:パフォーマンスが重要な場合 CとGolang:パフォーマンスが重要な場合 Apr 13, 2025 am 12:11 AM

Cは、ハードウェアリソースと高性能の最適化が必要なシナリオにより適していますが、Golangは迅速な開発と高い並行性処理が必要なシナリオにより適しています。 1.Cの利点は、ハードウェア特性と高い最適化機能に近いものにあります。これは、ゲーム開発などの高性能ニーズに適しています。 2.Golangの利点は、その簡潔な構文と自然な並行性サポートにあり、これは高い並行性サービス開発に適しています。

Golangの影響:速度、効率、シンプルさ Golangの影響:速度、効率、シンプルさ Apr 14, 2025 am 12:11 AM

speed、効率、およびシンプル性をspeedsped.1)speed:gocompilesquilesquicklyandrunseffictient、理想的なlargeprojects.2)効率:等系dribribraryreducesexexternaldedenciess、開発効果を高める3)シンプルさ:

GolangとC:パフォーマンスのトレードオフ GolangとC:パフォーマンスのトレードオフ Apr 17, 2025 am 12:18 AM

GolangとCのパフォーマンスの違いは、主にメモリ管理、コンピレーションの最適化、ランタイム効率に反映されています。 1)Golangのゴミ収集メカニズムは便利ですが、パフォーマンスに影響を与える可能性があります。

See all articles