Golang tour Switch evaluation order: time.Now().Weekday() + 2 yields runtime error: index out of range

huangapple go评论94阅读模式
英文:

Golang tour Switch evaluation order: time.Now().Weekday() + 2 yields runtime error: index out of range

问题

我正在学习Golang,在教程中遇到了关于Switch评估顺序的教程。我稍微修改了一下(例如,将Saturday改为Sunday),只是为了玩一下。即使是Sunday,它也打印出了Too far away.。所以,我修改了代码,如下所示:

package main

import (
	"fmt"
	"time"
)

func main() {
	day := time.Monday
	
	fmt.Printf("When's %v?\n", day)
	today := time.Now().Weekday()
	
	switch {
	case day == today:
		fmt.Println("Today.")
	case day == today + 1:
		fmt.Println("Tomorrow.", today + 1)
	case day == today + 2:
		fmt.Println("In two days.", today + 2)
	default:
		fmt.Println("Too far away.", today + 2)
	}
}

现在,它给我输出的结果是:

When's Monday?
Too far away. %!v(PANIC=runtime error: index out of range)

我应该如何对索引进行MOD运算,而不是将其添加到数组之外?对我来说,这似乎是某种运算符重载。在处理天数时,默认情况下,它不应该在加法操作中执行MOD运算吗?

英文:

I am learning Golang, was going through the tour where I found a tutorial on Switch evaluation order. I modified it a bit (e.g. Saturday to Sunday), just to play around. It printed Too far away. even for Sunday. So, I modified the code to look like this:

package main

import (
	"fmt"
	"time"
)

func main() {
	day := time.Monday
	
	fmt.Printf("When's %v?\n", day)
	today := time.Now().Weekday()
	
	switch day {
	case today + 0:
		fmt.Println("Today.")
	case today + 1:
		fmt.Println("Tomorrow.", today + 1)
	case today + 2:
		fmt.Println("In two days.", today + 2)
	default:
		fmt.Println("Too far away.", today + 2)
	}
}

Now, it gives me the output:

When's Monday?
Too far away. %!v(PANIC=runtime error: index out of range)

What can I do to MOD the index, instead of adding it beyond array? Seems to me like some kind of operator overloading. Shouldn't it do MOD, on add operation, by default in case of days, at least?

答案1

得分: 4

这是一个实现细节。

在这一行代码中:

fmt.Println("In two days.", today + 2)

todaytime.Weekday 类型,其底层类型为 int2 是一个无类型的整数常量,它将被转换为 time.Weekday 类型并进行相加运算。

fmt.Println() 的实现会检查传递给它的值是否实现了 fmt.Stringer 接口,因为 time.Weekday 实现了该接口,所以会调用其 String() 方法,其实现如下:

// String 返回星期的英文名称("Sunday", "Monday", ...)。
func (d Weekday) String() string { return days[d] }

其中 days 是一个包含 7 个元素的数组:

var days = [...]string{
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
}

Weekday.String() 方法中没有范围检查,因为例如 time.Saturday + 2 不是一个有效的星期。Weekday.String() 方法只保证对 time 包中定义的常量有效:

type Weekday int

const (
    Sunday Weekday = iota
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
)

如果你想让它正常工作,你需要使用除以 7 的余数,像这样:

switch day {
case (today + 0) % 7:
    fmt.Println("Today.")
case (today + 1) % 7:
    fmt.Println("Tomorrow.", (today+1)%7)
case (today + 2) % 7:
    fmt.Println("In two days.", (today+2)%7)
default:
    fmt.Println("Too far away.", (today+2)%7)
}
英文:

This is an implementation detail.

In this line

fmt.Println("In two days.", today + 2)

today is of type time.Weekday which has int as its underlying type, 2 is an untyped integer constant, which will be converted to time.Weekday and the addition will be carried out.

The implementation of fmt.Println() will check if values passed to it implement fmt.Stringer, and because time.Weekday does, its String() method will be called whose implementation is:

// String returns the English name of the day ("Sunday", "Monday", ...).
func (d Weekday) String() string { return days[d] }

Where days is an array of 7 elements:

var days = [...]string{
  	"Sunday",
  	"Monday",
  	"Tuesday",
  	"Wednesday",
  	"Thursday",
  	"Friday",
  	"Saturday",
  }

There is no range check in Weekday.String() because time.Saturday + 2 for example is not a weekday. Weekday.String() only guarantees to work properly for the constants defined in the time package:

type Weekday int

const (
    Sunday Weekday = iota
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
)

If you want to make it work, you have to use the remainder after dividing by 7, like this:

switch day {
case (today + 0) % 7:
	fmt.Println("Today.")
case (today + 1) % 7:
	fmt.Println("Tomorrow.", (today+1)%7)
case (today + 2) % 7:
	fmt.Println("In two days.", (today+2)%7)
default:
	fmt.Println("Too far away.", (today+2)%7)
}

huangapple
  • 本文由 发表于 2017年6月2日 16:58:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/44324792.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定