Pair / tuple data type di Go

118

Saat melakukan latihan terakhir Tour of Go , saya memutuskan bahwa saya membutuhkan antrean ( string, int) pasangan. Cukup mudah:

type job struct {
    url string
    depth int
}

queue := make(chan job)
queue <- job{url, depth}

Tapi ini membuat saya berpikir: apakah ada tipe data berpasangan / tupel bawaan di Go? Ada dukungan untuk mengembalikan beberapa nilai dari suatu fungsi, tetapi AFAICT, tupel nilai berganda yang dihasilkan bukanlah warga kelas satu dalam sistem tipe Go. Apakah itu masalahnya?

Adapun bagian "apa yang telah Anda coba", sintaks yang jelas (dari POV programmer Python)

queue := make(chan (string, int))

tidak berhasil.

Fred Foo
sumber

Jawaban:

57

Tidak ada tipe tupel di Go, dan Anda benar, beberapa nilai yang dikembalikan oleh fungsi tidak mewakili objek kelas satu.

Jawaban Nick menunjukkan bagaimana Anda dapat melakukan hal serupa yang menangani tipe arbitrer menggunakan interface{}. (Saya mungkin telah menggunakan array daripada struct untuk membuatnya dapat diindeks seperti tupel, tetapi ide utamanya adalah interface{}tipenya)

Jawaban saya yang lain menunjukkan bagaimana Anda dapat melakukan sesuatu yang serupa yang menghindari membuat tipe menggunakan struct anonim.

Teknik-teknik ini memiliki beberapa sifat tupel, tetapi tidak, mereka bukan tupel.

Sonia
sumber
91

Kamu bisa melakukan ini. Ini terlihat lebih bertele-tele daripada tupel, tetapi ini merupakan peningkatan besar karena Anda mendapatkan pemeriksaan tipe.

Edit: Potongan yang diganti dengan contoh kerja lengkap, mengikuti saran Nick. Tautan Playground: http://play.golang.org/p/RNx_otTFpk

package main

import "fmt"

func main() {
    queue := make(chan struct {string; int})
    go sendPair(queue)
    pair := <-queue
    fmt.Println(pair.string, pair.int)
}

func sendPair(queue chan struct {string; int}) {
    queue <- struct {string; int}{"http:...", 3}
}

Struct dan field anonim bisa digunakan untuk solusi cepat dan kotor seperti ini. Untuk semua kecuali kasus yang paling sederhana, Anda sebaiknya mendefinisikan struct bernama seperti yang Anda lakukan.

Sonia
sumber
9
Anda mungkin harus menjelaskan cara mendapatkan nilai dari anggota struct anonim karena menurut saya itu tidak jelas bagi pemula!
Nick Craig-Wood
9
Namun, ini tidak akan berfungsi jika ada beberapa bidang dengan tipe yang sama
newacct
1
Anda dapat memiliki bidang bernama di struct anonim, Anda hanya perlu memastikan bahwa bidang diberi nama dengan cara yang sama di setiap tempat definisi struct anonim muncul (tiga kali dalam contoh ini.) Bidang anonim lebih mudah jika Anda bisa lolos begitu saja .
Sonia
5
Jadi jawabannya "tidak, tidak ada tipe tupel"?
Fred Foo
37

Anda bisa melakukan hal seperti ini jika Anda mau

package main

import "fmt"

type Pair struct {
    a, b interface{}
}

func main() {
    p1 := Pair{"finished", 42}
    p2 := Pair{6.1, "hello"}
    fmt.Println("p1=", p1, "p2=", p2)
    fmt.Println("p1.b", p1.b)
    // But to use the values you'll need a type assertion
    s := p1.a.(string) + " now"
    fmt.Println("p1.a", s)
}

Namun saya pikir apa yang Anda sudah benar-benar idiomatik dan struct menggambarkan data Anda dengan sempurna yang merupakan keuntungan besar dibandingkan menggunakan tupel biasa.

Nick Craig-Wood
sumber