วิธีการคูณระยะเวลาด้วยจำนวนเต็ม?


285

ในการทดสอบ goroutines พร้อมกันฉันเพิ่มโฆษณาให้กับฟังก์ชั่นที่จะทำให้มันใช้เวลาสุ่มเพื่อผลตอบแทน (ถึงหนึ่งวินาที)

time.Sleep(rand.Int31n(1000) * time.Millisecond)

อย่างไรก็ตามเมื่อฉันรวบรวมฉันได้รับข้อผิดพลาดนี้

. \ crawler.go: 49: การดำเนินการไม่ถูกต้อง: rand.Int31n (1000) * time.Millisecond (ไม่ตรงกันประเภท Int32 และ time.Duration)

ความคิดใด ๆ ฉันจะคูณระยะเวลาได้อย่างไร

คำตอบ:


431

int32และtime.Durationเป็นประเภทที่แตกต่างกัน คุณจำเป็นต้องแปลงint32ไปเช่นtime.Durationtime.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond)


5
ขอบคุณที่ใช้งานได้ ฉันยังได้เรียนรู้เกี่ยวกับการสร้างตัวสร้างตัวเลขแบบสุ่มrand.Seed(time.Now().Unix())
พันเอก Panic

44
เพียงเพื่อความรู้ของฉันไม่ว่าต่อไปนี้การทำงานแล้ว? time.Sleep(time.Second * 2)
Ishan Khare

59
มันทำงานได้เพราะค่าคงที่มีชนิดปรับตัวตามวิธีการใช้งาน ดูโพสต์นี้บล็อกโดย Rob หอกที่อธิบายในรายละเอียด: blog.golang.org/constants
MNA

28
นี่เป็นหนึ่งในสิ่งแปลกประหลาดที่เกิดขึ้นเนื่องจากระบบประเภทง่าย ๆ (ขาดตัวดำเนินการมากไปในกรณีนี้) - คุณต้องแปลงการคูณเป็นDuration* Duration= Durationแทนที่จะเป็นระบบดั้งเดิมซึ่งมีเหตุผลมากกว่า: Duration* int=Duration =
Timmmm

14
ทั้งตัวดำเนินการมากเกินไปหรือการแปลงตัวเลขโดยนัยจะช่วยให้งานนี้ ฉันคิดว่าพวกเขามีสิทธิ์ที่จะออกจากการแปลงเชิงตัวเลข หลังจากมองย้อนกลับไปในเรื่องนี้มันint64(...) * Durationสมเหตุสมผลมากกว่าการส่งไปDurationซึ่งเป็นการละเมิดพื้นฐานว่าหน่วยควรทำงานอย่างไร น่าเศร้าที่ใช้ไม่ได้ คุณต้องทำสิ่งDuration * Durationที่น่ากลัวจริงๆ
Timmmm

60

Playgroundคุณต้องโยนให้เป็นรูปแบบที่ถูกต้อง

yourTime := rand.Int31n(1000)
time.Sleep(time.Duration(yourTime) * time.Millisecond)

ถ้าคุณจะตรวจสอบเอกสารสำหรับการนอนหลับคุณจะเห็นว่ามันต้องใช้func Sleep(d Duration)ระยะเวลาเป็นพารามิเตอร์ คุณrand.Int31nint32ผลตอบแทน

บรรทัดจากตัวอย่างใช้งานได้ ( time.Sleep(100 * time.Millisecond)) เนื่องจากคอมไพเลอร์ฉลาดพอที่จะเข้าใจได้ว่าที่นี่ค่าคงที่ 100 ของคุณหมายถึงระยะเวลา แต่ถ้าคุณผ่านตัวแปรคุณควรใช้มัน


16

ใน Go คุณสามารถคูณตัวแปรชนิดเดียวกันได้ดังนั้นคุณต้องมีทั้งสองส่วนของ expression เหมือนกัน

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

ฉันควรแปลงเวลามิลลิวินาทีเป็น int64 แล้วคูณด้วยจำนวนมิลลิวินาทีจากนั้นแปลงเป็นเวลาระยะเวลา:

time.Duration(int64(time.Millisecond) * int64(rand.Int31n(1000)))

วิธีนี้ส่วนใดของการแสดงออกสามารถพูดได้ว่ามีค่าที่มีความหมายตามประเภทของมัน int64(time.Millisecond)ส่วนหนึ่งเป็นเพียงค่าไร้มิติ - จำนวนหน่วยที่เล็กที่สุดของเวลาในค่าดั้งเดิม

ถ้าเดินเส้นทางที่ง่ายเล็กน้อย

time.Duration(rand.Int31n(1000)) * time.Millisecond

ส่วนด้านซ้ายของการคูณเป็นเรื่องไร้สาระ - ค่าประเภท "เวลาช่วงเวลา" ถือบางสิ่งที่ไม่เกี่ยวข้องกับประเภทของมัน:

numberOfMilliseconds := 100
// just can't come up with a name for following:
someLHS := time.Duration(numberOfMilliseconds)
fmt.Println(someLHS)
fmt.Println(someLHS*time.Millisecond)

และมันไม่ได้เป็นแค่ความหมายมีฟังก์ชั่นจริงที่เกี่ยวข้องกับประเภท พิมพ์รหัสนี้:

100ns
100ms

ที่น่าสนใจตัวอย่างโค้ดที่นี่ใช้รหัสที่ง่ายที่สุดโดยมีความหมายที่ทำให้เข้าใจผิดของการแปลงระยะเวลา: https://golang.org/pkg/time/#Duration

วินาที = 10

fmt.Print (time.Duration (วินาที) * time.Second) // พิมพ์ 10 วินาที


5

เป็นเรื่องที่ดีที่ Go มีDurationประเภท - การมีหน่วยงานที่กำหนดไว้อย่างชัดเจนสามารถป้องกันปัญหาในโลกแห่งความจริง

และเนื่องจากกฎประเภทที่เข้มงวดของ Go คุณจึงไม่สามารถคูณ Duration ด้วยจำนวนเต็มได้ - คุณต้องใช้การส่งนักแสดงเพื่อคูณประเภทสามัญ

/*
MultiplyDuration Hide semantically invalid duration math behind a function
*/
func MultiplyDuration(factor int64, d time.Duration) time.Duration {
    return time.Duration(factor) * d        // method 1 -- multiply in 'Duration'
 // return time.Duration(factor * int64(d)) // method 2 -- multiply in 'int64'
}

เอกสารอย่างเป็นทางการแสดงให้เห็นถึงการใช้วิธีการ # 1:

ในการแปลงจำนวนเต็มหน่วยเป็นระยะเวลาให้คูณ:

seconds := 10
fmt.Print(time.Duration(seconds)*time.Second) // prints 10s

แต่แน่นอนว่าการคูณระยะเวลาด้วยระยะเวลาไม่ควรสร้างระยะเวลา - ที่ไร้สาระบนใบหน้าของมัน ในกรณีที่จุด 5 มิลลิวินาทีครั้งที่ 5 6h56m40sมิลลิวินาทีผลิต ความพยายามในการทำตาราง 5 วินาทีจะส่งผลให้เกิดการโอเวอร์โฟลว์

อย่างไรก็ตามการเป็นint64ตัวแทนDurationในหน่วยนาโนวินาที"จำกัด ระยะเวลาที่สามารถนำเสนอได้มากที่สุดเป็นประมาณ 290 ปี"และสิ่งนี้บ่งชี้ว่าDurationเช่นint64นั้นจะถือว่าเป็นค่าที่ลงชื่อ: (1<<(64-1))/(1e9*60*60*24*365.25) ~= 292และนั่นคือวิธีการนำไปใช้จริง:

// A Duration represents the elapsed time between two instants
// as an int64 nanosecond count. The representation limits the
// largest representable duration to approximately 290 years.
type Duration int64

ดังนั้นเนื่องจากเรารู้ว่าการเป็นตัวแทนพื้นฐานของDurationคือการint64แสดงตัวระหว่างint64และDurationเป็น NO-OP ที่สมเหตุสมผล - ต้องการเพียงเพื่อให้เป็นไปตามกฎภาษาเกี่ยวกับประเภทการผสมและไม่มีผลต่อการดำเนินการคูณที่ตามมา

หากคุณไม่ชอบการคัดเลือกนักแสดงด้วยเหตุผลของความบริสุทธิ์ให้ฝังไว้ในการเรียกใช้ฟังก์ชันตามที่ฉันได้แสดงไว้ด้านบน


"คูณเป็น / กับชนิดที่พบบ่อย"
nobar

การอภิปรายที่คล้ายกันที่เกี่ยวข้องกับส่วนที่ (ผิด) คำตอบที่นี่
nobar

-3

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

    oneHr:=3600
    addOneHrDuration :=time.Duration(oneHr)
    addOneHrCurrTime := time.Now().Add(addOneHrDuration*time.Second)

นี่ไม่ใช่วิธีที่ดีในการใช้time.Durationตัวแปรของ Go คุณตั้งชื่อตัวแปรaddOneHrDurationเวลาtime.Durationแต่ตั้งค่าเป็น 3600 ns ไม่ใช่หนึ่งชั่วโมง A time.Durationมีหน่วยเป็นนาโนวินาที หากต้องการรับระยะเวลาหนึ่งชั่วโมงคุณสามารถทำสิ่งที่ต้องการ: const oneHourDuration = 60 * time.Hour(หรือ3600 * time.Secondหรือtime.Hour)
เดฟ C
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.