在Go中编码的正确方法是什么?

时间:2015-12-16 16:03:11

标签: git go server revel

最近我发现Revel是一个非常好的MVC Web框架,我想尝试一下。 问题是,我是Go的新手,一切看起来都有点不同。

使用PHP时,我只是将文件放入/var/www/文件夹,或使用某些IDE,然后我可以打开浏览器并进行实时测试。使用RoR或Node.js会更容易,我只是转到本地项目文件夹(并不重要),在终端中运行一个命令,并且已经可以在localhost:3000上看到结果。 / p>

这样,我在本地机器上有以下结构:

home
└── mark
    └── code
        ├── php
        │   └── my_php_app
        └── ruby
            └── my_ruby_app

他们都通过git同步。然后,当我想在我的远程机器上部署时,我只需将它们拉入/var/www/并设置Apache2 / Nginx

但是如何使用Go应用程序执行此操作?我在家里的Linux机器和我的VPS上安装了Go。当我打开~/code/go/mygoapp并尝试使用revel run运行时,它表示在GOPATH中找不到它。所以,我认为,我需要将所有Go项目与GOPATH中的其他项目分开,可以是/usr/local/go/src/~/gocode/src/

问题是:

  1. 如果我想将go文件夹中的所有Go / Revel项目与phpruby一起放在本地计算机上,我应该怎么做:

    home
    └── mark
        └── code
            ├── go
            │   └── my_revel_app
            ├── php
            │   └── my_php_app
            └── ruby
                └── my_ruby_app
    
  2. 我如何以正确的方式在远程服务器上实际部署它们?

  3. 如果我仍然需要使用GOPATH,我如何命名包?是GOPATH/src/mygoappGOPATH/src/mark/mygoapp还是GOPATH/src/bitbucket.org/mark/mygoapp(这个回购是私有的)?

  4. 我知道,这可能是一个菜鸟问题,但我在这里看不到逻辑。即使使用简单的Go程序,我也不需要将它们放到GOPATH中来运行。

3 个答案:

答案 0 :(得分:1)

将目录(工作空间)添加到包含go source的GOPATH,并符合结构src, pkg, bin。您可以在GOPATH中拥有任意数量的工作空间。在您的系统上相应地定义变量。您服务器上的GOPATH很可能与您本地计算机上的git不同。

您可以使用GOPATH分享您的项目。在github或bitbucket上创建一个帐户,并进行同步。

您的go get指向工作区。第一个用于存储notifyIntent包。

答案 1 :(得分:1)

简介

我觉得有一些误解。让我们继续努力。

PHP和Go之间存在一些根本区别,其中一个原因是PHP是一种解释性语言,而Go则是一种编译语言。

PHP的设计对于大多数应用程序来说都是一种所谓的解释语言,这意味着每次调用PHP文件时源代码都会被转换为机器可读的指令。

另一方面,Go是一种编译语言,这意味着源代码被编译为可执行二进制文件一次,并且静态链接是默认的,导致生成的可执行文件没有依赖关系(除了操作系统)它被编译为),甚至不是Go运行时。因此,您可以构建一个自给自足的Web应用程序,包括Web服务器和(使用特殊用途的Go包)甚至资源文件,如图像和样式表。

虽然您可以使用go run filename.go,但它只是go build的快捷方式并执行生成的已编译二进制文件,因为go run --help的输出证明:

  

go run [build flags] [-exec xprog] gofiles ... [arguments ...]

     

运行编译并运行包含命名Go源文件的主包。   Go源文件被定义为以文字“.go”后缀结尾的文件。

     

默认情况下,'go run'直接运行已编译的二进制文件:'a.out arguments ...'。

实施例

我将向您展示$ GOPATH及其子目录是如何互连的。

让我们采用最简单的Web服务器示例:

package main 

import (
    "net/http"
    "fmt"
)

// Default Request Handler
func defaultHandler(w http.ResponseWriter, r *http.Request) {
      fmt.Fprintf(w, "<h1>Hello %s!</h1>", r.URL.Path[1:])
}

func main() {
    http.HandleFunc("/", defaultHandler)
    http.ListenAndServe(":8080", nil)
}

我把它放到这样的目录结构中,包括权限和文件大小。这是在OS X系统上

$GOPATH/src/github.com/mwmahlberg/DemoServer/
└── [-rw-r--r--  178]  server_main.go

现在,在DemoServer目录中调用GOOS=linux go build ./...时,在我的情况下,交叉编译二进制文件以在linux上运行。二进制文件构建,目录如下所示:

$GOPATH/src/github.com/mwmahlberg/DemoServer/
├── [-rwxr-xr-x 6.2M]  DemoServer
└── [-rw-r--r--  178]  server_main.go

请注意可执行文件server,其大小为6.3M。但是,让我们检查一下:

$ file DemoServer
server: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped

您实际上可以将此可执行文件复制到任何64位Linux并通过调用

运行它
$ ./DemoServer

现在,使用http://hostname:8080/Mark调用相应的服务器,您将看到一个问候您的网站。

这并不是说这使得部署非常简单。您无需处理任何依赖关系,无需配置其他Web服务器。您可以直接复制二进制文件并运行它。但是,这并不妨碍您使用更复杂的方法,例如创建像.deb.rpm或(我更喜欢)Docker镜像等软件包。

根据$GOPATH/src下面的子目录:实际上,你完全可以自由地在那里整理你的包。但是,三胞胎

  

codehoster /用户名/包

是有原因的。 go get命令实际上可以使用git,Mercurial和bzr站点自动下载包。有关详细信息,请参阅Package Publishing。是的,直接联系这些代码托管网站。 go get实际上至少依赖于git。三元组仅反映代码的全局可达位置。当然,您可以将代码存储在$GOPATH/src/foobar中并将其推送到github.com/mark/foobar,尽管这变得相当不明显,特别是当我像在github.com上托管开放项目以及在bitbucket.org上托管所有其他项目时那样。

现在,让我们做一些有用的事情,并在调用日期网址时显示日期:

package main 

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

// Default Request Handler
func defaultHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "<h1>Hello %s!</h1>", r.URL.Path[1:])
}

func dateHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w,"<h1>%s</h1>",time.Now())
}

func main() {
    http.HandleFunc("/date",dateHandler)
    http.HandleFunc("/", defaultHandler)
    http.ListenAndServe(":8080", nil)
}

但是,我们的main函数中仍然包含所有处理程序。我们将提取defaultHandler和dateHandler:

$GOPATH/src/github.com/mwmahlberg/DemoServer/
├── [-rw-r--r--  214]  dateHandler.go
├── [-rw-r--r--  165]  defaultHandler.go
└── [-rw-r--r--  178]  server_main.go

我们的server_main.go现在看起来像这样:

package main 

import (
    "net/http"    
)

func main() {
    http.HandleFunc("/date",dateHandler)
    http.HandleFunc("/", defaultHandler)
    http.ListenAndServe(":8080", nil)
}

defaultHandler.go

package main

import (
    "net/http"
    "fmt"
)

func defaultHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "<h1>Hello %s!</h1>", r.URL.Path[1:])
}

我们的dateHandler.go

package main

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

func dateHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w,"<h1>%s</h1>",time.Now())
}

让我们假设我们有一个特定于应用程序的可重用函数,我们希望将它们放入一个包中。为了这个例子,我们将为dateHandler提供一个Formatter。

$GOPATH/src/github.com/mwmahlberg/DemoServer/
├── [-rw-r--r--  214]  dateHandler.go
├── [-rw-r--r--  165]  defaultHandler.go
├── [drwxr-xr-x  102]  formatter
│   └── [-rw-r--r--  110]  dateformatter.go
└── [-rw-r--r--  178]  server_main.go

dateformatter.go的内容非常简单:

package formatter

import (
    "time"
)

func FormatDate(d time.Time) string {
    return d.Format(time.RFC850)
}

我们在日期处理程序中使用它:

package main

import (
    "fmt"
    "net/http"
    "time"

    "github.com/mwmahlberg/DemoServer/formatter"
)

func dateHandler(w http.ResponseWriter, r *http.Request) {

    fmt.Fprintf(w, formatter.FormatDate(time.Now()))

}

所以,我希望这会有所帮助。

答案 2 :(得分:0)

我会逐一回答你的问题:

1)如果我想将所有Go / Revel项目保存在go文件夹中,并将php和ruby保存在本地计算机上,我应该怎么做:

实际上你不能。 Go提出了一种构建Go代码结构的方法,理想情况是它应该如何遵循。 Go项目共享一个工作区,而不像其他项目那样,每个项目都有单独的工作区。

2)我如何以正确的方式在远程服务器上实际部署它们?

我能想到的一个有效方法是拥有一个单独的构建服务器,其中构建所有软件包以及获取远程软件包(github.com)。 Tar建造的项目。转到您的远程服务器,只需从bin运行可执行文件。这样可以节省生产服务器获取和构建远程包的时间。

3)如果我还需要使用GOPATH,我如何命名包?是GOPATH / src / mygoapp,GOPATH / src / mark / mygoapp还是GOPATH / src / bitbucket.org / mark / mygoapp(这个回购是私有的)?

我认为第三种方法是命名包的最合适方式,因为导入应该以主机名开头,然后是剩下的东西。