我的程序“猴子”用Go写成,可以接收这样的文件:
并打印输出(在上述“文件”、“22”和“5”的情况下)。变量也可以声明为表达式。在这个“文件”中:
*5 4:a+a 2:a
变量a以22结尾,因为首先我们将其赋值给5*4 (20),然后添加2 (22)。
这是该程序的源代码,这里是带有语法高亮显示的。
package main
import (
"bufio"
"fmt"
"os"
"strings"
"strconv"
)
// error management
func check(e error) {
if e != nil {
panic(e)
}
}
func openfile(filename string) (lines []string) {
// safely open file
source, err := os.Open(filename)
check(err)
scanner := bufio.NewScanner(source)
// equivalent to a while loop
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return
}
var variables map[string]float32
// determine whether a token is a variable reference or
// an integer literal, and return it.
func getvalue(item string) float32 {
// if item is number
if num, err := strconv.Atoi(item); err == nil {
return float32(num)
}
return variables[item]
}
func operate(operands []string, op string) float32 {
var result float32 = 0
// o = index in operands[]
for o := 0; o < len(operands); o++ {
if op == "+" {
if o == 0 {
result = getvalue(operands[0])
} else {
result += getvalue(operands[o])
}
} else if op == "-" {
if o == 0 {
result = getvalue(operands[0])
} else {
result -= getvalue(operands[o])
}
} else if op == "*" {
if o == 0 {
result = getvalue(operands[0])
} else {
result *= getvalue(operands[o])
}
} else if op == "/" {
if o == 0 {
result = getvalue(operands[0])
} else {
result /= getvalue(operands[o])
}
} else {
return 0.0
}
}
return result
}
var x, y int64 // these will be assigned to function params
var xerr, yerr error
func main() {
variables = make(map[string]float32)
lines := openfile(os.Args[1])
for lineNumber, line := range lines {
words := strings.Split(line, " ")
operands := 0 // count of numbers that the operation will be applied to
for _, word := range words {
if _, err := strconv.Atoi(word); err == nil {
operands += 1
}
}
// line needs to end in ';' or ': varName' to be correct
if len(words) >= operands + 2 {
if words[operands + 1] == ";" {
fmt.Println(operate(words[1:operands+1], words[0]))
} else if words[operands + 1] == ":" {
fmt.Println("var", words[operands + 2], "=", operate(words[1:operands+1], words[0]))
variables[words[operands + 2]] = operate(words[1:operands+1], words[0])
}
} else if len(words) < 0 && len(words) < operands + 2 {
fmt.Println("error: not enough arguments at line", lineNumber)
}
}
}发布于 2014-07-02 06:01:33
作为一种通用的命名约定,go方法被命名为LikeThis (用于公共方法)或likeThis (用于包私有方法)。对于这样一个小的、单一的文件项目来说,这并不太重要,但是不管怎么说,这是一个很好的习惯。
您的openfile方法可能应该命名为readFile,因为它不只是打开文件,它还读取文件中的每一行。此外,当您完成该文件时,您会忘记关闭它。Go有一种相当干净的方法来确保这种情况永远发生:defer关键字:
func readFile(filename string) (lines []string) {
source, err := os.Open(filename)
defer source.Close() // Make sure we close the file
...
}可以更清晰地编写operate函数;第一,通过确认每个分支中的大小写if o == 0完全相同,其次使用switch语句(在go中更惯用):
func operate(operands []string, op string) float32 {
result := getvalue(operands[0])
for o := range operands[1:] {
switch op {
case "+": result += getvalue(o)
case "-": result -= getvalue(o)
case "*": result *= getvalue(o)
case "/": result /= getvalue(o)
default: return 0.0
}
}
return result
}这里,我们将结果初始化为操作数中的第一个值。然后,我们对操作数中的其余元素进行了调整。这使用range,当您可以使用它们时,它应该比手动for循环更好,并且还可以分割切片的第一个元素。
注意,go不需要switch中的break语句,而是需要一个显式的fallthrough (在使用switch语句时可能会停止最大的bug类)。
https://codereview.stackexchange.com/questions/55508
复制相似问题