7

次のコードから Go インターフェイスに関して 2 つの質問があります。

type Color interface {
    getColor() string
    setColor(string)
}

type Car struct {
    color string
}
func (c Car) getColor() string {
    return c.color
}
func (c Car) setColor(s string) {
    c.color = s
}

func main() {
    car := Car{"white"}
    col := Color(car)

    car = col.(Car)         // L(1)
    car.setColor("yellow")
    fmt.Println(col)        // L(2)
    fmt.Println(car)
    car.color = "black"
    fmt.Println(col)        // L(3)
    fmt.Println(car)
}

Q1: 書いてもいいですか?L(1) as "car, _ := col.(Car)"?

Q2: L(2)「黄色」ではなく「白」を印刷します。

それはなぜです?L(3)「黒」を正しく印刷しているようです。

ありがとう。

4

2 に答える 2

10

Q1:

いいえ、car,_ := col.(Car) とは言えません。この理由は明らかではありません。L1 の OK ステートメントのリストを次に示します。

car,ok := col.(Car)
car = col.(Car)
car,_ = col.(Car)
_,ok := col.(Car)

":=" は宣言/割り当ての省略形です。car はそのスコープで既に宣言されているため、:= を指定するとエラーが発生します (":=" の左側に新しい変数はありません)。そこに「ok」を入れると、新しい変数 (「ok」) が宣言されますが、アンダースコア/無視の疑似変数は、:= の目的では新しい変数としてカウントされません。

編集:明確にするために、型アサーションは型アサートされた値と、アサーションが成功したかどうかを示すブール値の両方を返すため、ここに「ok」またはアンダースコアを入れることができます。質問が実際に「_」の一般的なケースに関するものであり、「:=」演算子に関する質問ではない場合: いいえ、一般的なケースでは次のようなことはできません

a,_ := 5

そのステートメントは 1 つの値のみを返し、go では何も無視できないためです。(「割り当て数の不一致 2 = 1」というエラーが表示されます)。

Q2:

Go では、メソッドはポインターまたは値/基本型にある可能性があります。以下がうまくいくことがわかると思います:

car.setColor("yellow")
//...
func (car Car) setColor(s string) {
    car.color = s
    fmt.Println(car.color)
}

このコードでは、「黄色」を正しく出力します。これは、メソッドレシーバーをで渡しているためです。実際、それは車を変更しますが、渡した車とは別の車であり、たまたまメソッドを呼び出した車の完全なコピーである車です。これを修正するには、ポインターレシーバーが必要です。

func (car *Car) setColor(s string) {
    car.color = s
}

これにより、車が持つデータだけでなく、車が存在する場所をメソッドに与えるため、呼び出し後に変更が表示されます。徹底的に言うと、「参照型」(マップ、スライス、チャネル) が関係するケースがいくつかあります。これらのケースでは、ポインター以外のメソッドの外側で副作用が見られますが、これらは規則の例外です。

このメソッドにポインター レシーバーを指定すると、Car 型の変数はインターフェイス Color を実装しなくなることに注意してください。代わりに、インターフェイスを実装する型は *Car (Car へのポインター) です。実際、Go ではポインターは透過的であるため、これは getColor を非ポインター レシーバーに任せても当てはまりますが、通常は、ポインターまたは基本型のいずれかでインターフェイスを実装する型ですべてのメソッドを作成する方が適切です。両方の混合。

学習しているように見えるので、その他の注意事項が 1 つあります。setColor と getColor を小文字で開始しても、それ自体は何の問題もありません。ただし、これらのメソッドは、作成中のパッケージ以外では使用できないことに注意してください。それらを表示するには、大文字で始める必要があります。

于 2013-07-31T05:00:34.950 に答える
2

setColor が Car オブジェクトを変更するには、ポインターを渡す必要があると予想されます。コードは値で Car を渡し、その値の色を変更し、メソッドが返されたときに Car 値のコピーをすぐに破棄します。

インターフェイスが Car へのポインターによって満たされるように変更された例を次に示します。

func (c *Car) getColor() string {
    return c.color
}
func (c *Car) setColor(s string) {
    c.color = s
}

上記のリンクは次のように出力します。

&{yellow}
&{yellow}
&{black}
&{black}
于 2013-07-31T04:59:42.513 に答える