10

iPerson以下のコード スニペットでは、コンテンツがまだ初期化されていないときに正確に格納されるものを理解したいと思います: 0 バイトの値だけですか? それとも、実際にはボンネットの下のポインターですか (もちろん、0 バイトに初期化されています)? いずれにせよ、で正確に何が起こるのiPerson = personですか?

iPerson = personのコピーを作成する場合person、実装しているがサイズ/メモリ フットプリントが異なるオブジェクトIPersonが に割り当てられるとどうなりiPersonますか? iPersonはスタックに格納される変数であることを理解しているため、そのサイズは固定する必要があります。つまり、ヒープは実際には内部で使用されているため、iPerson実際にはポインターとして実装されていますが、上記のコードで示されているように、割り当てはオブジェクトをコピーしますか? コードは次のとおりです。

type Person struct{ name string }

type IPerson interface{}

func main() {
    var person Person = Person{"John"}
    var iPerson IPerson
    fmt.Println(person)  // => John
    fmt.Println(iPerson) // => <nil>  ...so looks like a pointer

    iPerson = person     //           ...this seems to be making a copy
    fmt.Println(iPerson) // => John

    person.name = "Mike"
    fmt.Println(person)  // => Mike
    fmt.Println(iPerson) // => John   ...so looks like it wasn't a pointer,
                         //           or at least something was definitely copied
}

(この質問は、なぜ io.WriterString で実行時エラーが発生するのかに対する私の回答の正確な事実の正確性について考え直した結果です。そのため、インターフェース変数と割り当てが正確にどのようになっているのかを理解するために、いくつかの調査を試みることにしました。それらは Go で動作します。)

編集:いくつかの有用な回答を受け取った後、私はまだこれに戸惑っています:

iPerson = person
iPerson = &person

— どちらも合法です。しかし、私には、なぜコンパイラがそのような弱い型付けを許してしまうのかという疑問が生じます。上記の 1 つの意味は次のとおりです。

iPerson = &person
var person2 = iPerson.(Person)  # panic: interface conversion: interface is *main.Person, not main.Person

一方、最初の行を変更すると修正されます。

iPerson = person
var person2 = iPerson.(Person)  # OK

iPerson...したがって、ポインタまたは値のどちらを保持しているかを静的に判断することはできません。エラーが発生することなく、実行時にどちらかを割り当てることができるようです。なぜそのような設計決定が下されたのですか?それはどのような目的に役立ちますか?「タイプセーフ」の考え方には絶対に適合しません。

4

3 に答える 3

7

あなたはなぜ両方の理由を尋ねます

iPerson = person
iPerson = &person

許可されています。person と &person の両方が IPerson インターフェイスを実装しているため、両方とも許可されます。IPerson は空のインターフェイスであり、すべての値がそれを実装しているため、これは明らかです。

IPerson の値がポインターまたは値のどちらを保持しているかを静的に判断できないことは事実です。だから何?IPerson について知っていることは、その型の値に格納されたオブジェクトはすべて、インターフェイスのメソッドのリストを実装するということだけです。これらのメソッドが正しく実装されていることを前提としています。IPerson が値を保持するかポインターを保持するかは、それとは関係ありません。

たとえば、メソッドがオブジェクトに格納されているものを変更することになっている場合、そのメソッドはほとんどポインター メソッドである必要があります。この場合、ポインター値のみをインターフェイス型の変数に格納できます。ただし、どのメソッドもオブジェクトに格納されているものを変更しない場合、それらはすべて値メソッドである可能性があり、ポインター以外の値を変数に格納できます。

于 2013-10-07T19:47:06.793 に答える
5

次の行を実行すると:

iPerson = person

Personインターフェイス変数に値を格納しています。構造体への割り当てはコピーを実行するので、はい、あなたのコードはコピーを取ります。インターフェイス内から構造体を取得するには、別のコピーを取得する必要があります。

p := iPerson.(Person)

したがって、可変型でこれを行うことはめったにありません。代わりに、構造体へのポインターをインターフェイス変数に格納する場合は、これを明示的に行う必要があります。

iPerson = &person

ボンネットの下で何が起こっているかについては、インターフェース変数がポインターよりも大きな値を格納するためにヒープ領域を割り当てることは正しいですが、これは通常、ユーザーには表示されません。

于 2013-10-07T11:25:49.117 に答える