首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Go中基于文件的方程计算

Go中基于文件的方程计算
EN

Code Review用户
提问于 2014-06-27 19:38:24
回答 1查看 51关注 0票数 4

我的程序“猴子”用Go写成,可以接收这样的文件:

  • 9 13 / 10 2

并打印输出(在上述“文件”、“22”和“5”的情况下)。变量也可以声明为表达式。在这个“文件”中:

*5 4:a+a 2:a

变量a以22结尾,因为首先我们将其赋值给5*4 (20),然后添加2 (22)。

这是该程序的源代码,这里是带有语法高亮显示的。

代码语言:javascript
复制
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)
        }
    }
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2014-07-02 06:01:33

作为一种通用的命名约定,go方法被命名为LikeThis (用于公共方法)或likeThis (用于包私有方法)。对于这样一个小的、单一的文件项目来说,这并不太重要,但是不管怎么说,这是一个很好的习惯。

您的openfile方法可能应该命名为readFile,因为它不只是打开文件,它还读取文件中的每一行。此外,当您完成该文件时,您会忘记关闭它。Go有一种相当干净的方法来确保这种情况永远发生:defer关键字:

代码语言:javascript
复制
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中更惯用):

代码语言:javascript
复制
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类)。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/55508

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档