[インデックス 191] ファイルの概要
コミット
more maps more semi-colons type assignment of constants
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c242b53d22aacbce0b78a2d0c977e2d92069cba5
元コミット内容
commit c242b53d22aacbce0b78a2d0c977e2d92069cba5
Author: Ken Thompson <ken@golang.org>
Date: Tue Jun 17 22:33:32 2008 -0700
more maps
more semi-colons
type assignment of constants
SVN=123278
---
src/cmd/gc/const.c | 12 +++++++++++-\n src/cmd/gc/go.h | 1 +\n src/cmd/gc/go.y | 45 ++++++++++++++++++++++++++-------------------\n src/cmd/gc/subr.c | 10 ++++++++++\n src/cmd/gc/walk.c | 15 ++++++++++++---\n 5 files changed, 60 insertions(+), 23 deletions(-)
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index 589066a9bb..9bd3e742ef 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -20,7 +20,17 @@ convlit(Node *n, Type *t)
\tgoto bad1;
case Wlitnil:
-\t\tif(isptr[et] || et = TINTER)
+\t\tif(isptr[et] || et == TINTER)
+\t\t\tbreak;
+\t\tgoto bad1;
+\n+\tcase Wlitstr:
+\t\tif(isptrto(t, TSTRING))
+\t\t\tbreak;
+\t\tgoto bad1;
+\n+\tcase Wlitbool:
+\t\tif(et == TBOOL)
\t\t\tbreak;
\t\tgoto bad1;
\ndiff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 0946b680b1..4e08bc5845 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -446,6 +446,7 @@ void\twarn(char*, ...);\n void\tfatal(char*, ...);\n void\tlinehist(char*, long);\n Node*\tnod(int, Node*, Node*);\n+Node*\tlist(Node*, Node*);\n Type*\ttyp(int);\n Dcl*\tdcl(void);\n Node*\trev(Node*);\ndiff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index c72900f808..c07d113d9b 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -30,7 +30,7 @@
%type\t<lint>\t\tchandir\n %type\t<node>\t\txdcl xdcl_list_r oxdcl_list common_dcl\n %type\t<node>\t\toarg_type_list arg_type_list_r arg_type\n-%type\t<node>\t\telse_stmt1 else_stmt2\n+%type\t<node>\t\telse_stmt1 else_stmt2 inc_stmt noninc_stmt\n %type\t<node>\t\tcomplex_stmt compound_stmt ostmt_list\n %type\t<node>\t\tstmt_list_r Astmt_list_r Bstmt_list_r\n %type\t<node>\t\tAstmt Bstmt Cstmt Dstmt
@@ -232,20 +232,14 @@ else_stmt2:
\t}\n \n simple_stmt:\n+\tinc_stmt\n+|\tnoninc_stmt\n+\n+noninc_stmt:\n \texpr\n \t{\n \t\t$$ = $1;\n \t}\n-|\texpr LINC
-\t{\n-\t\t$$ = nod(OASOP, $1, literal(1));\n-\t\t$$->etype = OADD;\n-\t}\n-|\texpr LDEC
-\t{\n-\t\t$$ = nod(OASOP, $1, literal(1));\n-\t\t$$->etype = OSUB;\n-\t}\n |\texpr LASOP expr
\t{\n \t\t$$ = nod(OASOP, $1, $3);\n@@ -264,6 +258,18 @@ simple_stmt:
\t\t$$ = nod(OAS, $1, $3);\n \t}\n \n+inc_stmt:\n+\texpr LINC\n+\t{\n+\t\t$$ = nod(OASOP, $1, literal(1));\n+\t\t$$->etype = OADD;\n+\t}\n+|\texpr LDEC\n+\t{\n+\t\t$$ = nod(OASOP, $1, literal(1));\n+\t\t$$->etype = OSUB;\n+\t}\n+\n complex_stmt:\n \tLFOR for_stmt
\t{\n@@ -1094,14 +1100,15 @@ Bstmt:\n * need semi in back YES\n */\n Cstmt:\n-\tsimple_stmt\n+\tnoninc_stmt\n \n /*\n * need semi in front YES\n * need semi in back NO\n */\n Dstmt:\n-\tnew_name \':\'\n+\tinc_stmt\n+|\tnew_name \':\'\n \t{\n \t\t$$ = nod(OLABEL, $1, N);\n \t}\n@@ -1114,15 +1121,15 @@ Astmt_list_r:\n |\tDstmt\n |\tAstmt_list_r Astmt\n \t{\n-\t\t$$ = nod(OLIST, $1, $2);\n+\t\t$$ = list($1, $2);\n \t}\n |\tAstmt_list_r Dstmt
\t{\n-\t\t$$ = nod(OLIST, $1, $2);\n+\t\t$$ = list($1, $2);\n \t}\n |\tBstmt_list_r Astmt
\t{\n-\t\t$$ = nod(OLIST, $1, $2);\n+\t\t$$ = list($1, $2);\n \t}\n \n /*\n@@ -1133,15 +1140,15 @@ Bstmt_list_r:\n |\tCstmt\n |\tAstmt_list_r Bstmt
\t{\n-\t\t$$ = nod(OLIST, $1, $2);\n+\t\t$$ = list($1, $2);\n \t}\n |\tAstmt_list_r Cstmt
\t{\n-\t\t$$ = nod(OLIST, $1, $2);\n+\t\t$$ = list($1, $2);\n \t}\n |\tBstmt_list_r Bstmt
\t{\n-\t\t$$ = nod(OLIST, $1, $2);\n+\t\t$$ = list($1, $2);\n \t}\n \n stmt_list_r:\ndiff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 1cd9f94718..499200521f 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -254,6 +254,16 @@ nod(int op, Node *nleft, Node *nright)
\treturn n;\n }\n \n+Node*\n+list(Node *a, Node *b)\n+{\n+\tif(a == N)\n+\t\treturn b;\n+\tif(b == N)\n+\t\treturn a;\n+\treturn nod(OLIST, a, b);\n+}\n+\n Type*\n typ(int et)\n {\ndiff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 16f0c2ce3e..56475b177b 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -12,8 +12,12 @@ static\tNode*\tcurfn;\n void\n walk(Node *fn)\n {\n+\tif(debug[\'W\'])\n+\t\tdump(\"fn-before\", fn->nbody);\n \tcurfn = fn;\n \twalktype(fn->nbody, Etop);\n+\tif(debug[\'W\'])\n+\t\tdump(\"fn\", fn->nbody);\n }\n \n void\n@@ -458,6 +462,9 @@ loop:\n \t\t\tgoto badt;\n \n \t\tcase TMAP:\n+\n+print(\"top=%d type %lT\", top, t);\n+dump(\"index\", n);\n \t\t\t// right side must map type\n \t\t\tif(n->right->type == T) {\n \t\t\t\tconvlit(n->right, t->down);\n@@ -470,6 +477,8 @@ loop:\n \t\t\t\tgoto badt;\n \t\t\tn->op = OINDEX;\n \t\t\tn->type = t->type;\n+\t\t\tif(top == Erv)\n+*n = *mapop(n, top);\n \t\t\tbreak;\n \n \t\tcase TSTRING:\n@@ -710,7 +719,6 @@ walkswitch(Node *sw, Type*(*call)(Node*, Type*))\n {\n \tNode *n, *c;\n \tType *place;\n-\n \tplace = call(sw->ntest, T);\n \n \tn = sw->nbody;\n@@ -1372,10 +1380,10 @@ mapop(Node *n, int top)\n \t\tr->type = n->type;\n \t\tbreak;\n \n-\tcase OINDEXPTR:\n+\tcase OINDEX:\n \t\tif(top != Erv)\n \t\t\tgoto nottop;\n-\n+dump(\"access start\", n);\n \t\t// mapaccess1(hmap *map[any]any, key any) (val any);\n \n \t\tt = fixmap(n->left->type);\n@@ -1408,6 +1416,7 @@ mapop(Node *n, int top)\n \t\tr = nod(OCALL, on, r);\n \t\twalktype(r, Erv);\n \t\tr->type = t->type;\n+dump(\"access finish\", r);\n \t\tbreak;\n \n \t\t// mapaccess2(hmap *map[any]any, key any) (val any, pres bool);\n```
## 変更の背景
このコミットは、Go言語の非常に初期の段階、具体的には2008年6月に行われたものです。当時のGo言語はまだ一般公開されておらず、Google社内で開発が進められていました。この時期のコミットは、言語の基本的な構文、セマンティクス、およびコンパイラの内部動作を確立するための重要な変更を含んでいます。
コミットメッセージにある「more maps」「more semi-colons」「type assignment of constants」という記述は、当時のGo言語が、マップ(ハッシュテーブル)、セミコロンの扱い、そして定数の型推論と型割り当てといった、言語の根幹をなす機能の設計と実装を洗練させていたことを示唆しています。
特に、`src/cmd/gc`はGo言語の初期のコンパイラであり、C言語で書かれていました。このコミットは、その`gc`コンパイラ内部でのこれらの機能の処理方法を改善することを目的としています。言語仕様が固まっていく過程で、コンパイラもそれに合わせて進化する必要があり、本コミットはその一環として、より堅牢で正確なコンパイルを実現するための調整が行われたと考えられます。
## 前提知識の解説
### Go言語の初期開発と`gc`コンパイラ
Go言語は2007年9月に設計が開始され、2008年1月にはコンパイラの初期作業が始まりました。このコミットが行われた2008年6月は、Go言語がまだプロトタイプ段階から実用的な言語へと移行する過渡期にありました。
`gc`は「Go compiler」の略であり、Go言語の標準コンパイラです。初期の`gc`コンパイラはC言語で書かれており、Go言語のソースコードを機械語に変換する役割を担っていました。Go 1.4以降で`gc`コンパイラ自体がGo言語で書き直されるまで、C言語版の`gc`がGo言語開発の基盤となっていました。このコミットは、そのC言語版`gc`の内部実装に対する変更です。
### Goのセミコロン自動挿入 (ASI: Automatic Semicolon Insertion)
Go言語の正式な文法ではセミコロンが文の終端記号として定義されています。しかし、Goには「セミコロン自動挿入 (ASI)」という特徴的なメカニズムがあります。これは、コンパイラが特定のルールに基づいて行末に自動的にセミコロンを挿入するため、Goプログラマは通常、コード中で明示的にセミコロンを記述する必要がありません。
ASIのルールは以下の通りです。
* 行の最後のトークンが識別子、リテラル(整数、浮動小数点数、虚数、ルーン、文字列など)、または`break`, `continue`, `fallthrough`, `return`といった特定のキーワードである場合。
* 行の最後のトークンが`++`, `--`, `)`, `]`, `}`といった特定の演算子や句読点である場合。
このコミットにおける「more semi-colons」という記述は、このASIメカニズムの解析ロジック、特に文の区切り方や、インクリメント/デクリメント演算子(`++`, `--`)のような特定の構文要素の扱いに関する改善を示唆しています。
### Goの定数と型推論
Go言語では、`const`キーワードを用いて文字、文字列、真偽値、数値の定数を宣言します。Goの定数の特徴の一つは、それらが「型なし (untyped)」であるという点です。これは、定数が特定の型に明示的に変換されるか、または特定の型を要求する文脈で使用されるまで、型を持たないことを意味します。例えば、`const pi = 3.14`と宣言された`pi`は、`float64`型として使用されるまで、特定の浮動小数点型を持ちません。
数値定数は任意精度を持つように設計されていますが、コンパイラの内部表現には限界があります。Goは定数の厳密な定義を強制し、固定されたリテラル値に限定し、構造体のような複雑な型での初期化を許可しません。これは、異なる数値型を混在させる際に他の言語で発生する一般的な問題を軽減するための意図的な設計決定でした。
このコミットにおける「type assignment of constants」は、コンパイラがこれらの型なし定数に適切な型を割り当てるロジック、特に異なるリテラル型(nil、文字列、真偽値)の扱いに関する改善を示唆しています。
### Goのマップ
Go言語のマップは、キーと値のペアを格納するための組み込みのハッシュテーブルです。マップは`make`関数で作成され、`map[KeyType]ValueType`という構文で宣言されます。初期のGo言語では、マップの実装はまだ成熟しておらず、効率性や正確性を向上させるための継続的な改善が行われていました。このコミットの「more maps」は、コンパイラがマップの操作(インデックスアクセス、代入など)をどのように処理するかに関する改善を指しています。
## 技術的詳細
このコミットは、Go言語のコンパイラ(`src/cmd/gc`)の複数のC言語ソースファイルにわたる変更を含んでおり、主に以下の3つの領域に焦点を当てています。
1. **定数の型割り当ての改善 (`src/cmd/gc/const.c`)**:
`convlit`関数は、リテラルノードを指定された型に変換する役割を担っています。このコミットでは、`Wlitnil`(nilリテラル)の型チェックに加えて、新たに`Wlitstr`(文字列リテラル)と`Wlitbool`(真偽値リテラル)のケースが追加されています。これにより、コンパイラが文字列リテラルが文字列型へのポインタに変換可能か、真偽値リテラルが真偽値型に変換可能かをより正確に判断できるようになりました。これは、Goの型なし定数が、使用される文脈に応じて適切な型を持つことを保証するための重要なステップです。
2. **文法解析とセミコロン処理の調整 (`src/cmd/gc/go.y`)**:
`go.y`はGo言語の文法定義ファイルであり、Yacc/Bisonによって解析器が生成されます。このファイルへの変更は、Goの構文解析ロジック、特にセミコロン自動挿入とインクリメント/デクリメント演算子(`++`, `--`)の扱いに関するものです。
* `simple_stmt`プロダクションが`inc_stmt`と`noninc_stmt`に分割されました。これにより、インクリメント/デクリメント演算子を含む文(`inc_stmt`)と、それ以外の単純な文(`noninc_stmt`)が明確に区別され、解析器がこれらの構文をより正確に処理できるようになります。
* `Cstmt`(セミコロンを後ろに必要とする文)が`noninc_stmt`を参照するように変更されました。
* `Dstmt`(セミコロンを前に必要とする文)に`inc_stmt`が追加されました。
* `Astmt_list_r`や`Bstmt_list_r`といった文のリストを構築する部分で、`nod(OLIST, $1, $2)`の代わりに新しい`list($1, $2)`関数が使用されるようになりました。これは、リスト構築のロジックを共通化し、より堅牢にするためのリファクタリングです。
3. **マップ操作の処理とデバッグ機能の追加 (`src/cmd/gc/walk.c`)**:
`walk.c`は、コンパイラの「ウォーク」フェーズ、つまり抽象構文木(AST)を走査し、型チェックやコード生成のための変換を行う部分です。
* `walk`関数にデバッグ用の`dump`呼び出しが追加されました(`debug['W']`が有効な場合)。これにより、ASTの変換前後の状態を視覚的に確認できるようになり、コンパイラのデバッグと開発が容易になります。
* `TMAP`(マップ型)の処理において、マップのインデックスアクセス(`OINDEX`)に関するロジックが変更されました。特に、`top == Erv`(式が右辺値として評価される場合)に`mapop`関数が呼び出されるようになりました。
* `mapop`関数内で、`OINDEXPTR`が`OINDEX`に変更され、マップアクセスに関するデバッグ情報(`dump("access start", n)`、`dump("access finish", r)`)が追加されました。これは、マップのインデックスアクセスがどのようにコンパイラによって処理され、最終的にマップアクセスヘルパー関数(`mapaccess1`など)に変換されるかを追跡するために役立ちます。
## コアとなるコードの変更箇所
このコミットでは、以下のファイルが変更されています。
* **`src/cmd/gc/const.c`**:
* `convlit`関数内で、`Wlitnil`の型チェックロジックが修正され、`Wlitstr`と`Wlitbool`のリテラル型に対する型割り当てロジックが追加されました。
* **`src/cmd/gc/go.h`**:
* `list`関数のプロトタイプ宣言が追加されました。
* **`src/cmd/gc/go.y`**:
* `simple_stmt`が`inc_stmt`と`noninc_stmt`に分割され、インクリメント/デクリメント演算子の解析ルールが変更されました。
* `Cstmt`と`Dstmt`の定義が更新され、新しい`inc_stmt`と`noninc_stmt`が使用されるようになりました。
* 文のリストを構築する際に、`nod(OLIST, ...)`の代わりに`list(...)`関数が使用されるように変更されました。
* **`src/cmd/gc/subr.c`**:
* `list`関数が新しく追加されました。この関数は、2つのノードを受け取り、それらを`OLIST`ノードとして結合するヘルパー関数です。
* **`src/cmd/gc/walk.c`**:
* `walk`関数にデバッグ用の`dump`呼び出しが追加されました。
* マップのインデックスアクセス(`TMAP`ケース)の処理において、`mapop`関数の呼び出しロジックが調整されました。
* `mapop`関数内で、`OINDEXPTR`が`OINDEX`に変更され、マップアクセスに関するデバッグ出力が追加されました。
## コアとなるコードの解説
### `src/cmd/gc/const.c`における定数型割り当て
`convlit`関数は、コンパイラがリテラル値の型を決定する際の中心的な役割を担います。この変更により、Goの型なし定数(特にnil、文字列、真偽値)が、その使用される文脈(例えば、ポインタ型、インターフェース型、文字列型、真偽値型への代入)に基づいて、より正確に型チェックされるようになりました。これにより、コンパイラは早期に型不一致のエラーを検出し、より堅牢なコード生成が可能になります。
### `src/cmd/gc/go.y`における文法解析の改善
`go.y`の変更は、Go言語の構文解析器の精度と柔軟性を向上させます。`simple_stmt`を`inc_stmt`と`noninc_stmt`に分割することで、インクリメント/デクリメント演算子(`++`, `--`)が他の単純な文とは異なる特別な扱いを受けることが明確になりました。これは、Goのセミコロン自動挿入のルールと密接に関連しており、これらの演算子が文の終端に現れる場合の解析を正確に行うために重要です。また、`list`関数の導入は、ASTノードのリスト構築をより統一的かつ効率的に行うためのリファクタリングであり、解析器の保守性を高めます。
### `src/cmd/gc/subr.c`における`list`関数の追加
新しく追加された`list`関数は、抽象構文木(AST)のノードを連結してリストを形成するためのユーティリティです。これは、`go.y`で複数の文や式をまとめて処理する際に頻繁に必要となる操作を抽象化し、コードの重複を減らし、可読性を向上させます。`nod(OLIST, a, b)`を直接呼び出す代わりに`list(a, b)`を使用することで、`a`または`b`が`N`(nilノード)である場合の特殊なケースを内部で処理し、より安全なリスト構築を保証します。
### `src/cmd/gc/walk.c`におけるマップ操作とデバッグ機能
`walk.c`の変更は、Goのマップ操作のコンパイル時処理を改善します。特に、マップのインデックスアクセス(`n[key]`のような操作)が、コンパイラの「ウォーク」フェーズでどのように抽象構文木から低レベルのランタイム関数呼び出し(`mapaccess1`など)に変換されるかを制御します。`OINDEXPTR`から`OINDEX`への変更は、マップインデックス操作の内部表現の洗練を示唆しています。また、追加された`print`や`dump`デバッグ呼び出しは、コンパイラ開発者がASTの変換過程やマップ操作の内部動作を詳細に追跡し、デバッグするための強力なツールとなります。これは、Goのマップ実装の正確性とパフォーマンスを確保するために不可欠な機能です。
## 関連リンク
* Go言語の公式ドキュメント: [https://go.dev/doc/](https://go.dev/doc/)
* Go言語の仕様: [https://go.dev/ref/spec](https://go.dev/ref/spec)
* Go言語の歴史に関する情報: [https://go.dev/blog/go-principles](https://go.dev/blog/go-principles)
## 参考にした情報源リンク
* medium.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHcHm3KaHcUAur7HMJBkpt_24J4suxyA_sh3WoQvVjOfefMRtsKSLyHahK_LzzgAuRRql4MtoIaE2n-csNpYNpcMlZ-MGum0hiCCAOnV02oaHFbD-VzaYWpYLNqgrnSgboVyvCG4DNOkUgbbxeNH9-nUmo4GfAyb4hNDm8RvglTYgUIrvw=)
* wikipedia.org (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQF4Oc2RnG1SSwWvJxylTdrSo4Y4_anmr5YU7jGRrOc2peUTSXIGjrNCC82YUouHFMIXmtGD6_jwU_ITB7Oh8gjhflRHvVH-5ESFKkbs8B5NpuU4Ramov-JTa6SG-mYV4Q5fqQ7hTESQy6Gdz0KNhJ-t2KE=)
* wikibooks.org (https://vertexaisearch.cloud.com/grounding-api-redirect/AUZIYQHicYQ8pAkU6ELkN3vwcSiZIAGXRHtjLh4Qmph5Ka-6xaxWZ1_ByxyK5tIqoLhZSSd8yAUcZ_X4bxxbxUBWg9RQsQte3ZbfbjwIN9Q3wC3VGQwvLOvWcAOFc1yTcvMYUcnPRLa7Vt7CooGcCveGam3zwiznts2copBy)
* go.dev (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHBOAlGDWMcM5oOSTNuy_tp4J5Kr5BEh-FwraEaiC1QpNUlC4a06GDLkK5cRZBD8r2njNmWwEfh9KB8PAB3QonpOTKMdnIe841wJxXWJBUnf7k=)
* tencentcloud.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFdLHuAcFVKnnW6AQbSQPKzVZ5vKXC0a1exLguJvgvhYHTT279jxGIFUkal_XxL5IanakY9dKAUiS9ug7uTBAiHpa1j9V78fIl9v8vLI5nb8hDGD66bvBoPdT2aoH1q9z41Se6Be1CL7g==)
* caffeinatedwonders.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEbfB9UbBKeTX7iOPftZtpkiquY39_K3KKJL0-4gAbuJefwIKTWhI6k21HueFx36JvIuPUWrhfIv4fuBjn50z0xiSrpN8km3griXlTQRCg2yv-WjYXKIYhEQ_PCqtvWY2YNSZQ9hoeTKowc0cA8uy5fSPkA8clRiLfgWY-OOo8=)
* go.dev (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEsTU1WnPYcaQSvZ7VVPJ4XpYDvCsueWtY0C9POoS9oV9tVi0Yi1ENhs3pvXE8PuSR_sIwY22nJYAIYGAioIbvk2cfYwCmKB4Xiottn4cxMX5nBiuR6oqhWS2kpDSS108U=)
* stackoverflow.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEWKkMs8QnjqlJpN8MyymfHz0xlOuL6IcBko06CVG1Y2OrBEyhCalUt2i4X1g-1beJ81mTSAHyLnyVOyXIRsD-eIj-VJbvR69-vMK7t7MmAGfwDema0k4umJBRypC-I553qBt3wNqdhgE2AisuIuUXcU31XjUh4_SCqpjsz9K4jqYVlkLOHS_PMkyufzDknodteztSKSufKRoRnnKesU=)
* go.dev (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHRvtTorNhBF0YlvLt4HHDbn09GDb4yMg-OiKDrgKFrFW-EBO6M1yPmbOkaY4HMTcWxFva-Ey8TNjy8hT7Ofl3GhxmvwOQOSKrz_iw6Oyig5KeB)
* boldlygo.tech (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFZSgkP0W6DsiO_Loe1SD1LkJwv6fU62LkT9ZhfBCqNTiCIT9Q4TE79UefVT4dF-vAvle63RcrLbHll7lpSI1i9xzqn1IoVWKWGRs9Hf7jrYeLS1zCgxj04P5V3c2C93J5_HFfvC9rJSiA5MIb8npwTbCvUrxOcK0OEB79G03IEsg==)
* reddit.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGsiwhVS6H0wMzthMX3AwwO7fZb5kWoQvz-03J0Z1smH0UGpIdxg8p3Wuqu7zKnRxvw1In4S1gWzQQB1xeshG68KJtw3Xi7kBrok1aJ_j8__rJf4zw6oUWkP17lnKhHMIoTs70oZndbqU8e6LdYs-6hchKlZRAhvy_2ZsOr1-Q5qJTWN70NLx9RRyfLLRQ)
* stackoverflow.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHg-BI-KgRNOkKuKmlAB2D9xkWz6eYgCOOzUKMVqWiVeHi7vDja543wfl2rgrYluJDrYPj5RNGqTCSwdSWhvqmBhFGM2kF5Iqaa1v5QLZv85Y_mDYrRP0uGD1ErY8SD_Kiqy_L2MPokMoK98iDNPO5hz8n_vI1XC0leei2sN0MHUZLH3eXz)
* go.dev (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHmJhUjoALRry427WXdVurttHLjgSWIilAGSCrt_VvcSAsqfYD1QH1_EjvAgCesi9Nb9xqAMRxzUikyzOzwJ_I_52Zs4xoA5lV1NR7eDzhsQHtlVd6gMx-J)
* gobyexample.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGq0I4B2Jb8E6opO6WV6kZDj_vYnxWOthnTbXJYl7j_mZor0zbq8n5IaW1_mjRmtdn6Nvw-QkDB8Y3YbrVd7kOHC4WaKVu2ivqTKKN44xuN0aY7WjSKv6RnP_COwQ==)
* go.dev (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQH4-VpwGQOU1metmkuv0cAVTTXYLGZrcAys-EpGSTMyR2544XcdazL-lsCQFWrRVZf-Z7ObVMQaJ0ZccR8T7VAm1L-pHE9zPkvUUhGFygaSvqQ2Y8b6Ln8FaQ==)
* ardanlabs.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGJOkQZacEm5F-z1tmixOQuPX982ctgO9VzvgV6USplFspiBL-TlWEAhA9CLqEvaLs8wnv-8VH-iARRSWnV56dN_KTKqSUTSwC3BMy8GlHLboTvyRtWaadqH3quM0_gCQDPi36qUFIdZVhwNf4eSABTsiAC-GqDtGmkec96IvKLsElb4FT3WDjI8lDLOrdN)
* medium.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGNgKuzEUz8gUQlwXg8bjvZa9uVMcZcdMccnEDobBpOsJNSYbmLuMiX-R3fzuqR54_SEdWyIQOBIKJS27DPY_Cvo_485vPmSKdI9GiSzAzrRrSRLGEqr1ugd1hmwiwASRMNiMnbWARqd1flao8n_V4YTFrOw4RQ53R8vBzdw-RVNnS8wh4vF6NkLTtDknodteztSKSufKRoRnnKesU=)
* medium.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGSqGjMMhH1ny3l9TeaH-Kw_t_TesBEo8dmb9DdXsP3pSe1pemrZRBtdGBDrP8NDfuXkBo_AoO2Br7198JcPVP4tdrYimHXktJsuS3t8h5HZo_FH-jKRaAgVFjcPEvyHoPjEO902FDX51-CApqV94_teE6QNitRybLJnzcYn0NF2iOVeJxHw2LI9z7_beCFOGkyCAHjs4tYP9sfzOAO6_8Xm8wEgA==)