web-dev-qa-db-ja.com

「アドレスを取得できません」および「ポインタメソッドを呼び出せません」

これはコンパイルして動作します:

diff := projected.Minus(c.Origin)
dir := diff.Normalize()

これはしません(タイトルのエラーが発生します):

dir := projected.Minus(c.Origin).Normalize()

誰かが理由を理解するのを手伝ってくれる? (囲碁学習)

これらのメソッドは次のとおりです。

// Minus subtracts another vector from this one
func (a *Vector3) Minus(b Vector3) Vector3 {
    return Vector3{a.X - b.X, a.Y - b.Y, a.Z - b.Z}
}

// Normalize makes the vector of length 1
func (a *Vector3) Normalize() Vector3 {
    d := a.Length()
    return Vector3{a.X / d, a.Y / d, a.Z / d}
}
15
hunterloftis

Vector3.Normalize()メソッドにはpointerレシーバーがあるため、このメソッドを呼び出すには、_Vector3_値へのポインターが必要です(_*Vector3_)。最初の例では、Vector3.Minus()の戻り値を変数__Vector3_に格納します。

Goの変数はアドレス指定可能であり、diff.Normalize()を記述する場合、これはショートカットであり、コンパイラーはdiff変数のアドレスを自動的に取得して、タイプ_*Vector3_の必要なレシーバー値を順番に取得しますNormalize()を呼び出します。したがって、コンパイラはそれを次のように「変換」します

_(&diff).Normalize()
_

詳細は Spec:Calls: にあります

メソッドの呼び出しx.m()は、xメソッドセットmを含み、mのパラメーターリストに引数リストを割り当てることができる場合に有効です。 xaddressable であり、_&x_のメソッドセットにmが含まれている場合、x.m()は_(&x).m()_の省略形です。

2番目の例が機能しない理由は、関数とメソッドの呼び出しの戻り値がアドレス指定できないため、コンパイラーがここでも同じですが、コンパイラはVector3.Minus()呼び出しの戻り値のアドレスを取得できません。

アドレス指定可能なものは 仕様:アドレス演算子: に正確にリストされています

オペランドはaddressableでなければなりません。つまり、変数、ポインターの間接指定、またはスライスのインデックス付け操作のいずれかです。または、アドレス可能な構造体オペランドのフィールドセレクタ。または、アドレス可能な配列の配列インデックス操作。アドレス指定要件の例外として、x [_&x_の式の中の]も(括弧で囲まれている可能性があります) 複合リテラル です。

関連する質問を参照してください:

関数呼び出しから戻り値のポインタを取得する方法

操作の結果への参照をGoに保存するにはどうすればよいですか?

考えられる「回避策」

「最も簡単な」(変更が最も少ない)のは、単に変数に割り当て、その後にメソッドを呼び出すことです。これが最初の実用的なソリューションです。

もう1つの方法は、メソッドを変更して(ポインターレシーバーの代わりに)値レシーバーを持つことです。これにより、メソッドの戻り値のアドレスを取得する必要がなくなり、呼び出しを「連鎖」させることができます。メソッドがレシーバーを変更する必要がある場合、これは実行できない可能性があることに注意してください。これは、それがポインターである場合にのみ可能です(レシーバーは他のパラメーターと同じように-コピーを作成することによって渡されるため、それがポインターではない場合) 、コピーのみを変更できます)。

別の方法は、_*Vector3_ではなくポインタ(_Vector3_)を返すように戻り値を変更することです。戻り値が既にポインターである場合、ポインターレシーバーを必要とするメソッドへのレシーバーとしてはそのままなので、アドレスを取得する必要はありません。

また、アドレスを返す単純なヘルパー関数を作成することもできます。次のようになります。

_func pv(v Vector3) *Vector3 {
    return &v
}
_

それを使う:

_dir := pv(projected.Minus(c.Origin)).Normalize()
_

これは_Vector3_のメソッドである場合もあります。例:

_func (v Vector3) pv() *Vector3 {
    return &v
}
_

そしてそれを使う:

_dir := projected.Minus(c.Origin).pv().Normalize()
_

いくつかの注意事項:

タイプが3つの_float64_値のみで構成されている場合、パフォーマンスに大きな違いはありません。ただし、レシーバーと結果のタイプについて一貫している必要があります。ほとんどのメソッドにポインターレシーバーがある場合は、それらすべてにポインターレシーバーが必要です。ほとんどのメソッドがポインターを返す場合、すべてのポインターが返されます。

26
icza

受け入れられた答えは本当に長いので、私を助けたものを投稿します:

この行に関してこのエラーが発生しました:

services.HashingServices{}.Hash("blabla")

だから私はそれを次のように変更しました:

(&services.HashingServices{}).Hash("blabla")
0
VitalyGo877