如何在不丧失任何功能的情况下最小化 if/else 的数量?

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

how do i minimize the amount if/else without losing any functionality?

问题

package main
import "fmt"

var firstUserChoice int
var secondUserChoice int

func main() {
fmt.Println("欢迎使用GO METER应用")
fmt.Print("1-毫米转换\n2-厘米转换\n3-米转换\n4-千米转换\n请选择操作:")
fmt.Scanln(&firstUserChoice)
if firstUserChoice <= 4 {
secondStage()
} else {
fmt.Println("无效选择")
secondStage()
}
}

// 询问用户第二个单位
func secondStage() {
fmt.Print("1-转换为毫米\n2-转换为厘米\n3-转换为米\n4-转换为千米\n请选择操作:")
fmt.Scanln(&secondUserChoice)
if secondUserChoice <= 4 {
thirdStage()
} else {
fmt.Println("无效选择")
thirdStage()
}
}

func thirdStage() {
var number float64
const mm string = "毫米"
const cm string = "厘米"
const m string = "米"
const km string = "千米"
fmt.Print("请输入要转换的数字:")
fmt.Scanln(&number)
switch firstUserChoice {
case 1:
if secondUserChoice == 1 {
fmt.Println(number, mm, "等于", number, mm)
}
if secondUserChoice == 2 {
fmt.Println(number, mm, "等于", number/10, cm)
}
if secondUserChoice == 3 {
fmt.Println(number, mm, "等于", number/1000, m)
}
if secondUserChoice == 4 {
fmt.Println(number, mm, "等于", number/1000000, km)
}
case 2:
if secondUserChoice == 1 {
fmt.Println(number, cm, "等于", number10, mm)
}
if secondUserChoice == 2 {
fmt.Println(number, cm, "等于", number, cm)
}
if secondUserChoice == 3 {
fmt.Println(number, cm, "等于", number/100, m)
}
if secondUserChoice == 4 {
fmt.Println(number, cm, "等于", number/100000, km)
}
case 3:
if secondUserChoice == 1 {
fmt.Println(number, m, "等于", number
1000, mm)
}
if secondUserChoice == 2 {
fmt.Println(number, m, "等于", number100, cm)
}
if secondUserChoice == 3 {
fmt.Println(number, m, "等于", number, m)
}
if secondUserChoice == 4 {
fmt.Println(number, m, "等于", number/1000, km)
}
case 4:
if secondUserChoice == 1 {
fmt.Println(number, km, "等于", number
1000000, mm)
}
if secondUserChoice == 2 {
fmt.Println(number, km, "等于", number100000, cm)
}
if secondUserChoice == 3 {
fmt.Println(number, km, "等于", number
1000, m)
}
if secondUserChoice == 4 {
fmt.Println(number, km, "等于", number, km)
}
}
}

我写了这个程序作为一个小练习,它可以将4个长度单位相互转换,但我为每个可能的组合都编写了代码,我认为这不是很高效。
然而,问题是我对Go编程语言还很陌生,我需要你的慷慨帮助来清理我最近写的糟糕代码,如何通过减少if/else语句的数量将我的糟糕代码转变为更简单、更清晰和更可读的代码?
除了if/else之外,我还有什么错误使代码更可读吗?

英文:
package main
import &quot;fmt&quot;

var firstUserChoice int
var secondUserChoice int



func main()  {
   fmt.Println(&quot;Welcome to GO METER app&quot;)
   fmt.Print(&quot;1-Milimeter to\n2-Centimeter to\n3-Meter to\n4-Kilometer to\nPlease choose an operation: &quot;)
   fmt.Scanln(&amp;firstUserChoice)
   if firstUserChoice &lt;= 4 {
     secondStage()
   } else {
     fmt.Println(&quot;INVALID CHOICE&quot;)
     secondStage()
   }
}

// ask user for the second unit
func secondStage() ()  {
  fmt.Print(&quot;1-to Milimeter\n2-to Centimeter\n3-to Meter\n4-kilometer to\nPlease choose an operation: &quot;)
  fmt.Scanln(&amp;secondUserChoice)
  if secondUserChoice &lt;= 4 {
    thirdStage()
  } else {
    fmt.Println(&quot;INVALID CHOICE&quot;)
    thirdStage()
  }
}

func thirdStage()  {
  var number float64
  const mm string = &quot;Milimeters&quot;
  const cm string = &quot;Centimeters&quot;
  const m string = &quot;Meters&quot;
  const km string = &quot;Kilometers&quot;
  fmt.Print(&quot;Enter the number you want to convert: &quot;)
  fmt.Scanln(&amp;number)
  switch firstUserChoice {
  case 1:
    if secondUserChoice == 1 {
      fmt.Println(number, mm,&quot;Equals&quot;, number, mm)
    }
    if secondUserChoice == 2 {
      fmt.Println(number, mm,&quot;Equals&quot;, number/10, cm)
    }
    if secondUserChoice == 3 {
      fmt.Println(number, mm,&quot;Equals&quot;, number/1000, m)
    }
    if secondUserChoice == 4 {
      fmt.Println(number, mm,&quot;Equals&quot;, number/1000000, km)
    }
  case 2:
    if secondUserChoice == 1 {
      fmt.Println(number, cm,&quot;Equals&quot;, number*10, m)
    }
    if secondUserChoice == 2 {
      fmt.Println(number, cm,&quot;Equals&quot;, number, cm)
    }
    if secondUserChoice == 3 {
      fmt.Println(number, cm,&quot;Equals&quot;, number/100, m)
    }
    if secondUserChoice == 4 {
      fmt.Println(number, cm,&quot;Equals&quot;, number/100000, km)
    }
  case 3:
    if secondUserChoice == 1 {
      fmt.Println(number, m,&quot;Equals&quot;, number*1000, mm)
    }
    if secondUserChoice == 2 {
      fmt.Println(number, m,&quot;Equals&quot;, number*100, cm)
    }
    if secondUserChoice == 3 {
      fmt.Println(number, m,&quot;Equals&quot;, number, m)
    }
    if secondUserChoice == 4 {
      fmt.Println(number, m,&quot;Equals&quot;, number/1000, km)
    }
  case 4:
    if secondUserChoice == 1 {
      fmt.Println(number, km,&quot;Equals&quot;, number*1000000, mm)
    }
    if secondUserChoice == 2 {
      fmt.Println(number, km,&quot;Equals&quot;, number*100000, cm)
    }
    if secondUserChoice == 3 {
      fmt.Println(number, km,&quot;Equals&quot;, number*1000, mm)
    }
    if secondUserChoice == 4 {
      fmt.Println(number, km,&quot;Equals&quot;, number, km)
    }
  }
}

I wrote this program as a tiny exercise, it converts 4 length units to each other but i wrote code for every single possible combination which is not very efficient in my opinion.
However the problem is that I am still very new to the go programming language and i need your generous help with cleaning the dirty code that i recently wrote, how can i turn my dirty code into a more simpler, cleaner and readable by reducing the amount of if/else arguments?
And are there anything i did wrong other than if/else that makes the code more readable

答案1

得分: 1

由于这是一个练习,你可以考虑另一种组织逻辑的方式。这个示例没有处理错误的用户输入,并且没有对结果进行漂亮的打印。distance 类型以最低单位(毫米)保存值,类似于 time 包中的 Duration

package main

import (
	"fmt"
)

type unit byte

const (
	mm unit = 0
	cm unit = 1
	m  unit = 2
	km unit = 3

	inputUnitsMsg = "1-毫米转换为\n2-厘米转换为\n3-米转换为\n4-千米转换为\n请选择操作:"
	inputAmountMsg = "请输入要转换的数字:"
)


type unitWithAmount [4]int

type distance int

func newUnitWithAmount(u unit, amount int) unitWithAmount {
	var out [4]int
	out[u] = amount
	return out
}

func newDistance(uwa unitWithAmount) distance {
	return distance(uwa[mm] + uwa[cm]*10 + uwa[m]*1000 + uwa[km]*1000000)
}

func (d distance) convert(u unit) int {
	switch u {
	case mm:
		return d.mm()
	case cm:
		return d.cm()
	case m:
		return d.m()
	case km:
		return d.km()
	}
	return -1
}

func (d distance) mm() int {
	return int(d)
}

func (d distance) cm() int {
	return int(d) / 10
}

func (d distance) m() int {
	return int(d) / 1000
}

func (d distance) km() int {
	return int(d) / 1000000
}

func main() {
	var from, to, amount int
	fmt.Println("欢迎使用 GO METER 应用")
	fmt.Print(inputUnitsMsg)
	fmt.Scanln(&from)
	fmt.Print(inputUnitsMsg)
	fmt.Scanln(&to)
	fmt.Print(inputAmountMsg)
	fmt.Scanln(&amount)

	// 用户输入转换为切片索引
	from--
	to--

	// 要转换的单位和数量
	uwa := newUnitWithAmount(unit(from), amount)

	// 转换为的单位
	u := unit(to)

	d := newDistance(uwa)
	fmt.Println(d.convert(u))
}
英文:

Since it is an exercise you can look at another way to organise this logic. This example does not handle wrong user inputs and has no pretty printing of the result. distance type holds value in lowest unit (mm), similar to how time package does with Duration.

package main
import (
&quot;fmt&quot;
)
type unit byte
const (
mm unit = 0
cm unit = 1
m  unit = 2
km unit = 3
inputUnitsMsg = &quot;1-Milimeter to\n2-Centimeter to\n3-Meter to\n4-Kilometer to\nPlease choose an operation: &quot;
inputAmountMsg = &quot;Enter the number you want to convert: &quot;
)
type unitWithAmount [4]int
type distance int
func newUnitWithAmount(u unit, amount int) unitWithAmount {
var out [4]int
out[u] = amount
return out
}
func newDistance(uwa unitWithAmount) distance {
return distance(uwa[mm] + uwa[cm]*10 + uwa[m]*1000 + uwa[km]*1000000)
}
func (d distance) convert(u unit) int {
switch u {
case mm:
return d.mm()
case cm:
return d.cm()
case m:
return d.m()
case km:
return d.km()
}
return -1
}
func (d distance) mm() int {
return int(d)
}
func (d distance) cm() int {
return int(d) / 10
}
func (d distance) m() int {
return int(d) / 1000
}
func (d distance) km() int {
return int(d) / 1000000
}
func main() {
var from, to, amount int
fmt.Println(&quot;Welcome to GO METER app&quot;)
fmt.Print(inputUnitsMsg)
fmt.Scanln(&amp;from)
fmt.Print(inputUnitsMsg)
fmt.Scanln(&amp;to)
fmt.Print(inputAmountMsg)
fmt.Scanln(&amp;amount)
// user input to slice index
from--
to--
// unit with amount which we want to convert
uwa := newUnitWithAmount(unit(from), amount)
// to what unit we are converting
u := unit(to)
d := newDistance(uwa)
fmt.Println(d.convert(u))
}

答案2

得分: 1

有很多改进我们可以对这个程序进行。

  1. 不要使用全局变量。它们使代码更难理解和难以测试。

  2. 给函数起有意义的名称,描述函数的功能。目前它们描述的是它们被调用的时间,这相当晦涩(secondStagethirdStage)。

  3. 在出现错误的情况下返回错误并以非零退出。

  4. 考虑用户界面(UI)。我们能否改进它?也许改进界面也会使代码更易读。目前我们有以下界面:

Welcome to GO METER app
1-Milimeter to
2-Centimeter to
3-Meter to
4-Kilometer to
Please choose an operation: 1              // 1
1-to Milimeter
2-to Centimeter
3-to Meter
4-kilometer to
Please choose an operation: 4              // 2
Enter the number you want to convert: 3    // 3
3 Milimeters Equals 3e-06 Kilometers

用户需要输入一个数字并按下回车键3次(上面用注释标记)。在这3个数据输入中,有2个数字实际上是用来选择要做什么的,而一个数字是真正的输入。

如果我们考虑程序的目标,可以用更直接的方式实现相同的目标,就像从文本查询中获得的转换一样:3 mm to km 将回答 3e-6。我们将简化这个查询,去掉 to,只保留:3 mm km

对于上面的请求,我们将得到类似以下的结果:

Welcome to GO METER app
Usage: &lt;N&gt; &lt;from-unit&gt; &lt;to-unit&gt;
Where &lt;N&gt; is a number and &lt;from-unit&gt;, &lt;to-unit&gt; are one of mm, cm, m, km.
-&gt; 3 mm km
0.000003 km
  1. 如何简化逻辑?

关键是我们可以使用查找表:

// To convert &lt;n&gt; &lt;from-unit&gt; to &lt;to-unit&gt;:
// q := n * fromUnit.UtoM * toUnit.MtoU
var units = map[string]struct {
	UtoM float64 // unit to meter
	MtoU float64 // meter to unit
}{
	"mm": {1e-3, 1e+3},
	"cm": {1e-2, 1e+2},
	"m":  {1, 1},
	"km": {1e+3, 1e-3},
}

将所有这些内容结合起来,包括完整的错误处理:

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

// This looks like a global variable, but we actually treat it as a constant lookup table.
// To convert &lt;n&gt; &lt;from-unit&gt; to &lt;to-unit&gt;:
// q := n * fromUnit.UtoM * toUnit.MtoU
var units = map[string]struct {
	UtoM float64 // unit to meter
	MtoU float64 // meter to unit
}{
	"mm": {1e-3, 1e+3},
	"cm": {1e-2, 1e+2},
	"m":  {1, 1},
	"km": {1e+3, 1e-3},
}

func main() {
	if err := drive(); err != nil {
		fmt.Println("gometer: error:", err)
		os.Exit(1)
	}
}

func drive() error {
	fmt.Println("Welcome to GO METER app")
	fmt.Println("Usage: &lt;N&gt; &lt;from-unit&gt; &lt;to-unit&gt;")
	fmt.Println("Where &lt;N&gt; is a number and &lt;from-unit&gt;, &lt;to-unit&gt; are one of mm, cm, m, km.")
	fmt.Print("-&gt; ")

	var line string

	rd := bufio.NewReader(os.Stdin)
	line, err := rd.ReadString('\n')
	if err != nil {
		return fmt.Errorf("reading input: %s", err)
	}

	// input line:   "3 mm km"
	// tokens index:  0 1  2
	tokens := strings.Fields(line)

	if len(tokens) != 3 {
		return fmt.Errorf("got %d tokens; want 3 (%q)", len(tokens), tokens)
	}

	n, err := strconv.ParseFloat(tokens[0], 64)
	if err != nil {
		return fmt.Errorf("invalid number %q: %s", tokens[0], err)
	}

	fromUnitToken := tokens[1]
	toUnitToken := tokens[2]

	fromUnit, ok := units[fromUnitToken]
	if !ok {
		return fmt.Errorf("invalid from-unit %q", fromUnitToken)
	}
	toUnit, ok := units[toUnitToken]
	if !ok {
		return fmt.Errorf("invalid to-unit %q", toUnitToken)
	}

	q := n * fromUnit.UtoM * toUnit.MtoU

	fmt.Printf("%f %s\n", q, toUnitToken)
	return nil
}
  1. 我们还没有完成!以下增强功能留给读者作为练习。

6.1 我们真的需要询问用户吗?如果不需要,那么程序应该从命令行接受用户输入,而不是从提示符中接受。命令行可以通过 os.Args 访问。

6.2 如果需要,那么程序应该循环(类似基本计算器),而不是在第一次转换后退出。在交互式输入上循环的惯用方式是使用 bufio.Scanner。例如,参考 https://yourbasic.org/golang/read-file-line-by-line/。顺便说一下,https://yourbasic.org 上的所有内容都非常好。

  1. 测试。思考如何测试(写测试,而不是手动测试)这段代码。一个很好的起点是 https://quii.gitbook.io/learn-go-with-tests/

  2. 提高对 Go 的熟练程度。我建议在 https://exercism.org 上参加 Go 训练。

英文:

There are many improvements that we can do to this program.

  1. Do not use global variables. They make the code harder to understand and untestable.

  2. Give meaningful names to the functions, names that describe what the functions do. Currently they describe when they are called, which is quite opaque (secondStage, thirdStage).

  3. Return errors and exit non-zero in case of errors.

  4. Think about the UI (the User Interface). Can we make it better? Maybe making it better will also make the code more readable. Currently we have, for example:

Welcome to GO METER app
1-Milimeter to
2-Centimeter to
3-Meter to
4-Kilometer to
Please choose an operation: 1              // 1
1-to Milimeter
2-to Centimeter
3-to Meter
4-kilometer to
Please choose an operation: 4              // 2
Enter the number you want to convert: 3    // 3
3 Milimeters Equals 3e-06 Kilometers

The user has to enter a number and hit enter 3 times (marked above as comments). Of these 3 data entries, 2 numbers are actually to choose what to do and one number is the real input.

If we think about what is the goal of the program, the same can be obtained in a more straightforward way, like the conversion you get from a textual Google query: 3 mm to km will answer 3e-6. We will simplify this query removing the to, thus keeping: 3 mm km.

For the same request as above, we would get something like:

Welcome to GO METER app
Usage: &lt;N&gt; &lt;from-unit&gt; &lt;to-unit&gt;
Where &lt;N&gt; is a number and &lt;from-unit&gt;, &lt;to-unit&gt; are one of mm, cm, m, km.
-&gt; 3 mm km
0.000003 km
  1. How to simplify the logic?

The insight is that we can use a lookup table:

// To convert &lt;n&gt; &lt;from-unit&gt; to &lt;to-unit&gt;:
// q := n * fromUnit.UtoM * toUnit.MtoU
var units = map[string]struct {
	UtoM float64 // unit to meter
	MtoU float64 // meter to unit
}{
	&quot;mm&quot;: {1e-3, 1e+3},
	&quot;cm&quot;: {1e-2, 1e+2},
	&quot;m&quot;:  {1, 1},
	&quot;km&quot;: {1e+3, 1e-3},
}

Putting all this together, with full error handling:

package main

import (
	&quot;bufio&quot;
	&quot;fmt&quot;
	&quot;os&quot;
	&quot;strconv&quot;
	&quot;strings&quot;
)

// This looks like a global variable, but we actually treat it as a constant lookup table.
// To convert &lt;n&gt; &lt;from-unit&gt; to &lt;to-unit&gt;:
// q := n * fromUnit.UtoM * toUnit.MtoU
var units = map[string]struct {
	UtoM float64 // unit to meter
	MtoU float64 // meter to unit
}{
	&quot;mm&quot;: {1e-3, 1e+3},
	&quot;cm&quot;: {1e-2, 1e+2},
	&quot;m&quot;:  {1, 1},
	&quot;km&quot;: {1e+3, 1e-3},
}

func main() {
	if err := drive(); err != nil {
		fmt.Println(&quot;gometer: error:&quot;, err)
		os.Exit(1)
	}
}

func drive() error {
	fmt.Println(&quot;Welcome to GO METER app&quot;)
	fmt.Println(&quot;Usage: &lt;N&gt; &lt;from-unit&gt; &lt;to-unit&gt;&quot;)
	fmt.Println(&quot;Where &lt;N&gt; is a number and &lt;from-unit&gt;, &lt;to-unit&gt; are one of mm, cm, m, km.&quot;)
	fmt.Print(&quot;-&gt; &quot;)

	var line string

	rd := bufio.NewReader(os.Stdin)
	line, err := rd.ReadString(&#39;\n&#39;)
	if err != nil {
		return fmt.Errorf(&quot;reading input: %s&quot;, err)
	}

	// input line:   &quot;3 mm km&quot;
	// tokens index:  0 1  2
	tokens := strings.Fields(line)

	if len(tokens) != 3 {
		return fmt.Errorf(&quot;got %d tokens; want 3 (%q)&quot;, len(tokens), tokens)
	}

	n, err := strconv.ParseFloat(tokens[0], 64)
	if err != nil {
		return fmt.Errorf(&quot;invalid number %q: %s&quot;, tokens[0], err)
	}

	fromUnitToken := tokens[1]
	toUnitToken := tokens[2]

	fromUnit, ok := units[fromUnitToken]
	if !ok {
		return fmt.Errorf(&quot;invalid from-unit %q&quot;, fromUnitToken)
	}
	toUnit, ok := units[toUnitToken]
	if !ok {
		return fmt.Errorf(&quot;invalid to-unit %q&quot;, toUnitToken)
	}

	q := n * fromUnit.UtoM * toUnit.MtoU

	fmt.Printf(&quot;%f %s\n&quot;, q, toUnitToken)
	return nil
}
  1. We are not done yet! The following enhancements are left as an exercise to the reader.

6.1 Do we really need to ask the user anything? If not, then the program should accept the user input from the command-line, not from a prompt. The command-line is accessible with os.Args.

6.2 If yes, then the program should loop (a sort of basic calculator), instead of exiting after the first conversion. The idiomatic way to loop on interactive input is to use bufio.Scanner. See for example https://yourbasic.org/golang/read-file-line-by-line/. By the way, everything on https://yourbasic.org is very good.

  1. Testing. Think how you can test (in the sense: write tests, not manual tests) this code. A good starting point is https://quii.gitbook.io/learn-go-with-tests/

  2. Becoming proficient with Go in general. I suggest the Go track at https://exercism.org/

答案3

得分: 0

你可以使用数组或映射,这里有一个使用数组的示例:

type args struct {
	number        float64
	km, m, cm, mm string
}

var choiceArray = [5][5]func(args){
	1: {
		1: func(a args) { fmt.Println(a.number, a.mm, "等于", a.number, a.mm) },
		2: func(a args) { fmt.Println(a.number, a.mm, "等于", a.number/10, a.cm) },
		3: func(a args) { fmt.Println(a.number, a.mm, "等于", a.number/1000, a.m) },
		4: func(a args) { fmt.Println(a.number, a.mm, "等于", a.number/1000000, a.km) },
	},
	2: {
		1: func(a args) { fmt.Println(a.number, a.cm, "等于", a.number*10, a.m) },
		2: func(a args) { fmt.Println(a.number, a.cm, "等于", a.number, a.cm) },
		3: func(a args) { fmt.Println(a.number, a.cm, "等于", a.number/100, a.m) },
		4: func(a args) { fmt.Println(a.number, a.cm, "等于", a.number/100000, a.km) },
	},
	3: {
		1: func(a args) { fmt.Println(a.number, a.m, "等于", a.number*1000, a.mm) },
		2: func(a args) { fmt.Println(a.number, a.m, "等于", a.number*100, a.cm) },
		3: func(a args) { fmt.Println(a.number, a.m, "等于", a.number, a.m) },
		4: func(a args) { fmt.Println(a.number, a.m, "等于", a.number/1000, a.km) },
	},
	4: {
		1: func(a args) { fmt.Println(a.number, a.km, "等于", a.number*1000000, a.mm) },
		2: func(a args) { fmt.Println(a.number, a.km, "等于", a.number*100000, a.cm) },
		3: func(a args) { fmt.Println(a.number, a.km, "等于", a.number*1000, a.mm) },
		4: func(a args) { fmt.Println(a.number, a.km, "等于", a.number, a.km) },
	},
}
func thirdStage() {
	a := args{
		mm: "毫米",
		cm: "厘米",
		m:  "米",
		km: "千米",
	}

	fmt.Print("输入要转换的数字:")
	fmt.Scanln(&a.number)
	
    choiceArray[firstUserChoice][secondUserChoice](a)
}
英文:

You can use an array or a map, here's an example with an array:

type args struct {
	number        float64
	km, m, cm, mm string
}

var choiceArray = [5][5]func(args){
	1: {
		1: func(a args) { fmt.Println(a.number, a.mm, &quot;Equals&quot;, a.number, a.mm) },
		2: func(a args) { fmt.Println(a.number, a.mm, &quot;Equals&quot;, a.number/10, a.cm) },
		3: func(a args) { fmt.Println(a.number, a.mm, &quot;Equals&quot;, a.number/1000, a.m) },
		4: func(a args) { fmt.Println(a.number, a.mm, &quot;Equals&quot;, a.number/1000000, a.km) },
	},
	2: {
		1: func(a args) { fmt.Println(a.number, a.cm, &quot;Equals&quot;, a.number*10, a.m) },
		2: func(a args) { fmt.Println(a.number, a.cm, &quot;Equals&quot;, a.number, a.cm) },
		3: func(a args) { fmt.Println(a.number, a.cm, &quot;Equals&quot;, a.number/100, a.m) },
		4: func(a args) { fmt.Println(a.number, a.cm, &quot;Equals&quot;, a.number/100000, a.km) },
	},
	3: {
		1: func(a args) { fmt.Println(a.number, a.m, &quot;Equals&quot;, a.number*1000, a.mm) },
		2: func(a args) { fmt.Println(a.number, a.m, &quot;Equals&quot;, a.number*100, a.cm) },
		3: func(a args) { fmt.Println(a.number, a.m, &quot;Equals&quot;, a.number, a.m) },
		4: func(a args) { fmt.Println(a.number, a.m, &quot;Equals&quot;, a.number/1000, a.km) },
	},
	4: {
		1: func(a args) { fmt.Println(a.number, a.km, &quot;Equals&quot;, a.number*1000000, a.mm) },
		2: func(a args) { fmt.Println(a.number, a.km, &quot;Equals&quot;, a.number*100000, a.cm) },
		3: func(a args) { fmt.Println(a.number, a.km, &quot;Equals&quot;, a.number*1000, a.mm) },
		4: func(a args) { fmt.Println(a.number, a.km, &quot;Equals&quot;, a.number, a.km) },
	},
}
func thirdStage() {
	a := args{
		mm: &quot;Milimeters&quot;,
		cm: &quot;Centimeters&quot;,
		m:  &quot;Meters&quot;,
		km: &quot;Kilometers&quot;,
	}

	fmt.Print(&quot;Enter the number you want to convert: &quot;)
	fmt.Scanln(&amp;a.number)
	
    choiceArray[firstUserChoice][secondUserChoice](a)
}

答案4

得分: 0

你可以在switch语句中使用任何类型的组合值,包括非整数值,例如:

package main

import (
	"fmt"
)

func main() {
	first := 2
	second := 1

	v1 := fmt.Sprintf("%d.%d", first, second)
	switch v1 {
	case "1.1":
		fmt.Println("case 1.1")
	case "1.2":
		fmt.Println("case 1.2")
	case "2.1":
		fmt.Println("case 2.1")
	case "2.2":
		fmt.Println("case 2.2")
	default:
		fmt.Println("default")
	}
	
	v2 := 10*(first-1) + second
	switch v2 {
	case 1:
		fmt.Println("case 1/1")
	case 2:
		fmt.Println("case 1/2")
	case 11:
		fmt.Println("case 2/1")
	case 12:
		fmt.Println("case 2/2")
	default:
		fmt.Println("default")
	}
}

你还可以考虑将常见操作从条件语句中提取出来,例如:

if firstUserChoice <= 4 {
   secondStage()
} else {
   fmt.Println("INVALID CHOICE")
   secondStage()
}

可以改写为:

if firstUserChoice > 4 {
     fmt.Println("INVALID CHOICE")
}
secondStage()
英文:

You can use any sort of combined values for switch, including non-integer, e.g.

package main

import (
	&quot;fmt&quot;
)

func main() {
	first := 2
	second := 1

	v1 := fmt.Sprintf(&quot;%d.%d&quot;, first, second)
	switch v1 {
	case &quot;1.1&quot;:
		fmt.Println(&quot;case 1.1&quot;)
	case &quot;1.2&quot;:
		fmt.Println(&quot;case 1.2&quot;)
	case &quot;2.1&quot;:
		fmt.Println(&quot;case 2.1&quot;)
	case &quot;2.2&quot;:
		fmt.Println(&quot;case 2.2&quot;)
	default:
		fmt.Println(&quot;default&quot;)
	}
	
	v2 := 10*(first-1) + second
	switch v2 {
	case 1:
		fmt.Println(&quot;case 1/1&quot;)
	case 2:
		fmt.Println(&quot;case 1/2&quot;)
	case 11:
		fmt.Println(&quot;case 2/1&quot;)
	case 12:
		fmt.Println(&quot;case 2/2&quot;)
	default:
		fmt.Println(&quot;default&quot;)
	}
}

You can also consider taking common actions out of conditions, i.e.

if firstUserChoice &lt;= 4 {
secondStage()
} else {
fmt.Println(&quot;INVALID CHOICE&quot;)
secondStage()
}

becoming

if firstUserChoice &gt; 4 {
fmt.Println(&quot;INVALID CHOICE&quot;)
}
secondStage()

答案5

得分: 0

根据mkopriva的说法,你可以使用arraymap

为了提高可读性,可以添加Enum

package main

import (
  "fmt"
  "os"
)

const (
  mm int = iota + 1
  cm
  m
  km
)

var mapping_length = map[int]string{
  mm : "毫米",
  cm : "厘米",
  m  : "米",
  km : "千米",
}

var choicesMap = map[int]map[int]func(float64)(float64) {
 mm: {
   mm: func(num float64) float64 {
     return num
   },
   cm: func(num float64) float64 {
     return num / 10
   },
   m: func(num float64) float64 {
     return num / 1000
   },
   km: func(num float64) float64 {
     return num / 1000000
   },
 },
 cm: {
   mm: func(num float64) float64 {
     return num * 10
   },
   cm: func(num float64) float64 {
     return num
   },
   m: func(num float64) float64 {
     return num / 100
   },
   km: func(num float64) float64 {
     return num / 100000
   },
 },
 m: {
   mm: func(num float64) float64 {
     return num * 1000
   },
   cm: func(num float64) float64 {
     return num * 100
   },
   m: func(num float64) float64 {
     return num
   },
   km: func(num float64) float64 {
     return num / 1000
   },
 },
 km: {
   mm: func(num float64) float64 {
     return num * 1000000
   },
   cm: func(num float64) float64 {
     return num * 100000
   },
   m: func(num float64) float64 {
     return num * 1000
   },
   km: func(num float64) float64 {
     return num
   },
 },
}

func getChoice() int {
	fmt.Print("1: 毫米转换为\n2: 厘米转换为\n3: 米转换为\n4: 千米转换为\n请选择操作:")
  var userChoice int
  fmt.Scanln(&userChoice)
  return userChoice
}

func main()  {
   fmt.Println("欢迎使用 GO METER 应用程序")

   var firstUserChoice = getChoice()
   if firstUserChoice > 4 {
     fmt.Println("无效的选择")
     os.Exit(0)
   }

   var secondUserChoice = getChoice()
   if secondUserChoice > 4 {
     fmt.Println("无效的选择")
     os.Exit(0)
   }

   var number float64
   fmt.Print("请输入要转换的数字:")
   fmt.Scanln(&number)

   var result = choicesMap[firstUserChoice][secondUserChoice](number)

   fmt.Println(number, mapping_length[firstUserChoice], "等于", result, mapping_length[secondUserChoice])
}
英文:

As stated by mkopriva you can use array and map.

Enum can be added for improving readability.

package main

import (
  &quot;fmt&quot;
  &quot;os&quot;
)

const (
  mm int = iota + 1
  cm
  m
  km
)

var mapping_length = map[int]string{
  mm : &quot;Milimeters&quot;,
  cm : &quot;Centimeters&quot;,
  m  : &quot;Meters&quot;,
  km : &quot;Kilometers&quot;,
}

// var choicesArray = [][]func(float64)(float64) {
//  mm: {
//    mm: func(num float64) float64 {
//      return num
//    },
//    cm: func(num float64) float64 {
//      return num / 10
//    },
//    m: func(num float64) float64 {
//      return num / 1000
//    },
//    km: func(num float64) float64 {
//      return num / 1000000
//    },
//  },
//  cm: {
//    mm: func(num float64) float64 {
//      return num * 10
//    },
//    cm: func(num float64) float64 {
//      return num
//    },
//    m: func(num float64) float64 {
//      return num / 100
//    },
//    km: func(num float64) float64 {
//      return num / 100000
//    },
//  },
//  m: {
//    mm: func(num float64) float64 {
//      return num * 1000
//    },
//    cm: func(num float64) float64 {
//      return num * 100
//    },
//    m: func(num float64) float64 {
//      return num
//    },
//    km: func(num float64) float64 {
//      return num / 1000
//    },
//  },
//  km: {
//    mm: func(num float64) float64 {
//      return num * 1000000
//    },
//    cm: func(num float64) float64 {
//      return num * 100000
//    },
//    m: func(num float64) float64 {
//      return num * 1000
//    },
//    km: func(num float64) float64 {
//      return num
//    },
//  },
// }

var choicesMap = map[int]map[int]func(float64)(float64) {
 mm: {
   mm: func(num float64) float64 {
     return num
   },
   cm: func(num float64) float64 {
     return num / 10
   },
   m: func(num float64) float64 {
     return num / 1000
   },
   km: func(num float64) float64 {
     return num / 1000000
   },
 },
 cm: {
   mm: func(num float64) float64 {
     return num * 10
   },
   cm: func(num float64) float64 {
     return num
   },
   m: func(num float64) float64 {
     return num / 100
   },
   km: func(num float64) float64 {
     return num / 100000
   },
 },
 m: {
   mm: func(num float64) float64 {
     return num * 1000
   },
   cm: func(num float64) float64 {
     return num * 100
   },
   m: func(num float64) float64 {
     return num
   },
   km: func(num float64) float64 {
     return num / 1000
   },
 },
 km: {
   mm: func(num float64) float64 {
     return num * 1000000
   },
   cm: func(num float64) float64 {
     return num * 100000
   },
   m: func(num float64) float64 {
     return num * 1000
   },
   km: func(num float64) float64 {
     return num
   },
 },
}

func getChoice() int {
	fmt.Print(&quot;1: Milimeter to\n2: Centimeter to\n3: Meter to\n4: Kilometer to\nPlease choose an operation: &quot;)
  var userChoice int
  fmt.Scanln(&amp;userChoice)
  return userChoice
}

func main()  {
   fmt.Println(&quot;Welcome to GO METER app&quot;)

   var firstUserChoice = getChoice()
   if firstUserChoice &gt; 4 {
     fmt.Println(&quot;INVALID CHOICE&quot;)
     os.Exit(0)
   }

   var secondUserChoice = getChoice()
   if secondUserChoice &gt; 4 {
     fmt.Println(&quot;INVALID CHOICE&quot;)
     os.Exit(0)
   }

   var number float64
   fmt.Print(&quot;Enter the number you want to convert: &quot;)
   fmt.Scanln(&amp;number)

   // Array
   // var result = choicesArray[firstUserChoice][secondUserChoice](number)
   // Map
   var result = choicesMap[firstUserChoice][secondUserChoice](number)

   fmt.Println(number, mapping_length[firstUserChoice], &quot;Equals&quot;, result, mapping_length[secondUserChoice])
}

huangapple
  • 本文由 发表于 2021年9月11日 20:11:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/69142900.html
匿名

发表评论

匿名网友

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

确定