ประกาศชิ้นหรือทำชิ้น?


102

ใน Go ความแตกต่างระหว่างvar s []intและs := make([]int, 0)คืออะไร?

ฉันพบว่าทั้งสองได้ผล แต่อันไหนดีกว่ากัน?


อันแรกสร้างสnilไลซ์ในขณะที่อันที่สองสร้างสemptyไลซ์ (นี่คือคำศัพท์ที่ใช้ในหนังสือ "Go in action book" ) เพื่อหลีกเลี่ยงการโพสต์คำตอบเดียวกันที่นี่ด้วยคุณสามารถตรวจสอบstackoverflow.com/a/45997533/1561148
tgogos

คำตอบ:


96

นอกจากคำตอบของfabriziomแล้วคุณสามารถดูตัวอย่างเพิ่มเติมได้ที่ " Go Slices: การใช้งานและภายใน " ซึ่งกล่าวถึงการใช้งาน:[]int

เนื่องจากค่าศูนย์ของ slice ( nil) ทำหน้าที่เหมือนชิ้นส่วนที่มีความยาวเป็นศูนย์คุณสามารถประกาศตัวแปร slice แล้วผนวกเข้ากับมันในลูป:

// Filter returns a new slice holding only
// the elements of s that satisfy f()
func Filter(s []int, fn func(int) bool) []int {
    var p []int // == nil
    for _, v := range s {
        if fn(v) {
            p = append(p, v)
        }
    }
    return p
}

หมายความว่าหากต้องการผนวกเข้ากับชิ้นส่วนคุณไม่จำเป็นต้องจัดสรรหน่วยความจำก่อน: nilชิ้นส่วนp int[]นั้นเพียงพอสำหรับชิ้นส่วนที่จะเพิ่มเข้าไป


ทำไมคุณถึงคิดว่าจะจัดสรร? หมวกเป็นศูนย์ดังนั้นจึงไม่มีการจัดสรรโดยมีหรือไม่มียี่ห้อ
Arman Ordookhani

1
@ArmanOrdookhani เห็นด้วย ฉันพบว่าการประกาศนั้นvar p []intง่ายกว่าการใช้make(ซึ่งฉันเชื่อมโยงกับการจัดสรรมากกว่าแม้ว่าจะมีขีด จำกัด 0 แต่ก็จะไม่จัดสรรอะไรเลย) ในแง่ของความสามารถในการอ่านฉันไม่ต้องการใช้makeที่นี่
VonC

1
ฉันใช้ตัวอักษรมากขึ้นทุกที่ (เช่นp := []int{}) เนื่องจากโดยปกติแล้วเราจะใช้:=ไวยากรณ์เพื่อประกาศตัวแปรส่วนใหญ่จึงเป็นเรื่องธรรมดาที่จะมีทุกที่แทนที่จะมีข้อยกเว้นสำหรับชิ้นส่วน นอกเหนือจากนี้การพยายามคิดถึงการจัดสรรมักจะผลักดันให้ผู้คนไปสู่การเพิ่มประสิทธิภาพก่อนเวลาอันควร
Arman Ordookhani

116

ประกาศง่ายๆ

var s []int

ไม่จัดสรรหน่วยความจำและsชี้ไปnilในขณะที่

s := make([]int, 0)

จัดสรรหน่วยความจำและsชี้ไปยังหน่วยความจำให้กับชิ้นส่วนที่มี 0 องค์ประกอบ

โดยปกติอันแรกจะเป็นสำนวนมากกว่าหากคุณไม่ทราบขนาดที่แน่นอนของกรณีการใช้งานของคุณ


ฉันพูดเหมือนกันกับแผนที่ได้ไหม var m map [string] int vs m: = make (map [string] int)? ขอบคุณ.
joshua

11
ไม่คุณต้องทำmakeแผนที่เพราะแม้แต่พื้นที่ว่างก็ยังmapต้องการพื้นที่ว่างสำหรับการทำบัญชี
twotwotwo

11
หากคุณต้องการส่งคืนชิ้นงานที่มีองค์ประกอบ 0 (แทนที่จะเป็น 'nil') ให้เป็นการใช้งานที่ถูกต้อง
Jess

6
หากคุณกำลังสร้าง API และส่งคืนอาร์เรย์เป็นการตอบสนองการใช้รูปแบบการประกาศจะส่งคืนnilในกรณีที่ชิ้นส่วนของคุณไม่มีองค์ประกอบใด ๆ แทนที่จะเป็นอาร์เรย์ว่างเปล่า อย่างไรก็ตามหากmakeใช้เพื่อสร้างชิ้นส่วนอาร์เรย์ว่างจะถูกส่งกลับแทนซึ่งโดยทั่วไปแล้วจะเป็นเอฟเฟกต์ที่ต้องการ
robinmitra

6
ตามที่กล่าวไว้ในความคิดเห็นเกี่ยวกับคำตอบนี้: stackoverflow.com/a/29164565/1311538มีความแตกต่างเมื่อพยายามทำสิ่งต่างๆเช่น json marshaling Marshaling the nil slice ( var s []int) จะผลิตnullในขณะที่ marshaling the empty slice ( s := make([]int, 0)) จะให้ผลตามที่คาดหวัง[]
ขึ้น

8

เพิ่งพบความแตกต่าง ถ้าคุณใช้

var list []MyObjects

และจากนั้นคุณเข้ารหัสออกเป็น JSON nullคุณจะได้รับ

list := make([]MyObjects, 0)

ผลลัพธ์[]เป็นไปตามที่คาดไว้


ใช่อย่างหลังมีประโยชน์มากเมื่อเราต้องการตอบสนองด้วยอาร์เรย์ [] แทนที่จะเป็น null
Nhan Tran

4

สมบูรณ์มากขึ้นเล็กน้อย (อีกหนึ่งอาร์กิวเมนต์ในmake) ตัวอย่าง:

slice := make([]int, 2, 5)
fmt.Printf("length:  %d - capacity %d - content:  %d", len(slice), cap(slice), slice)

ออก:

length:  2 - capacity 5 - content:  [0 0]

หรือด้วยประเภทไดนามิกของslice:

slice := make([]interface{}, 2, 5)
fmt.Printf("length:  %d - capacity %d - content:  %d", len(slice), cap(slice), slice)

ออก:

length:  2 - capacity 5 - content:  [<nil> <nil>]

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