Golang学习之旅

Golang是2009年由谷歌的三位大佬(Robert Griesemer, Rob Pike, Ken Thompson)创造的一门新语言。Goalng有很多优点。比如,作为静态类型语言,Golang的依赖少,易于部署。它还支持协程并发,支持垃圾回收,可跨平台编译。Golang兼具动态语言的强大表达能力和C的执行效率,被誉为21世纪的C语言。

最近在学习Golang,为了寻找配置教程、优秀的电子书以及难度曲线适中的入门实践项目,我颇费了些功夫。趁着记忆还新鲜,我想分享一下我的学习路径以及学习资料。本文涉及Golang的安装、配置、运行以及实践项目。希望通过阅读本文,初学者们可以更快地找到适合自己的学习方向。

下载安装

官网提供标准安装包,一路点击就能完成安装。

安装包的链接是https://golang.org/dl/,更多关于安装的信息见安装 Go.

环境配置

(一)在终端运行

在命令行运行程序 几乎不需要配置。只要下载Golang,然后按官方建议,创建一个名为gocode的文件夹,直接在里面写代码就可以了。为了防止以后import其他包发生错误,建议把gocode文件夹放在GOPATH下。如何知道Golang的工作路径(GOPATH)在哪里呢?打开命令行,输入go env,就能在输出里找到工作路径了(注意区别安装路径和工作路径,它们是两个不同的路径)。

下面是Golang在命令行运行时的一些常用命令:


新建目录
$ mkdir foldername

打开目录
$ cd foldername

返回上一级目录
$ cd ..

新建go文件
$ touch filename.go

删除go文件
$ rm filename.go

重命名go文件
$ mv filename1.go filename2.go

用vim打开go文件
$ vim filename.go

运行go程序
$ go run filename.go

生成可执行的二进制文件
$ go build filename.go

运行二进制文件
$ ./filename

注:用vim打开文件以后,需要按a键打开编辑模式。编辑结束后,按esc键退出编辑模式。如果需要保存后退出,输入`:wq`。如果不保存直接退出,输入`:q`。最后按回车执行。

(二)在VSCode上运行

关于如何在VSCode上配置Golang运行环境,这个Youtube视频讲得很细:How to Configure Visual Studio Code for Go?

鉴于国内可能打不开YouTube,我用文字介绍一下配置步骤:

  1. 在VSCode安装go插件
  2. 打开Command Palette,输入Go Install/Update Tools。会弹出一列单选框,点全选,然后点OK安装
  3. 再次打开Command Palette,输入Shell Command: Install 'code' command in PATH,按回车安装

这样就配置完成啦!

运行go程序时,在Command Palette输入View: Toggle Integrated Terminal,即可在VSCode内打开命令行界面。在命令行界面输入go run filename.go,即可运行go程序。使用VSCode快捷键,可以更快地完成上述步骤,在此就不多作介绍了。

学习路径

(一)语言基础

Golang是一门简捷的语言,遵循敏捷开发(Agile Development)的原则,语言本身并不难。而且Golang官网提供了相当丰富的教程和代码示例,因此入门还是相当容易的。

对于初学者,建议先看官方的入门教程,再跑跑Go by Example上的Demo熟悉一下语言特性,就差不多了。

(二)入门书籍

入门书籍我推荐build-web-application-with-golang。这本书对概念的讲解细致到位,示例代码丰富,学习曲线也很平滑,适合初学者学习理解。在开始项目实践之前,可以先快速地浏览一下这本书。建议读一读2.2 Go基础中的代码,对深入了解Go语言还是挺有帮助的。

(三)项目实践

项目实践的最终目标是制作一个属于自己的Web application。为了实现这个目标,需要循序渐进。所以我们先用Go搭建我们的第一个静态网页,然后再尝试搭建动态网页。

(1)用Go搭建静态网页

搭建静态网页,我参考的是这个教程:Serving Static Sites with Go [PDF]。

按教程做完之后,我打算把之前在JavaScript初探中写的网页移植到这里验证一下。

详细代码(点击展开)

首先打开命令行,为项目创建目录。

$ mkdir to-do-list
$ cd to-do-list

除了在app.go中放置我们的代码,我们还需要创建static文件夹放置网页内容,templates文件夹放置模版。

$ touch app.go

$ mkdir -p static/stylesheets
$ touch static/example.html static/stylesheets/style.css

$ mkdir -p static/javascript
$ touch static/example.html static/javascript/main.js

$ mkdir templates
$ touch templates/layout.html templates/example.html

File: app.go
package main

import (
	"html/template"
	"log"
	"net/http"
	"os"
	"path/filepath"
)

func main() {
	fs := http.FileServer(http.Dir("static"))
	http.Handle("/static/", http.StripPrefix("/static/", fs))
	http.HandleFunc("/", serveTemplate)

	log.Println("\nWeb Server is available at http://localhost:3000/example.html")
	http.ListenAndServe(":3000", nil)
}

func serveTemplate(w http.ResponseWriter, r *http.Request) {
	lp := filepath.Join("templates", "layout.html")
	fp := filepath.Join("templates", filepath.Clean(r.URL.Path))

	// Return a 404 if the template doesn't exist
	info, err := os.Stat(fp)
	if err != nil {
		if os.IsNotExist(err) {
			http.NotFound(w, r)
			return
		}
	}

	// Return a 404 if the request is for a directory
	if info.IsDir() {
		http.NotFound(w, r)
		return
	}

	tmpl, err := template.ParseFiles(lp, fp)
	if err != nil {
		// Log the detailed error
		log.Println(err.Error())
		// Return a generic "Internal Server Error" message
		http.Error(w, http.StatusText(500), 500)
		return
	}

	if err := tmpl.ExecuteTemplate(w, "layout", nil); err != nil {
		log.Println(err.Error())
		http.Error(w, http.StatusText(500), 500)
	}
}

File: static/stylesheets/style.css
body {
    font-family: "Source Han Sans", "San Francisco", "PingFang SC", "Hiragino Sans GB", "Droid Sans Fallback", "Microsoft YaHei", sans-serif;
    font-size: 14px;
    color: #333;
}
a {
    text-decoration: none;
    color: #f66;
    transition-property: color;
    transition-duration: .2s;
    transition-timing-function: ease-in-out;
}
a:hover {
    color: #333;
}
p {
    margin: 1em 0;
}
p:empty {
    height: 1.5em;
}
main {
    margin: 0 5em;
    max-width: 60em;
}
h1 {
    margin: 1em 0;
    font-size: 24px;
    font-weight: 300;
}
textarea, article {
    width: 100%;
    height: 12em;
    margin: 2em 0;
    padding: .5em;
    overflow-y: scroll;
    border: 1px solid #999;
    border-radius: 2px;
    line-height: 1.5;
    text-align: justify;
    text-justify: inter-ideograph;
}
textarea {
    height: 9em;
    font-size: 14px;
    font-family: "Source Han Sans", "San Francisco", "PingFang SC", "Hiragino Sans GB", "Droid Sans Fallback", "Microsoft YaHei", sans-serif;
    color: #333;
}
article {
    cursor: pointer;
}
button {
    background: #fff;
    border: 1px solid #ccc;
    border-radius: 2px;
    line-height: 1;
    padding: .5em;
    color: #666;
    transition-property: color, background, border;
    transition-duration: .2s;
    transition-timing-function: ease-in-out;
}
button[id] {
    border: 1px solid #999;
    color: #333;
    cursor: pointer;
}
button[id]:hover {
    background: #666;
    border-color: #666;
    color: #fff;
}
::selection {
    color: #fff;
    background: #666;
}
::-moz-selection {
    color: #fff;
    background: #666;
}
table, th, td {
    border: 1px solid black;
    border-collapse: collapse;
    text-align: center;
}
th, td {
    padding: 5px;
}
th {
    text-align: left;
}

File: static/javascript/main.js
"use strict";
var Items = {
    	name: "",
    	isCheck: "false",
    isDelete: "false"
};

var objArray = [];

var subArray = [];

var submit_flag = true;

var delete_flag = true;

function addElement() {
    submit_flag = true;
    var item = Object.create(Items);
    
    var v = document.getElementById("myTextarea").value;
    item.name = v
    objArray.push(item);
    var body = ''
    
    for (var i = 0; i < objArray.length; i++) {
        var index = i+1;
        body += '';
        body += '';
        //body += '';
        body += '';
        //body += '';
        //body += '';
        body += '';
    }
    
    body += '
#Name
' + index.toString(10) + '' + '' + '' + objArray[i].name + '' + objArray[i].isDelete + '' + '' + '
'; document.getElementById("object_list").innerHTML = body; document.getElementById("myTextarea").value = ''; } function submit() { if (submit_flag == true) { submit_flag = false; subArray = objArray; objArray = []; var body = '' for (var i = 0; i < subArray.length; i++) { var index = i+1; body += ''; body += ''; body += ''; body += ''; body += ''; body += ''; } body += '
#Check BoxNameDelete
' + index.toString(10) + '' + '' + '' + subArray[i].name + '' + '' + '
'; document.getElementById("object_list").innerHTML = body; } } function finalSheet() { var myDate=new Date(); var final_sheet = '

计划完成统计表

' + myDate + '

' var body = '' var i = 0; var index = 1; var showtext = ""; while (i < subArray.length) { if (subArray[i].isDelete != "true" ) { if (subArray[i].isCheck == "true") { showtext = "√"; }else { showtext = "×"; } body += ''; body += ''; body += ''; body += ''; body += ''; index++; } i++; } body += '
#NameDone
' + index.toString(10) + '' + subArray[i].name + '' + showtext + '
'; document.getElementById("object_list").innerHTML = body; final_sheet += body download('计划完成统计表.html', final_sheet) } function handleEnter(event) { if (event.keyCode == 13 && !event.shiftKey) { addElement(); } } function clearText() { document.getElementById("myTextarea").value = ''; } function clearContents(element) { element.value = ''; } function isChecked(element) { var id_str = element.id id_str = id_str.replace("cb",""); var id_num = parseInt(id_str) if (element.checked == true){ subArray[id_num].isCheck = "true"; } else { subArray[id_num].isCheck = "false"; } } function isDeleted(element) { var id_str = element.id id_str = id_str.replace("btn",""); var id_num = parseInt(id_str) if (delete_flag == true) { delete_flag = false; subArray[id_num].isDelete = "true"; element.value="×" } else { delete_flag = true; subArray[id_num].isDelete = "false"; element.value="" } } function download(filename, text) { var element = document.createElement('a'); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); element.setAttribute('download', filename); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); }

File: templates/layout.html
{
    {define "layout"}}



    
    {
    {template "title"}}
    
    


    {
    {template "body"}}


{
    {end}}

File: templates/example.html
{
    {define "title"}}To Do List{
    {end}}

{
    {define "body"}}

计划表生成工具

© 2019 Chang Luo | Home


这是俺写的小工具,什么?居然被你发现了 O_O !!!


      →             →                      

{ {end}}

(2)用Go搭建动态网页

搭建动态网页,我参考了:

  • A Golang + ReactJS Application
  • How to Build a Simple Web App with React, Graphql, and Go

附录:资源列表

  1. 为什么学习Go语言:

    • 为什么要使用 Go 语言?Go 语言的优势在哪里?
    • Why should you learn Go?
    • jobbole/awesome-go-cn
  2. Golang在VSCode上的配置:How to Configure Visual Studio Code for Go?。

  3. Go的安装、运行、设计理念等基础知识,详见官方文档和入门教程。

  4. 通过例子 学习Go语言的语法和特性,详见Go by Example。

  5. 一本讲解Go语言基础以及Web Application实现的电子书 build-web-application-with-golang。

  6. 第一个实践项目,用Golang搭建一个静态网站 Serving Static Sites with Go [PDF]。

  7. 第二个实践项目,用Golang作后端,React作前端,搭建一个动态网站。

    • A Golang + ReactJS Application
    • How to Build a Simple Web App with React, Graphql, and Go


更多文章见我的博客: https://luochang212.github.io

你可能感兴趣的:(golang,golang,教程)