Tại sao tôi không thể gán * Struct cho Giao diện *?


142

Tôi chỉ đang làm việc thông qua chuyến tham quan Go và tôi bối rối về các con trỏ và giao diện. Tại sao mã này không được biên dịch?

package main

type Interface interface {}

type Struct struct {}

func main() {
    var ps *Struct
    var pi *Interface
    pi = ps

    _, _ = pi, ps
}

tức là nếu Structlà một Interface, tại sao không phải *Structlà một *Interface?

Thông báo lỗi tôi nhận được là:

prog.go:10: cannot use ps (type *Struct) as type *Interface in assignment:
        *Interface is pointer to interface, not interface


có vẻ như các giao diện có thể hoạt động giống như con trỏ ngầm ...
Victor

tôi có thể đề nghị làm phong phú sân chơi của bạn với func main() { var ps *Struct = new(Struct) var pi *Interface var i Interface i = ps pi = &i fmt.Printf("%v, %v, %v\n", *ps, pi, &i) i = *ps fmt.Printf("%v, %v, %v\n", *ps, pi, i) _, _, _ = i, pi, ps }và đưa ra những kết luận của riêng bạn không
Victor

Câu trả lời:


183

Khi bạn có một cấu trúc thực hiện một giao diện, một con trỏ tới cấu trúc đó cũng tự động thực hiện giao diện đó. Đó là lý do tại sao bạn không bao giờ có *SomeInterfacetrong nguyên mẫu của các hàm, vì điều này sẽ không thêm bất cứ thứ gì vào SomeInterfacevà bạn không cần một kiểu khai báo biến như vậy (xem câu hỏi liên quan này ).

Giá trị giao diện không phải là giá trị của cấu trúc cụ thể (vì nó có kích thước thay đổi, điều này sẽ không thể thực hiện được), nhưng đó là một loại con trỏ (chính xác hơn là một con trỏ tới cấu trúc và một con trỏ tới loại ). Russ Cox mô tả chính xác ở đây :

Các giá trị giao diện được biểu diễn dưới dạng một cặp hai từ cung cấp một con trỏ tới thông tin về loại được lưu trữ trong giao diện và một con trỏ tới dữ liệu liên quan.

nhập mô tả hình ảnh ở đây

Đây là lý do tại sao Interface, và không phải *Interfacelà loại chính xác để giữ một con trỏ đến một cấu trúc thực hiện Interface.

Vì vậy, bạn chỉ cần sử dụng

var pi Interface

8
OK, tôi nghĩ rằng nó có ý nghĩa với tôi. Tôi chỉ tự hỏi tại sao (trong trường hợp đó), nó không chỉ đơn giản là một lỗi thời gian biên dịch var pi *Interface.
Simon Nickerson

1
Tôi đã đi vào chi tiết hơn để giải thích nó. Xem chỉnh sửa. Tôi đề nghị đọc bài viết của Russ Cox mà tôi liên kết đến.
Denys Séguret

1
Điều này chỉ giúp tôi có ý nghĩa của con trỏ trong một cách mà tôi đã không bao giờ có thể làm trong C hoặc C ++ ... cảm ơn bạn rất nhiều vì đã giải thích thanh lịch và đơn giản này :-)
mindplay.dk

2
Được rồi, tôi vẫn không hiểu tại sao *SomeInterfacekhông đơn giản là một lỗi biên dịch?
sazary

2
@charneykaye Bạn không hoàn toàn chính xác ở đây. Bạn không bao giờ có * Một số mặt khi khai báo một biến giao diện hoặc khi trả về một loại giao diện như là một phần của khai báo hàm . Tuy nhiên, bạn có thể có * Một số mặt trong các tham số của hàm .
arauter

7

Đây có lẽ là những gì bạn có nghĩa là:

package main

type Interface interface{}

type Struct struct{}

func main() {
        var ps *Struct
        var pi *Interface
        pi = new(Interface)
        *pi = ps

        _, _ = pi, ps
}

Biên dịch OK. Xem thêm tại đây .


Điều này nên được chấp nhận, người kia không thực sự trả lời câu hỏi.
DrKey

0

Đây là một cách rất đơn giản để gán một cấu trúc cho một giao diện:

package main

type Interface interface{}

type Struct struct{}

func main() {
    ps := new(Struct)
    pi := Interface(ps)

    _, _ = pi, ps
}

https://play.golang.org/p/BRTaTA5AG0S


0

Tôi đang sử dụng cách sau đây interface{}trong khi tôi chỉ sử dụng eventsI interface{}làm đối số, tôi vẫn có thể gửi Con trỏ cấu trúc như bạn có thể thấy bên dưới.

func Wait(seconds float64) *WaitEvent {
    return WaitEventCreate(seconds)
}

chính

var introScene = []interface{}{
        storyboard.Wait(5),
        storyboard.Wait(2),
    }

    var storyboardI = storyboard.Create(stack, introScene)
    stack.Push(&storyboardI)

Bây giờ bên trong storyboard.gotập tin Tạo chức năng

type Storyboard struct {
    Stack  *gui.StateStack
    Events []interface{} //always keep as last args
}

func Create(stack *gui.StateStack, eventsI interface{}) Storyboard {
    sb := Storyboard{
        Stack: stack,
    }

    if eventsI != nil {
        events := reflect.ValueOf(eventsI)
        if events.Len() > 0 {
            sb.Events = make([]interface{}, events.Len())
            for i := 0; i < events.Len(); i++ {
                sb.Events[i] = events.Index(i).Interface()
            }
        }
    }

    return sb
}

Như bạn có thể thấy ở trên Storyboard.go chỉ tiêu thụ Events []interface{}nhưng thực tế tôi đang gửi là một con trỏ Struct và nó hoạt động tốt.

một ví dụ khác ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.