在结构中设置一个值失败。

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

Setting a value in structure fails

问题

我在结构体中设置了值,但是没有生效。方法是按顺序调用的,而不是并行调用的。这是使用golang编写的代码,我忘了提醒你了。

如果我将代码更改为在"start"方法中设置值(而不是"init"方法),它可以正常工作;但是在"init"方法中设置值会失败。对我来说看起来非常奇怪。

以下是代码:

package main

import (
	"log"
	"net/http"
	"time"
)

type tServer struct {
	ipAddress string
	port      string
	server    http.Server
}

var server tServer

func main() {
	server.ipAddress = "0.0.0.0"
	server.port = "12345"
	server.init()
	server.start()
	time.Sleep(time.Second * 5)
}

func (srv tServer) init() {
	srv.server.Addr = srv.ipAddress + ":" + srv.port
	log.Println("srv.server.Addr=", srv.server.Addr) ////////////////////
}

func (srv tServer) start() {
	log.Println("srv.server.Addr=", srv.server.Addr) ////////////////////
	go srv.startServerRoutine()
}

func (srv tServer) startServerRoutine() {
	log.Println("Server started at", srv.server.Addr) //
	err := srv.server.ListenAndServe()
	if err != nil {
		log.Println("Server Error:", err) //
		return
	}
}

这是控制台输出:

2017/04/18 19:43:07 srv.server.Addr= 0.0.0.0:12345
2017/04/18 19:43:07 srv.server.Addr= 
2017/04/18 19:43:07 Server started at 
2017/04/18 19:43:07 Server Error: listen tcp :80: bind: permission denied

请注意,根据你的代码,我无法提供关于为什么在"init"方法中设置值失败的具体原因。但是,根据输出结果,可以看出在"start"方法中设置值是有效的,而在"init"方法中设置值则失败了。

英文:

I set the value in the structure, but it is not set. The methods are called consequently, not in parallel. How can that be? This is golang, forgot to say.

If I change the code to set value in the "start" method (instead of "init" method), it works; but setting value in "init" method fails. Looks very strange to me.

package main

import (
    "log"
    "net/http"
    "time"
)

type tServer struct {
    ipAddress string
    port      string
    server    http.Server
}

var server tServer

func main() {
    server.ipAddress = "0.0.0.0"
    server.port = "12345"
    server.init()
    server.start()
    time.Sleep(time.Second * 5)
}

func (srv tServer) init() {
    srv.server.Addr = srv.ipAddress + ":" + srv.port
    log.Println("srv.server.Addr=", srv.server.Addr) ////////////////////
}

func (srv tServer) start() {
    log.Println("srv.server.Addr=", srv.server.Addr) ////////////////////
    go srv.startServerRoutine()
}

func (srv tServer) startServerRoutine() {
    log.Println("Server started at", srv.server.Addr) //
    err := srv.server.ListenAndServe()
    if err != nil {
	    log.Println("Server Error:", err) //
	    return
    }
}

Here is the console:

2017/04/18 19:43:07 srv.server.Addr= 0.0.0.0:12345
2017/04/18 19:43:07 srv.server.Addr= 
2017/04/18 19:43:07 Server started at 
2017/04/18 19:43:07 Server Error: listen tcp :80: bind: permission denied

答案1

得分: 4

这是由于方法的原型:

func (srv tServer) init()
    // ^^^ 复制值

所以:

server.init()   // 更新自己的 server 副本,
                // 副本在 init() 返回后被丢弃

server.start()  // 使用自己的 server 副本

你需要通过指针将 srv 传递给方法:

func (srv *tServer) init()

在这种情况下,init()start() 调用将在同一个 tServer 结构的副本上工作,并共享其字段中的值。

英文:

This is due to prototype of methods:

func (srv tServer) init()
    // ^^^ copies values 

so:

server.init()   // updates its own copy of server, 
                // copy gets disposed after init() returns

server.start()  // uses its own copy of server

You need to pass srv by pointer to methods:

func (srv *tServer) init()

in that case both init() and start() calls will work on the same copy of tServer structure and will share values in its fields.

答案2

得分: 1

如果你查看http.Server的文档,你会发现可以使用空值,表示":http":

type Server struct {
       Addr      string      // TCP address to listen on, ":http" if empty
}

你在init()函数中直接设置了srv.server.Addr,但这不是正确使用http.Server类型的方式。

也许你的意思是这样做:

func (srv tServer) startServerRoutine() {
    log.Println("Server started at", srv.ipAddress + ":" + srv.port)
    err := srv.server.ListenAndServe(srv.ipAddress + ":" + srv.port)
    if err != nil {
        log.Println("Server Error:", err)
        return
    }
}
英文:

If you look at the docs for http.Server you will see that a blank value is possible, and means ":http":

type Server struct {
       Addr      string      // TCP address to listen on, ":http" if empty

You set srv.server.Addr directly in init(), but this is not the proper way to use the http.Server type.

Perhaps you meant to do this:

func (srv tServer) startServerRoutine() {
    log.Println("Server started at", srv.ipAddress + ":" + srv.port) //
    err := srv.server.ListenAndServe(srv.ipAddress + ":" + srv.port)
    if err != nil {
        log.Println("Server Error:", err) //
        return
    }
}

huangapple
  • 本文由 发表于 2017年4月19日 00:56:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/43478050.html
匿名

发表评论

匿名网友

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

确定