使用golang进行函数式编程 (怎么用golang弄一个数据计算器)

以下文章来源于GoUpUp ,作者dj

简介

在之前文章中,我们介绍了一个 Go 的高颜值 GUI 库fyne。本文接着,介绍如何使用fyne编写一个简单的计算器程序。程序效果如下:

使用GoGUI库fyne编写一个计算器程序

控件布局

我们使用widget.Entry来显示输入的数字、运算符和运算结果。先创建一个widget.Entry对象,设置可显示多行:

display:=widget.NewEntry()
display.MultiLine=true

其它数字和符号控件都用widget.Button来表示。按钮也分为两种,一种是没有特殊效果的,点击后直接在显示框中添加对应的字符即可。一种是有特殊效果的,例如清空显示框(AC)、进行计算(=)。中间三行按钮都是前一种,我们使用GridLayout来布局,每行显示 4 个:

digits:=[]string{
"7","8","9","×",
"4","5","6","-",
"1","2","3","+",
}
vardigitBtns[]fyne.CanvasObject
for_,val:=rangedigits{
digitBtns=append(digitBtns,widget.NewButton(val,input(display,val)))
}
digitContainer:=fyne.NewContainerWithLayout(
layout.NewGridLayout(4),
digitBtns...)

input回调后面介绍。

第一行有 3 个具有特殊效果的按钮:

  • AC:清空显示框;
  • +/-:切换正负号;
  • %将数字变为百分数,即除以 100。

外加一个除法按钮。这一行同样使用GridLayout布局:

clearBtn:=widget.NewButton("AC",clear(display))
signBtn:=widget.NewButton("+/-",sign(display))
percentBtn:=widget.NewButton("%",percent(display,"%"))
divideBtn:=widget.NewButton("÷",input(display,"÷"))
clearContainer:=fyne.NewContainerWithLayout(
layout.NewGridLayout(4),
clearBtn,
signBtn,
percentBtn,
divideBtn,
)

几个回调处理后面统一介绍。

最后一行由于0这个按钮宽度是其它按钮的 2 倍。我们先使用GridLayout布局,将这一行平均分成两Grid(即每行 2 个控件)。按钮0独占一个Grid,由于GridLayout布局中每个Grid大小相同,故按钮0有整个行一半的宽度。后一个Grid,按钮.和=平分,同样使用一个GridLayout达到这个效果:

zeroBtn:=widget.NewButton("0",input(display,"0"))
dotBtn:=widget.NewButton(".",input(display,"."))
equalBtn:=widget.NewButton("=",equals(display))
zeroContainer:=fyne.NewContainerWithLayout(
layout.NewGridLayout(2),
zeroBtn,
fyne.NewContainerWithLayout(
layout.NewGridLayout(2),
dotBtn,
equalBtn,
),
)

最后我们将所有部分用垂直的BoxLayout组合到一起:

container:=fyne.NewContainerWithLayout(
layout.NewVBoxLayout(),
display,
clearContainer,
digitContainer,
zeroContainer,
copyright,
)

在实际开发中,一般会组合使用多种布局实现界面效果。

按钮响应

清空按钮响应比较简单,直接将显示框的Text设置为空即可:

funcclear(display*widget.Entry)func(){
returnfunc(){
display.Text=""
display.Refresh()
}
}

注意,要调用Entry.Refresh()方法刷新界面。由于按钮响应都是对应显示框进行操作,所以都需要传入该对象。

我们设计在显示框中显示两行,第一行是上次计算的表达式,第二行是本次的。切换正负号在本次只输入一个数字时将该数字的正负号进行切换:

funcsign(display*widget.Entry)func(){
returnfunc(){
lines:=strings.Split(display.Text,"\n")
iflen(lines)==0{
return
}

line:=lines[len(lines)-1]
value,err:=strconv.ParseInt(line,10,64)
iferr!=nil{
return
}
lines[len(lines)-1]=strconv.FormatInt(-value,10)
display.Text=strings.Join(lines,"\n")
}
}

输入回调我们只做了简单的处理——将对应字符串拼接到显示框中:

funcinput(display*widget.Entry,valuestring)func(){
returnfunc(){
display.Text+=value
display.Refresh()
}
}

计算表达式的函数也很简单,我这里使用了govaluate库(可以看我之前的文章):

funcequals(display*widget.Entry)func(){
returnfunc(){
lines:=strings.Split(display.Text,"\n")
iflen(lines)==0{
return
}

line:=lines[len(lines)-1]
line=strings.Trim(line,"+÷×")
exprLine:=strings.Replace(line,"÷","/",-1)
exprLine=strings.Replace(exprLine,"×","*",-1)
expr,_:=govaluate.NewEvaluableExpression(exprLine)
result,_:=expr.Evaluate(nil)
line+="=\n"
line+=fmt.Sprint(result)
display.Text=line
display.Refresh()
}
}

注意,这里做了一点容错,把前后多余的运算符去掉了。另外,我们前面为了显示,使用了÷表示除法符号,×表示乘法符号。要使用govaluate,必须将它们分别替换为/和*。

至此计算器就编写完成了,下面我们介绍如何打包。

打包

准备好一张图片资源作为图标,放到项目目录下:

使用GoGUI库fyne编写一个计算器程序

打包:

$ fyne package -os windows -icon icon.jpg

在同目录下生成了一个*ex.e**文件和一个.syso文件。现在可直接点击calculator*ex.e**运行程序,没有其他依赖。

总结

本文介绍如何使用fyne编写一个简单的计算器程序,主要介绍如何组合使用多种布局。当然计算器功能和错误处理还不完善,而且实现偏过程式编程,感兴趣的可自行完善。完整代码在fyne/calculator中。

大家如果发现好玩、好用的 Go 语言库,欢迎到 Go 每日一库 GitHub 上提交 issue

参考

  1. fyne GitHub:https://github.com/fyne-io/fyne
  2. fyne 官网:https://fyne.io/
  3. fyne 官方入门教程:https://developer.fyne.io/tour/introduction/hello.html
  4. Go 每日一库 GitHub:https://github.com/darjun/go-daily-lib