เหตุใดฉันจึงพิมพ์ฟังก์ชันนามแฝงและใช้งานได้โดยไม่ต้องแคสต์


98

ใน Go หากคุณกำหนดประเภทใหม่เช่น:

type MyInt int

จากนั้นคุณไม่สามารถส่งผ่านMyIntไปยังฟังก์ชันที่คาดหวังว่าจะเป็น int หรือในทางกลับกัน:

func test(i MyInt) {
    //do something with i
}

func main() {
    anInt := 0
    test(anInt) //doesn't work, int is not of type MyInt
}

ละเอียด. แต่เหตุใดจึงใช้ฟังก์ชันเดียวกันนี้ไม่ได้ เช่น:

type MyFunc func(i int)
func (m MyFunc) Run(i int) {
    m(i)
}

func run(f MyFunc, i int) {
    f.Run(i)
}

func main() {
    var newfunc func(int) //explicit declaration
    newfunc = func(i int) {
        fmt.Println(i)
    }
    run(newfunc, 10) //works just fine, even though types seem to differ
}

ตอนนี้ฉันไม่ได้บ่นเพราะมันช่วยให้ฉันไม่ต้องแคสต์อย่างชัดเจนnewfuncเพื่อพิมพ์MyFuncอย่างที่ฉันต้องทำในตัวอย่างแรก ดูเหมือนว่าไม่สอดคล้องกัน ฉันแน่ใจว่ามีเหตุผลที่ดีสำหรับมัน ใครช่วยสอนฉันได้ไหม

เหตุผลที่ฉันถามส่วนใหญ่เป็นเพราะฉันต้องการย่อประเภทฟังก์ชันที่ค่อนข้างยาวของฉันให้สั้นลงด้วยวิธีนี้ แต่ฉันต้องการให้แน่ใจว่ามันคาดหวังและยอมรับได้ในการทำสิ่งนี้ :)


typeค่อนข้างมีประโยชน์ใน Go มากกว่า Scala Scala เพียงมีนามแฝงประเภทอนิจจา
Rick-777

4
Go now มีนามแฝงประเภทgithub.com/golang/go/issues/18130
Hut8

ใครช่วยอธิบายข้อมูลโค้ดที่สองได้ไหม ฉันไม่สามารถรับการประกาศฟังก์ชันเหล่านั้นได้จริง ๆ
DevX

คำตอบ:


150

ปรากฎว่านี่เป็นความเข้าใจผิดที่ฉันมีเกี่ยวกับวิธีที่ Go จัดการกับประเภทซึ่งสามารถแก้ไขได้โดยอ่านส่วนที่เกี่ยวข้องของข้อมูลจำเพาะ:

http://golang.org/ref/spec#Type_identity

ความแตกต่างที่เกี่ยวข้องที่ผมก็ไม่รู้เป็นที่ของชื่อและชื่อประเภท

ประเภทที่มีชื่อคือประเภทที่มีชื่อเช่น int, int64, float, string, bool นอกจากนี้ประเภทใด ๆ ที่คุณสร้างโดยใช้ "ประเภท" คือประเภทที่มีชื่อ

ประเภทที่ไม่มีชื่อได้แก่ [] string, map [string] string, [4] int พวกเขาไม่มีชื่อเป็นเพียงคำอธิบายที่สอดคล้องกับวิธีการจัดโครงสร้าง

หากคุณเปรียบเทียบสองประเภทที่มีชื่อชื่อจะต้องตรงกันเพื่อให้สามารถใช้แทนกันได้ หากคุณเปรียบเทียบประเภทที่มีชื่อและไม่มีชื่อตราบใดที่การแสดงที่เป็นตัวแทนตรงกันคุณก็พร้อมที่จะไป!

เช่นกำหนดประเภทต่อไปนี้:

type MyInt int
type MyMap map[int]int
type MySlice []int
type MyFunc func(int)

ต่อไปนี้ไม่ถูกต้อง:

var i int = 2
var i2 MyInt = 4
i = i2 //both named (int and MyInt) and names don't match, so invalid

ต่อไปนี้เป็นเรื่องปกติ:

is := make([]int)
m := make(map[int]int)
f := func(i int){}

//OK: comparing named and unnamed type, and underlying representation
//is the same:
func doSlice(input MySlice){...}
doSlice(is)

func doMap(input MyMap){...}
doMap(m)

func doFunc(input MyFunc){...}
doFunc(f)

ฉันรู้สึกเสียใจเล็กน้อยที่ไม่รู้ว่าเร็วกว่านั้นดังนั้นฉันหวังว่าจะชี้แจงประเภทที่สนุกสนานสำหรับคนอื่น! และหมายถึงความหล่อน้อยกว่าที่คิดไว้ตอนแรกมาก :)


1
คุณยังสามารถใช้is := make(MySlice, 0); m := make(MyMap)ซึ่งสามารถอ่านได้มากขึ้นในบางบริบท
R2B2

13

ทั้งคำถามและคำตอบค่อนข้างให้ความกระจ่าง อย่างไรก็ตามฉันต้องการนำเสนอความแตกต่างซึ่งไม่ชัดเจนในคำตอบของ Lytnus

  • ตั้งชื่อประเภทจะแตกต่างจากชื่อประเภท

  • Variable of Named Typeสามารถกำหนดให้กับตัวแปรของUnnamed Typeได้ในทางกลับกัน

  • ตัวแปรของประเภทชื่อที่แตกต่างกันไม่สามารถกำหนดให้กันได้

http://play.golang.org/p/uaYHEnofT9

import (
    "fmt"
    "reflect"
)

type T1 []string
type T2 []string

func main() {
    foo0 := []string{}
    foo1 := T1{}
    foo2 := T2{}
    fmt.Println(reflect.TypeOf(foo0))
    fmt.Println(reflect.TypeOf(foo1))
    fmt.Println(reflect.TypeOf(foo2))

    // Output:
    // []string
    // main.T1
    // main.T2

    // foo0 can be assigned to foo1, vice versa
    foo1 = foo0
    foo0 = foo1

    // foo2 cannot be assigned to foo1
    // prog.go:28: cannot use foo2 (type T2) as type T1 in assignment
    // foo1 = foo2
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.