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 には以下の組み込み制約があります
- any: 任意の型を表します。これはインターフェースのエイリアスです。{}これは制約が必要ない場合に使用されます
func FunctionName[T TypeConstraint](parameterName T) ReturnType { // Function body using T }
- comparable: 等価比較 (== および !=) をサポートする型を許可します。マップキー、重複検出、または等価性チェックに役立ちます。これらの型は直接比較をサポートしていないため、これはマップ、スライス、関数には使用できません。
func Sum[T int | float64](a, b T) T { return a + b }
実験上の制約
- constraints.Complex: 複素数値型 (complex64 および complex128) を許可します。
- constraints.Float: float 数値型 (float32 および float64) を許可します
- constraints.Integer: 符号付きおよび符号なしの両方の整数を許可します (int8、int16、int32、int64、int、uint8、uint16、uint32、uint64、および uint)
- constraints.Signed: 任意の符号付き整数 (int8、int16、int32、int64、および int) を許可します
- constraints.Unsigned: 任意の符号なし整数 (uint8、uint16、uint32、uint64、および uint) を許可します。
- 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] <p><strong><em>Sum 関数</em></strong> は、int、int64、float64 パラメーターのみを使用して呼び出すことができます。</p> <h3> メソッド別の制約 </h3> <p>型に特定のメソッドを実装する必要がある場合は、それらのメソッドを使用して型を定義できます。<br> </p> <pre class="brush:php;toolbar:false">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] <pre class="brush:php;toolbar:false">type Numeric interface { int | float64 | uint }
結果の分析
実行時間:
汎用実装は、実行時の型アサーションを回避し、指定された型で直接動作するため、インターフェイス バージョンよりも約 63.64% 高速です。割り当て:
インターフェースのバージョンでは、主に値の挿入および取得時のボックス化/ボックス化解除により、3 倍多くの割り当てが行われます。{}これにより、ガベージ コレクションにオーバーヘッドが追加されます。
100 万回のエンキュー/デキュー操作など、より大きなワークロードの場合、パフォーマンスのギャップは拡大します。高スループット要件を持つ現実世界のアプリケーション (メッセージ キュー、ジョブ スケジューラなど) は、ジェネリックから大きな恩恵を受けます。
最終的な考え
Go のジェネリックスは、パワーとシンプルさのバランスをとり、再利用可能でタイプセーフなコードを作成するための実用的なソリューションを提供します。 Rust や C ほど機能が豊富ではありませんが、Go のミニマリスト哲学と完全に一致しています。 Constraints.Ordered などの制約を理解し、ジェネリックを効果的に活用することで、コードの品質と保守性を大幅に向上させることができます。
ジェネリックは進化し続けるため、Go のエコシステムで中心的な役割を果たすことになります。 Go プログラミングにおける型安全性と柔軟性の新時代を体験し、実験し、受け入れてください!
ジェネリックに関するいくつかのサンプルについては、github リポジトリをチェックアウトしてください。
サダナンドダワダカール
/
ゴージェネリクス
リポジトリには go ジェネリックの動作例が含まれています
Go Generics: 包括的なサンプル リポジトリ
Go ジェネリック リポジトリ へようこそ!このリポジトリは、バージョン 1.18 で導入された Go のジェネリックスを理解し、学習し、習得するためのワンストップ リソースです。ジェネリックは Go に型パラメーターの機能をもたらし、開発者がパフォーマンスや読みやすさを犠牲にすることなく、再利用可能で型安全なコードを作成できるようにします。
このリポジトリには、基本的な構文から高度なパターン、実用的な使用例まで、幅広いトピックをカバーする慎重に厳選された例が含まれています。初心者でも経験豊富な Go 開発者でも、このコレクションはプロジェクトでジェネリックを効果的に活用するのに役立ちます。
?中身は何ですか
?基本的な汎用プログラム
これらの例では、ジェネリックスの基本的な概念を紹介し、構文とコア機能を理解するのに役立ちます。
- GenericMap: 任意のタイプのスライスを変換する汎用マップ関数を示します。
- Swap: 2 つの値を一般的に交換する、シンプルかつ強力な例です。
- FilterSlice: フィルタリングする方法を示します…
以上がGo のジェネリックス: コードの再利用性を変革するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

この記事では、Goのパッケージインポートメカニズム:名前付きインポート(例:インポート "fmt&quot;)および空白のインポート(例:_&quot; fmt&quot;)について説明しています。 名前付きインポートはパッケージのコンテンツにアクセス可能になり、空白のインポートはtのみを実行します

この記事では、MySQLクエリの結果をGO structスライスに効率的に変換することを詳しく説明しています。 データベース/SQLのスキャン方法を使用して、手動で解析することを避けて強調しています。 DBタグとロブを使用した構造フィールドマッピングのベストプラクティス

この記事では、Webアプリケーションでのページ間データ転送のためのBeegoのnewflash()関数について説明します。 newflash()を使用して、コントローラー間で一時的なメッセージ(成功、エラー、警告)を表示し、セッションメカニズムを活用することに焦点を当てています。 リミア

この記事では、GENICSのGOのカスタムタイプの制約について説明します。 インターフェイスがジェネリック関数の最小タイプ要件をどのように定義するかを詳しく説明し、タイプの安全性とコードの再利用性を改善します。 この記事では、制限とベストプラクティスについても説明しています

この記事では、ユニットテストのためにGOのモックとスタブを作成することを示しています。 インターフェイスの使用を強調し、模擬実装の例を提供し、模擬フォーカスを維持し、アサーションライブラリを使用するなどのベストプラクティスについて説明します。 articl

この記事では、goで効率的なファイルの書き込みを詳しく説明し、os.writefile(小さなファイルに適している)とos.openfileおよびbuffered write(大規模ファイルに最適)と比較します。 延期エラー処理、Deferを使用し、特定のエラーをチェックすることを強調します。

この記事では、GOでユニットテストを書くことで、ベストプラクティス、モッキングテクニック、効率的なテスト管理のためのツールについて説明します。

この記事では、トレースツールを使用してGOアプリケーションの実行フローを分析します。 手動および自動計装技術について説明し、Jaeger、Zipkin、Opentelemetryなどのツールを比較し、効果的なデータの視覚化を強調しています


ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

Dreamweaver Mac版
ビジュアル Web 開発ツール

Safe Exam Browser
Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

SAP NetWeaver Server Adapter for Eclipse
Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

SublimeText3 英語版
推奨: Win バージョン、コードプロンプトをサポート!
