ทำไมฉันไม่สามารถกำหนด * Struct ให้กับ * Interface ได้?


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และคุณไม่ต้องการประเภทของการประกาศตัวแปร (ดูคำถามที่เกี่ยวข้องนี้ )

ค่าอินเทอร์เฟซไม่ใช่ค่าของโครงสร้างคอนกรีต (เนื่องจากมีขนาดตัวแปรสิ่งนี้เป็นไปไม่ได้) แต่เป็นตัวชี้ชนิดหนึ่ง (เพื่อให้แม่นยำมากขึ้นตัวชี้ไปยังโครงสร้างและตัวชี้ไปยังประเภท ) Russ Cox อธิบายตรงนี้ :

ค่าอินเทอร์เฟซถูกแสดงเป็นคู่สองคำที่ให้ตัวชี้ไปยังข้อมูลเกี่ยวกับชนิดที่เก็บไว้ในอินเทอร์เฟซและตัวชี้ไปยังข้อมูลที่เกี่ยวข้อง

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือเหตุผลInterfaceและไม่*Interfaceเป็นชนิดที่ถูกต้องที่จะถือตัวชี้ไปยัง struct Interfaceที่ดำเนินการ

ดังนั้นคุณต้องใช้

var pi Interface

8
ตกลงฉันคิดว่ามันสมเหตุสมผลสำหรับฉัน ฉันแค่สงสัยว่าทำไม (ในกรณีนั้น) var pi *Interfaceมันไม่ได้เป็นเพียงแค่ข้อผิดพลาดรวบรวมเวลาที่จะพูด
Simon Nickerson

1
ฉันเข้าไปดูรายละเอียดเพิ่มเติมเพื่ออธิบาย ดูการแก้ไข ฉันขอแนะนำให้อ่านบทความของ Russ Cox ที่ฉันลิงก์ไป
Denys Séguret

1
สิ่งนี้ช่วยให้ฉันรู้สึกถึงพอยน์เตอร์ในแบบที่ฉันไม่สามารถทำได้ใน C หรือ C ++ ... ขอบคุณมากสำหรับคำอธิบายที่หรูหราและเรียบง่ายนี้ :-)
mindplay.dk

2
เอาล่ะฉันยังไม่เข้าใจว่าทำไม*SomeInterfaceไม่ใช่แค่ข้อผิดพลาดในการคอมไพล์?
sazary

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{}เป็นอาร์กิวเมนต์ แต่ฉันยังสามารถส่งตัวชี้โครงสร้างตามที่คุณเห็นด้านล่าง

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{}แต่การส่ง Im ในความเป็นจริงนั้นเป็นตัวชี้โครงสร้างและทำงานได้ดี

อีกตัวอย่างเพิ่มเติมที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.