介绍
我觉得有一些误解。让我们继续努力。
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...]
Run 编译并运行包含命名 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
GOOS=linux go build ./...
现在,在目录 DemoServer 中调用时,在我的例子中,交叉编译二进制文件以在 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
or.rpm
或(我更喜欢)Docker 映像。
根据下面的子目录$GOPATH/src
:实际上你完全可以自由地在那里组织你的包。然而,三胞胎
codehoster/用户名/包名
是有原因的。该go get
命令实际上可以使用 git、Mercurial 和 bzr 站点自动下载包。有关详细信息,请参阅包发布。是的,直接联系这些代码托管站点。go get
实际上至少依赖于git 。三元组简单地反映了代码的全局可达位置。当然,您可以将代码存储在 中 $GOPATH/src/foobar
并将其推送到github.com/mark/foobar
,尽管这变得相当不透明,尤其是像我在 github.com 和 bitbucket.org 上托管开放项目时那样做。
现在,让我们做一些有用的事情,并在调用日期 url 时显示日期:
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()))
}
所以,我希望这会有所帮助。