| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- package main
- import (
- "bufio"
- "errors"
- "flag"
- "fmt"
- "io"
- "os"
- "strconv"
- "strings"
- )
- // run 接收参数、输入和输出,方便测试时不依赖真实终端。
- // 参数不包含程序名,通常由 main 传入 os.Args[1:]。
- func run(args []string, input io.Reader, output io.Writer) error {
- // ContinueOnError 让解析失败返回错误,而不是直接结束整个进程。
- flags := flag.NewFlagSet("study", flag.ContinueOnError)
- flags.SetOutput(output) // 帮助信息和参数解析错误写到这里。
- name := flags.String("name", "", "学习者姓名;交互模式可留空")
- minutes := flags.Int("minutes", 0, "学习时长(分钟,1~1440)")
- interactive := flags.Bool("interactive", false, "从标准输入读取姓名和时长")
- if err := flags.Parse(args); err != nil {
- return err
- }
- if flags.NArg() != 0 {
- return fmt.Errorf("不支持的位置参数:%s", strings.Join(flags.Args(), " "))
- }
- if *interactive {
- // 明确禁止混用两种输入来源,避免覆盖用户提供的参数。
- mixed := false
- flags.Visit(func(item *flag.Flag) {
- if item.Name == "name" || item.Name == "minutes" {
- mixed = true
- }
- })
- if mixed {
- return errors.New("交互模式不能同时指定 name 或 minutes")
- }
- scanner := bufio.NewScanner(input)
- if _, err := fmt.Fprint(output, "请输入姓名:"); err != nil {
- return err
- }
- if !scanner.Scan() {
- if err := scanner.Err(); err != nil {
- return err
- }
- return errors.New("没有读取到姓名")
- }
- *name = scanner.Text()
- if _, err := fmt.Fprint(output, "请输入学习分钟数:"); err != nil {
- return err
- }
- if !scanner.Scan() {
- if err := scanner.Err(); err != nil {
- return err
- }
- return errors.New("没有读取到分钟数")
- }
- value, err := strconv.Atoi(strings.TrimSpace(scanner.Text()))
- if err != nil {
- return fmt.Errorf("分钟数必须是整数:%w", err)
- }
- *minutes = value
- }
- cleanName := strings.TrimSpace(*name)
- if cleanName == "" {
- return errors.New("姓名不能为空,请指定 -name 或使用 -interactive")
- }
- if *minutes < 1 || *minutes > 1440 {
- return errors.New("学习分钟数必须在 1~1440 之间")
- }
- _, err := fmt.Fprintf(output, "学习者:%s,学习时长:%d 分钟\n", cleanName, *minutes)
- return err
- }
- func main() {
- // Args[0] 通常是程序名,Args[1:] 是用户提供的参数。
- if err := run(os.Args[1:], os.Stdin, os.Stdout); err != nil {
- if errors.Is(err, flag.ErrHelp) {
- return // -h 是查看帮助,不属于失败。
- }
- fmt.Fprintln(os.Stderr, "错误:", err)
- os.Exit(1)
- }
- }
|