Чому я не можу призначити * Struct інтерфейсу *?


142

Я просто працюю через гастрольний тур Go , і я плутаюся вказівників та інтерфейсів. Чому цей код не компілюється?

package main

type Interface interface {}

type Struct struct {}

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

    _, _ = pi, ps
}

тобто якщо Structє Interface, чому б не *Structбути *Interface?

Повідомлення про помилку, яке я отримую:

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

1
Дивіться також stackoverflow.com/q/20874798/260805
Ztyx

схоже, інтерфейси можуть поводитись як неявні покажчики ...
Віктор

Чи можу я запропонувати збагатити свій ігровий майданчик 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 }та зробити власні висновки
Віктор

Відповіді:


183

Коли у вас є структура, що реалізує інтерфейс, вказівник на цю структуру також автоматично реалізує цей інтерфейс. Ось чому ви ніколи не маєте *SomeInterfaceв прототипі функцій, оскільки це нічого не додасть SomeInterface, і вам не потрібен такий тип у змінному оголошенні (див. Це пов'язане питання ).

Значення інтерфейсу - це не значення конкретної структури (оскільки вона має змінний розмір, це було б неможливо), але це свого роду вказівник (точніше вказівник на структуру та вказівник на тип ). Расс Кокс описує це саме тут :

Значення інтерфейсу представлені у вигляді пари двох слів, що дає вказівник на інформацію про тип, що зберігається в інтерфейсі, та вказівник на пов’язані дані.

введіть тут опис зображення

Ось чому Interface, а не *Interfaceє правильним типом утримувати вказівник на реалізацію структури Interface.

Тому потрібно просто використовувати

var pi Interface

8
Гаразд, я думаю, що це має для мене сенс. Мені просто цікаво, чому (у такому випадку) сказати не просто помилка часу компіляції var pi *Interface.
Саймон Нікерсон

1
Я розібрався, щоб пояснити це. Див. Редагування. Я пропоную прочитати статтю Расса Кокса, на яку я посилаюся.
Denys Séguret

1
Це просто допомогло мені зрозуміти покажчики таким чином, що я ніколи не міг зробити на C або C ++ ... дуже дякую за це вишукане і просте пояснення :-)
mindplay.dk

2
Гаразд, я все ще не розумію, чому *SomeInterfaceне просто помилка компіляції?
сазарій

2
@charneykaye Ви тут не зовсім правильні. У вас ніколи не є * SomeInterface при оголошенні змінної інтерфейсу або при поверненні типу інтерфейсу як частини декларації функції . Однак у параметрах функції можна мати * SomeInterface .
arauter

7

Це, мабуть, те, що ви мали на увазі:

package main

type Interface interface{}

type Struct struct{}

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

        _, _ = pi, ps
}

Компілює ОК. Дивіться також тут .


Це слід прийняти, інший насправді не відповідає на питання.
DrKey


0

Я використовую наступний спосіб, interface{}поки я просто використовую eventsI interface{}в якості аргументів, я все ще в змозі надіслати покажчики Struct, як ви можете бачити нижче.

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

main.go

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

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

Тепер всередині storyboard.goфайла Створити функцію

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
}

Як ви бачите вище, Storyboard.go споживає справедливе, Events []interface{}але фактично надсилання ім я - покажчик Struct, і він працює добре.

ще один приклад тут

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.