Tại sao tôi có thể nhập các hàm bí danh và sử dụng chúng mà không cần truyền?


97

Trong Go, nếu bạn xác định một kiểu mới, ví dụ:

type MyInt int

Sau đó, bạn không thể chuyển một hàm MyIntcho một hàm mong đợi một số nguyên, hoặc ngược lại:

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

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

Khỏe. Nhưng tại sao điều tương tự không áp dụng cho các hàm? ví dụ:

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
}

Bây giờ, tôi không phàn nàn vì nó giúp tôi không phải ép kiểu rõ ràng newfuncđể nhập MyFunc, như tôi sẽ phải làm trong ví dụ đầu tiên; nó chỉ có vẻ không nhất quán. Tôi chắc rằng có một lý do chính đáng cho nó; bất cứ ai có thể khai sáng cho tôi?

Lý do tôi hỏi chủ yếu là vì tôi muốn rút ngắn một số loại hàm khá dài của mình theo cách này, nhưng tôi muốn đảm bảo rằng nó được mong đợi và chấp nhận được để làm điều này :)


typekhá hữu ích trong cờ vây hơn là Scala. Scala chỉ có bí danh loại, than ôi.
Rick-777,

4
Go bây giờ thực sự có loại bí danh github.com/golang/go/issues/18130
Hut8

ai đó có thể giải thích đoạn mã thứ hai không? Tôi thực sự không thể nhận được các khai báo hàm đó
DevX

Câu trả lời:


148

Hóa ra, đây là một hiểu lầm mà tôi đã có về cách Go xử lý các loại, có thể được giải quyết bằng cách đọc phần liên quan của thông số kỹ thuật:

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

Sự khác biệt có liên quan mà tôi không biết là loại có tênkhông tên .

Kiểu được đặt tên là kiểu có tên, chẳng hạn như int, int64, float, string, bool. Ngoài ra, bất kỳ kiểu nào bạn tạo bằng cách sử dụng 'type' đều là kiểu được đặt tên.

Các kiểu không được đặt tên là những kiểu như chuỗi [], chuỗi [chuỗi] bản đồ, [4] int. Chúng không có tên, chỉ đơn giản là một mô tả tương ứng với cách chúng được cấu trúc.

Nếu bạn so sánh hai loại được đặt tên, các tên phải khớp để chúng có thể hoán đổi cho nhau. Nếu bạn so sánh một loại được đặt tên và một loại không có tên, thì miễn là đại diện bên dưới khớp với nhau , thì bạn đã sẵn sàng!

Ví dụ: đưa ra các loại sau:

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

cái sau không hợp lệ:

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

sau đây là tốt:

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)

Tôi hơi buồn vì tôi đã không biết điều đó sớm hơn, vì vậy tôi hy vọng rằng điều đó sẽ làm sáng tỏ loại chỉ trích một chút cho người khác! Và có nghĩa là ít đúc hơn tôi nghĩ lúc đầu :)


1
Bạn cũng có thể sử dụng is := make(MySlice, 0); m := make(MyMap), dễ đọc hơn trong một số ngữ cảnh.
R2B2

13

Cả câu hỏi và câu trả lời đều khá thú vị. Tuy nhiên, tôi muốn đưa ra một sự khác biệt không rõ ràng trong câu trả lời của lytnus.

  • Loại có tên khác với Loại không tên .

  • Biến của Loại có tên có thể được gán cho biến của Loại không được đặt tên , ngược lại.

  • Không thể gán các biến của Loại được đặt tên khác nhau .

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
}
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.