Làm thế nào để nhân thời lượng với số nguyên?


284

Để kiểm tra goroutines đồng thời, tôi đã thêm một dòng vào một hàm để làm cho nó mất một thời gian ngẫu nhiên để trở lại (tối đa một giây)

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

Tuy nhiên khi tôi biên dịch, tôi đã gặp lỗi này

. \ crawler.go: 49: hoạt động không hợp lệ: rand.Int31n (1000) * time.Millisecond (loại không khớp int32 và time.Duration)

Có ý kiến ​​gì không? Làm thế nào tôi có thể nhân một thời lượng?

Câu trả lời:


430

int32time.Durationlà các loại khác nhau. Bạn cần chuyển đổi int32thành a time.Duration, chẳng hạn như time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond).


5
Cảm ơn đã làm việc. Tôi cũng đã học được về gieo mầm máy tạo số ngẫu nhiênrand.Seed(time.Now().Unix())
Đại tá Panic

44
chỉ cho kiến ​​thức của tôi, làm thế nào sau đây làm việc? time.Sleep(time.Second * 2)
Ishan Khare

59
Nó hoạt động vì hằng số có một loại thích ứng, dựa trên cách chúng được sử dụng. Xem bài đăng trên blog này của Rob Pike giải thích chi tiết: blog.golang.org/constants
mna

28
Đây là một trong những điều kỳ lạ do hệ thống loại đơn giản của nó (thiếu quá tải toán tử trong trường hợp này) - bạn phải bỏ phép nhân thành Duration* Duration= Duration, thay vì hệ thống ban đầu thực sự có ý nghĩa hơn: Duration* int= Duration.
Timmmm

14
Vâng, toán tử quá tải hoặc chuyển đổi số ngầm định sẽ cho phép điều này hoạt động. Tôi nghĩ rằng họ đã đúng khi bỏ qua chuyển đổi số ngầm định. Sau khi nhìn lại điều này có int64(...) * Durationý nghĩa hơn nhiều so với việc truyền vào Duration, đó chỉ là một sự vi phạm cơ bản về cách các đơn vị nên làm việc. Đáng buồn thay, nó không hoạt động. Bạn thực sự phải làm điều Duration * Durationđó là khủng khiếp.
Timmmm

59

Bạn phải chuyển nó sang một định dạng chính xác Playground.

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

Nếu bạn sẽ kiểm tra tài liệu cho giấc ngủ , bạn sẽ thấy rằng nó yêu cầu func Sleep(d Duration)thời lượng như một tham số. Trả lại rand.Int31n của bạn int32.

Dòng từ ví dụ hoạt động ( time.Sleep(100 * time.Millisecond)) vì trình biên dịch đủ thông minh để hiểu rằng ở đây hằng số 100 của bạn có nghĩa là thời lượng. Nhưng nếu bạn vượt qua một biến, bạn nên bỏ nó.


16

Trong Go, bạn có thể nhân các biến cùng loại, vì vậy bạn cần có cả hai phần của biểu thức cùng loại.

Điều đơn giản nhất bạn có thể làm là truyền một số nguyên cho thời lượng trước khi nhân, nhưng điều đó sẽ vi phạm ngữ nghĩa đơn vị. Điều gì sẽ được nhân thời lượng theo thời lượng theo đơn vị?

Tôi muốn chuyển đổi thời gian.Millisecond thành int64, sau đó nhân nó với số mili giây, sau đó chuyển thành time.Duration:

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

Bằng cách này, bất kỳ phần nào của biểu thức có thể được cho là có giá trị có ý nghĩa theo loại của nó. int64(time.Millisecond)một phần chỉ là một giá trị không thứ nguyên - số đơn vị thời gian nhỏ nhất trong giá trị ban đầu.

Nếu đi một con đường đơn giản hơn một chút:

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

Phần bên trái của phép nhân là vô nghĩa - một giá trị của loại "time.Duration", giữ một cái gì đó không liên quan đến loại của nó:

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

Và nó không chỉ là ngữ nghĩa, có chức năng thực tế liên quan đến các loại. Mã này in:

100ns
100ms

Thật thú vị, mẫu mã ở đây sử dụng mã đơn giản nhất, với cùng một ngữ nghĩa sai lệch về chuyển đổi Thời lượng: https://golang.org/pkg/time/#Duration

giây: = 10

fmt.Print (time.Duration (giây) * time.Second) // in 10s


5

Thật tuyệt khi Go có một Durationloại - có các đơn vị được xác định rõ ràng có thể ngăn chặn các vấn đề trong thế giới thực.

Và do quy tắc loại nghiêm ngặt của Go, bạn không thể nhân Thời lượng với số nguyên - bạn phải sử dụng một nhóm để nhân các loại phổ biến.

/*
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'
}

Các tài liệu chính thức cho thấy sử dụng phương pháp # 1:

Để chuyển đổi số nguyên đơn vị thành Thời lượng, nhân:

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

Nhưng, tất nhiên, nhân một thời lượng với một khoảng thời gian sẽ không tạo ra thời lượng - điều đó là vô nghĩa trên mặt của nó. Trường hợp tại điểm, 5 mili giây nhân với 5 mili giây tạo ra 6h56m40s. Cố gắng bình phương 5 giây sẽ dẫn đến tràn (và thậm chí sẽ không biên dịch nếu được thực hiện với các hằng số).

Nhân tiện, việc int64biểu diễn tính Durationbằng nano giây "giới hạn thời gian biểu diễn lớn nhất trong khoảng 290 năm" và điều này cho thấy Duration, giống như int64, được coi là một giá trị đã ký: (1<<(64-1))/(1e9*60*60*24*365.25) ~= 292và đó chính xác là cách nó được thực hiện:

// 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

Vì vậy, bởi vì chúng ta biết rằng biểu diễn cơ bản của Durationlà một int64, thực hiện phân vai giữa int64Durationlà một NO-OP hợp lý - chỉ cần để đáp ứng các quy tắc ngôn ngữ về các kiểu trộn và nó không có tác dụng đối với hoạt động nhân tiếp theo.

Nếu bạn không thích buổi casting vì lý do thuần khiết, hãy chôn nó trong một cuộc gọi chức năng như tôi đã trình bày ở trên.


"Nhân với / với các loại phổ biến".
tộc

Thảo luận tương tự liên quan đến phân chia tại câu trả lời (sai) ở đây .
tộc

-3

Để nhân biến với thời gian. Thứ hai sử dụng mã sau

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

Đây không phải là một cách tốt để sử dụng time.Durationcác biến của Go . Bạn đặt tên cho biến addOneHrDurationthời gian của mình time.Durationnhưng sau đó tiến hành đặt nó thành 3600 ns chứ không phải một giờ. A time.Durationxảy ra để có các đơn vị cơ bản của nano giây. Để thực sự có được thời lượng một giờ, bạn có thể làm một cái gì đó như: const oneHourDuration = 60 * time.Hour(hoặc 3600 * time.Secondhoặc time.Hour).
Dave C
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.