我目前正在研究一个学习Golang的个人项目,但是当我开始使用Goroutines时遇到了一些问题,我认为有些概念我并没有正确理解。简而言之,我的代码具有一个带有接收器函数“循环”的结构,该结构在无限循环中每10秒执行一次处理,直到程序终止,该程序已经起作用。现在,我想添加一个简单的Web服务器,在循环运行时,我需要从中更新结构中的某些数据,这是我用来测试该案例的问题的抽象:
package main
import (
"fmt"
"net/http"
"../thing"
)
var Thing1 thing.Thing
func main() {
Thing1 := thing.NewThing("thing1")
//This is the loop that is always running
go Thing1.Loop()
http.HandleFunc("/", HelloServer)
http.ListenAndServe(":8080", nil)
}
func HelloServer(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.Error(w, "404 Not found", http.StatusNotFound)
return
}
switch r.Method {
case "GET":
http.ServeFile(w, r, "index.html")
case "POST":
if err := r.ParseForm(); err != nil {
fmt.Fprintf(w, "There was an error with the form: %v", err)
return
}
fmt.Println("In handler: " + r.FormValue("fData"))
Thing1.UpdateData(r.FormValue("fData"))
http.ServeFile(w, r, "index.html")
default:
http.Error(w, "405 Method not allowed", http.StatusMethodNotAllowed)
}
}
package thing
import (
"fmt"
"time"
)
type Thing struct {
ID string
data string
}
func NewThing(id string) Thing {
return Thing{ID: id}
}
func (t *Thing) Loop() {
for {
now := time.Now().Format("15:04:05")
fmt.Println(t.ID + " starts at " + now)
fmt.Println(t.ID + " Data: " + t.data)
time.Sleep(time.Second * 10)
}
}
func (t *Thing) UpdateData(g string) {
t.data = g
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test</title>
</head>
<body>
<p>Test control panel</p>
<form method="POST" action="/">
<label>Data</label><input type="text" name="fData" value="">
<input type="submit" value="submit">
</form>
</body>
</html>
基本上,当我按下提交按钮时,我想更新struct Things1中的“data”变量,当在循环内打印data变量时,这应该反映出来,但是它不起作用,data变量总是打印为空的。我不知道自己在做什么错,但是我想我缺少关于goroutine的一些基本概念。
任何建议将不胜感激。
最佳答案
在main
中,您首先开始:
Thing1 := thing.NewThing("thing1")
这将定义一个名为
Thing1
的新局部变量,就像您编写的一样:var Thing1 Thing
然后将变量设置为
thing.NewThing
的结果:Thing1 = thing.NewThing("thing1")
同时,您的函数
HelloServer
并未定义任何名为Thing1
的新变量,而是使用了外部(包)作用域Thing1
—一个不同的结构实例,ID = ""
(空字符串)和data = ""
。调用Thing1.UpdateData(r.FormValue("fData"))
时,会将空Thing1
的地址传递给UpdateData
接收器函数。这个未命名的Thing1
对象会更新其数据,而您的循环使用ID为Thing1
的"thing1"
。修复起来很容易:只是不要在main中创建新的
Thing1
。但是,作为JimB noted in a comment,您也不会同步数据更新和数据访问。如果要通过共享进行通信,则需要某种锁定。(Go encourages sharing by communicating, rather than communicating by sharing.但是,这需要不同的思维方式。)