int และ int64 ใน Go ต่างกันอย่างไร


86

ฉันมีสตริงที่มีจำนวนเต็ม (ซึ่งอ่านจากไฟล์)

ฉันกำลังพยายามแปลงstringเป็นการintใช้strconv.ParseInt(). ParseIntต้องการให้ฉันระบุขนาดบิต (ขนาดบิต 0, 8, 16, 32 และ 64 สอดคล้องกับ int, int8, int16, int32 และ int64)

จำนวนเต็มที่อ่านจากไฟล์มีขนาดเล็ก (เช่นควรพอดีกับ int ปกติ) อย่างไรก็ตามถ้าฉันส่งบิตขนาดเป็น 0 ฉันจะได้ผลลัพธ์เป็นประเภทint64(น่าจะเป็นเพราะฉันใช้ระบบปฏิบัติการ 64 บิต)

เหตุใดจึงเกิดขึ้น ฉันจะรับ int ปกติได้อย่างไร (ถ้ามีคนลงไพรเมอร์ด่วนเมื่อไหร่และทำไมฉันควรใช้ int ประเภทต่างๆนั่นจะยอดเยี่ยมมาก!)

แก้ไข: ฉันสามารถแปลง int64 เป็น int ปกติโดยใช้int([i64_var])ไฟล์. แต่ฉันยังไม่เข้าใจว่าทำไมถึงParseInt()ให้ int64 กับฉันเมื่อฉันขอบิตขนาดเป็น 0


2
ใช้Atoiเพื่อความกะทัดรัด? นอกจากนี้ฟังก์ชัน ParseInt ของคุณส่งคืนข้อผิดพลาดหรือไม่
แมท

2
เอาล่ะตอนนี้ฉันสับสนเล็กน้อย ถ้าฉันใช้ Atoi () มันจะให้ int และทุกอย่างก็ใช้ได้ ฉันกำลังโทรparseInt(s, 0, 0)ซึ่งควรอนุมาน base10 (เนื่องจากสตริงไม่มีคำนำหน้าฐาน) อย่างไรก็ตาม Atoi เป็นชวเลขสำหรับการเรียกโดยparseIntมีฐานเป็น 10 เหตุใดพารามิเตอร์พื้นฐานจึงสร้างความแตกต่างในประเภทที่ส่งคืน
Isaac Dontje Lindell

พารามิเตอร์พื้นฐานกำหนดวิธีการอ่านสตริงอินพุต สตริงอาจมีลักษณะเป็น "123" หรือ "0xBEEFCAKE" หรือ "1011101" หรือ "0677" ทั้งหมดนี้มีความหมายแตกต่างกันและให้ค่าตัวเลขที่แตกต่างกัน ค่าฐานของ0วิธีการที่รหัสพยายามคิดออกด้วยตัวเอง แต่บางครั้งก็ไม่สามารถทำได้ 11(ทศนิยม) เทียบกับ11(ไบนารี) แทนค่าที่แตกต่างกันอย่างสิ้นเชิง
jimt

1
โอเคฉันเดาว่าสิ่งที่ฉันสับสนจริงๆคือเอกสาร เอกสารของ Atoi บอกเพียงว่าเป็นเพียง "ชวเลขสำหรับparseInt(s, 10, 0)" เท่านั้น แต่ทำไม Atoi ถึงกลับมาintในขณะที่parseIntกลับ int64?
Isaac Dontje Lindell

1
ไม่ทราบว่าทำไมฉันจะคิดว่าAtoiมันถูกเพิ่มเข้ามาเพื่อรองรับผู้ที่คุ้นเคยกับ C API มากขึ้น:int atoi ( const char * str );
jimt

คำตอบ:


56
func ParseInt(s string, base int, bitSize int) (i int64, err error)

ParseInt ส่งกลับเสมอ int64

bitSizeกำหนดช่วงของค่า ถ้าค่าที่สอดคล้องกับ s ไม่สามารถแสดงด้วยจำนวนเต็มที่มีลายเซ็นของขนาดที่กำหนดให้ err.Err = ErrRange

http://golang.org/pkg/strconv/#ParseInt

type int int

int เป็นประเภทจำนวนเต็มที่มีการเซ็นชื่อซึ่งมีขนาดอย่างน้อย 32 บิต อย่างไรก็ตามเป็นประเภทที่แตกต่างกันและไม่ใช่นามแฝงสำหรับพูด int32

http://golang.org/pkg/builtin/#int

ดังนั้นintอาจใหญ่กว่า 32 บิตในอนาคตหรือในบางระบบเช่นintใน C.

ฉันเดาว่าในบางระบบint64อาจเร็วกว่าint32เพราะระบบนั้นใช้งานได้กับจำนวนเต็ม 64 บิตเท่านั้น

นี่คือตัวอย่างของข้อผิดพลาดเมื่อbitSizeเป็น 8

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

package main

import (
    "fmt"
    "strconv"
)

func main() {
    i, err := strconv.ParseInt("123456", 10, 8)
    fmt.Println(i, err)
}

22
ในทางปฏิบัติ Go มักใช้int64สำหรับintamd64 GOARCH และint32สำหรับGOARCHes int32 บิต อย่างน้อยด้วยคอมไพเลอร์เริ่มต้นฉันไม่แน่ใจเกี่ยวกับ gccgo ดังนั้น " intอาจใหญ่กว่า 32 บิต ... " ไม่ใช่แค่การเก็งกำไร แต่เป็นไปได้ค่อนข้างมากเนื่องจากโดยทั่วไปเป้าหมายการคอมไพล์ 64 บิตถือเป็นสาขาหลักใน Go
LinearZoetrope

12
"ในทางปฏิบัติ Go มักจะใช้ int64 สำหรับ int บน amd64 [.. ]" - อย่างแม่นยำยิ่งขึ้นint จะเท่ากับขนาดบิตของโปรเซสเซอร์เสมอ ในระบบ 64 บิตเป็น 64 บิตในระบบ 32 บิตเป็น 32 บิต ฉันชอบคิดว่ามันเป็นนามแฝงของ int32 หรือ int64 ขึ้นอยู่กับเป้าหมายการคอมไพล์ของคุณ (แม้ว่าจะไม่ได้ใช้เป็นนามแฝงก็ไม่สำคัญ)
zupa

@zupa แหล่งที่มา / ข้อมูลอ้างอิงสำหรับ "int จะเท่ากับขนาดบิตของโปรเซสเซอร์เสมอ" คืออะไร?
kapad

29

แพ็คเกจ strconv

func ParseInt

func ParseInt(s string, base int, bitSize int) (i int64, err error)

ParseInt ตีความสตริง s ในฐานที่กำหนด (2 ถึง 36) และส่งกลับค่าที่สอดคล้องกัน i ถ้าฐาน == 0 ฐานจะแสดงนัยโดยคำนำหน้าของสตริง: ฐาน 16 สำหรับ "0x", ฐาน 8 สำหรับ "0" และฐาน 10 มิฉะนั้น

อาร์กิวเมนต์ bitSize ระบุชนิดจำนวนเต็มที่ผลลัพธ์ต้องพอดี ขนาดบิต 0, 8, 16, 32 และ 64 สอดคล้องกับ int, int8, int16, int32 และ int64

ข้อผิดพลาดที่ ParseInt ส่งคืนมีชนิดคอนกรีต * NumError และรวม err.Num = s ถ้า s ว่างเปล่าหรือมีตัวเลขที่ไม่ถูกต้อง err.Err = ErrSyntax; ถ้าค่าที่สอดคล้องกับ s ไม่สามารถแทนด้วยจำนวนเต็มที่ลงนามของขนาดที่กำหนด err.Err = ErrRange

ParseIntส่งคืนint64ค่าเสมอ ทั้งนี้ขึ้นอยู่กับbitSizeค่านี้จะพอดีกับint, int8, int16, หรือint32 int64ถ้าค่าไม่สามารถแทนด้วยจำนวนเต็มลงนามในขนาดที่กำหนดโดยแล้วbitSizeerr.Err = ErrRange

ข้อกำหนดภาษาโปรแกรม Go

ประเภทตัวเลข

ค่าของจำนวนเต็ม n บิตกว้าง n บิตและแสดงโดยใช้เลขคณิตเสริมสองค่า

int8        the set of all signed  8-bit integers (-128 to 127)
int16       the set of all signed 16-bit integers (-32768 to 32767)
int32       the set of all signed 32-bit integers (-2147483648 to 2147483647)
int64       the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807)

นอกจากนี้ยังมีชุดประเภทตัวเลขที่ประกาศไว้ล่วงหน้าซึ่งมีขนาดเฉพาะการใช้งาน:

uint     either 32 or 64 bits
int      same size as uint

intเป็น 32 หรือ 64 บิตขึ้นอยู่กับการนำไปใช้งาน โดยปกติจะเป็น 32 บิตสำหรับคอมไพเลอร์ 32 บิตและ 64 บิตสำหรับคอมไพเลอร์ 64 บิต

เพื่อหาขนาดของนั้นintหรือใช้uintstrconv.IntSize

แพ็คเกจ strconv

ค่าคงที่

const IntSize = intSize

IntSizeคือขนาดเป็นบิตของค่าintหรือuint

ตัวอย่างเช่น,

package main

import (
    "fmt"
    "runtime"
    "strconv"
)

func main() {
    fmt.Println(runtime.Compiler, runtime.GOARCH, runtime.GOOS)
    fmt.Println(strconv.IntSize)
}

เอาท์พุต:

gc amd64 linux
64

7

strconv.ParseIntและเพื่อน ๆ ส่งคืนเวอร์ชัน 64 บิตเพื่อให้ API สะอาดและเรียบง่าย อย่างอื่นจะต้องสร้างเวอร์ชันแยกกันสำหรับผลตอบแทนแต่ละประเภทที่เป็นไปได้ หรือกลับinterface{}ซึ่งจะต้องผ่านการยืนยันประเภท ไม่มีสิ่งใดที่เหมาะ

int64ถูกเลือกเนื่องจากสามารถรองรับขนาดจำนวนเต็มใด ๆ ก็ได้และรวมถึง 64 บิตที่รองรับ ขนาดบิตที่คุณส่งผ่านเข้าไปในฟังก์ชันช่วยให้มั่นใจได้ว่าค่าถูกจับยึดอย่างเหมาะสมกับช่วงที่ถูกต้อง ดังนั้นคุณสามารถทำการแปลงประเภทกับมูลค่าที่ส่งคืนเพื่อเปลี่ยนเป็นประเภทจำนวนเต็มที่คุณต้องการ

สำหรับความแตกต่างระหว่างintและint64นี่ขึ้นอยู่กับสถาปัตยกรรม intเป็นเพียงนามแฝงสำหรับจำนวนเต็ม 32 บิตหรือ 64 บิตขึ้นอยู่กับสถาปัตยกรรมที่คุณกำลังรวบรวม

สำหรับสายตาที่มองเห็น: ค่าที่ส่งคืนเป็นจำนวนเต็มที่ลงนาม มีstrconv.ParseUintฟังก์ชันแยกต่างหากสำหรับจำนวนเต็มที่ไม่ได้ลงชื่อซึ่งจะส่งกลับuint64และเป็นไปตามเหตุผลเดียวกันกับที่อธิบายไว้ข้างต้น


4
จากสิ่งที่ฉันเห็นจนถึงตอนนี้มันเกือบจะถูกต้องยกเว้นว่าฉันไม่คิดว่าintเป็นเพียงนามแฝง - จริงๆแล้วมันเป็นประเภทที่แตกต่างกัน golang.org/pkg/builtin/#int
Isaac Dontje Lindell

แน่นอน. Go ไม่ได้ทำนามแฝงประเภทจริงๆ สิ่งที่ชอบtype int int32คือการถือเป็นประเภทที่ไม่เหมือนใครและแยกจากกัน โดยเฉพาะอย่างยิ่งเนื่องจากช่วยให้สามารถกำหนดฟังก์ชันการทำงานใหม่สำหรับintประเภทผ่านการประยุกต์ใช้วิธีการใหม่
jimt

5

สำหรับวัตถุประสงค์ของคุณstrconv.Atoi()ฉันคิดว่าจะสะดวกกว่า

คำตอบอื่น ๆ ค่อนข้างละเอียดเกี่ยวกับการอธิบายintประเภท แต่ฉันคิดว่าลิงก์ไปยังข้อกำหนดภาษา Go สามารถใช้ได้ที่นี่: http://golang.org/ref/spec#Numeric_types


0

ใน Go lang แต่ละประเภทถือเป็นประเภทข้อมูลแยกกันซึ่งไม่สามารถใช้แทนกันได้กับประเภทฐาน ตัวอย่างเช่น,

type CustomInt64 int64

ในคำประกาศข้างต้น CustomInt64 และ int64 ในตัวเป็นข้อมูลสองประเภทที่แยกจากกันและไม่สามารถใช้แทนกันได้

เช่นเดียวกันกับ int, int32 และ int64 ซึ่งทั้งหมดนี้เป็นชนิดข้อมูลแยกกันที่ไม่สามารถใช้แทนกันได้ โดยที่ int32 คือ 32 ประเภทจำนวนเต็ม int64 คือ 64 บิตและขนาดของประเภท int ทั่วไปขึ้นอยู่กับแพลตฟอร์ม กว้าง 32 บิตในระบบ 32 บิตและกว้าง 64 บิตในระบบ 64 บิต ดังนั้นเราต้องระมัดระวังและเจาะจงในขณะที่ระบุชนิดข้อมูลทั่วไปเช่น int, uint และ float อาจทำให้เกิดปัญหาในโค้ดและจะทำให้แอปพลิเคชันบนแพลตฟอร์มอื่นขัดข้อง

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