社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
go原生支持Unicode,所以可以支持处理任何国家的语言,go是编译型语言,通过go的自命令run可以将go源码编译、链接、生成可执行文件并执行。
$ go run helloworld.go
一个简单的helloworld程序如下所示:
//要运行的包必须为main
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
go run 命令不会输出生成的中间可执行文件,如果要生成一个可以复用的可执行文件,可以使用go build命令,这会生成一个名为helloworld的可执行文件,然后可以运行该文件。
//编译
$ go build helloworld.go
//运行
$ ./helloworld
go组织程序的方式类似于java,也是通过包来组织不同模块的代码。每一个go文件的开头需要声明所属于的包。
main这个包是很特殊的一个包名,它用来定义一个单独的可执行程序,而不是库。
go的基础库中有100多个包,用来完成文件操作,数学计算,网络处理等基础任务。例如fmt包,可以用来将输出格式化并写入标准输出。
通过import引入需要使用的包,但是***go对引入的包有严格的规范,只能引入要使用的包,如果引入没有使用的包,程序编译会失败***。这一点与java不同,java并不做严格的限制,可以引入不使用的包。
main函数类似其他语言的main函数的作用,就是程序的入口函数。
函数的声明包括:
func关键字 函数名 参数列表 返回值列表(可以为空) 放在大括号内的函数体
***os***包提供了一些函数和变量,以平台无关的方式与操作系统交互。
命令行参数通过os.Args变量来访问。
os.Args是一个字符串slice。
os.Args[0] 表示的是运行的程序本身
package main
import (
"fmt"
"os"
"strings"
)
func main(){
var s, temp string
for i:= 0; i< len(os.Args) ; i++ {
s += temp + os.Args[i]
temp = " "
}
fmt.Println(s)
s = ""
temp = ""
//or
for _, arg := range os.Args[:] {
s += temp + arg
temp = " "
}
fmt.Println(s)
//or
fmt.Println(strings.Join(os.Args," "))
}
第二中方式的 “_” 表示空标志符,因为go不允许声明不使用的变量,但是range操作会产生一对值(这里是数组的索引和该索引上的值),所以必须拿一个空标志符来接收。
package main
import (
"bufio"
"fmt"
"os"
)
func main(){
counts := make(map[string]int)
input := bufio.NewScanner(os.Stdin)
for input.Scan() {
if "" == input.Text(){
break
}
counts[input.Text()]++
}
for line, n := range counts{
if n > 1{
fmt.Printf("%dt%sn", n, line)
}
}
}
make语法可以用于创建一个固有格式的map(键可以是允许相等(==)比较的类型,例如上面的string,值可以是任意类型)。例如上面的声明表示key为string,value为int。
counts[input.Text()]++ 这个语句等价于:
templine := input.Text()
counts[templine] = counts[templine] + 1
bufio包可以用来高效的处理输入输出。其中一个很有用的特性就是扫描器(Scanner),它可以读取输入,以行或者单词为单位断开,这是处理以行为单位的输入内容的最简单方式。
scan()方法在读到新行时返回true,没有更多内容时返回false。使用text()方法获取读到的数据。
例子
package main
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"time"
)
func main() {
startTime := time.Now()
//创建string通道
ch := make(chan string)
//遍历参数传入的url
for _, url := range os.Args[1:] {
//启动一个goroutine
go fetch(url, ch)
}
//从通道读数据
for range os.Args[1:] {
fmt.Println(<-ch)
}
//统计用时
pass := time.Since(startTime).Seconds()
fmt.Println("总用时%.2f秒", pass)
}
func fetch(url string, ch chan<- string) {
startTime := time.Now()
resp, err := http.Get(url)
if err != nil {
//写入到通道
ch <- fmt.Sprint(err)
return
}
//拷贝到目的地 返回拷贝的字节数 第一个参数是目的地 这里是一个“丢弃”目的地
nbytes, err := io.Copy(ioutil.Discard, resp.Body)
//关闭资源
resp.Body.Close()
if nil != err {
//写入通道
ch <- fmt.Sprintf("while reading %s: err:%v", url, err)
return
}
//统计用时
pass := time.Since(startTime).Seconds()
//写入通道
ch <- fmt.Sprintf("用时%.2f秒 数据量%7d字节 url:%s", pass, nbytes, url)
}
注意:通道是阻塞式的发送与接受数据方式,当一个goroutine试图在一个通道上进行发送或接收操作时,它会阻塞,直到另一个goroutine试图进行接收或发送操作才传递值。
示例
package main
import (
"fmt"
"log"
"net/http"
"sync"
)
var mu sync.Mutex
var count int
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/count", counter)
log.Fatal(http.ListenAndServe("localhost:8000",nil))
}
func counter(w http.ResponseWriter, r *http.Request) {
mu.Lock()
fmt.Fprintf(w, "count %dn", count)
mu.Unlock()
}
func handler(w http.ResponseWriter, r *http.Request) {
//输出http方法,URL,协议
fmt.Fprintf(w, "%s %s %s n", r.Method, r.URL, r.Proto)
//输出Header
for k,v := range r.Header {
fmt.Fprintf(w, "Header[%q] = %q n", k, v)
}
//输出host
fmt.Fprintf(w, "HOST = %qn", r.Host)
//输出RemoteAddr
fmt.Fprintf(w, "RemoteAddr = %q n", r.RemoteAddr)
//if 内部定义局部变量
if err := r.ParseForm(); err != nil {
log.Println(err)
}
//输出Form内数据
for k,v := range r.Form {
fmt.Fprintf(w, "Form[%q] = %qn", k, v)
}
//通过sysc.Mutex实现请求计数
mu.Lock()
count++
mu.Unlock()
fmt.Fprintf(w, "URL.PATH = %qn", r.URL.Path)
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!