从PHP到Go的程序员需要注意的一些事项

PHP转Go的程序员很多,使用Go重写Web应用,代价不高,并且所带来性能的提升很明显,因此很多PHP程序员正在转Go。

PHP是一个弱类型,解释型的语言,Go是一个强类型,编译型语言,两者的差别很大。如果长期使用PHP,使用Go的时候,一些惯性思维会带来不太好的效果。这里总结一些从PHP转到Go需要注意的点。

(更多…)

C++学习笔记:流程控制

这是我的C++学习笔记第二篇,学习流程控制语句

我的学习路径如下:

1. 变量和数据类型
2. 流程控制
3. 函数声明和调用
4. 面向对象
5. 标准库

顺序

顺序语句为一条一条顺序执行的语句。C++的顺序语句有赋值,四则运算,位运算,逻辑运算等

int i = 0;
int j = i + 1;

条件

C++提供两种条件,一个是if条件语句,另一个是switch选择语句。

if条件

// 单个条件
if (条件) {
   语句 //条件成立则执行语句
}

// 带有else的条件
if (条件) {
    语句
} else {
    语句
}

// 带有else if 的条件
if (条件1) {
    语句1
} else if (条件2) {
    语句2
} else {
    语句3
}

switch条件

switch (值) {
    case "值1":
        语句1
    break;
    case "值2":
        语句2
    break;
    default:
        语句3
    break;
}

循环

循环语句有while循环,for循环,do…while循环。

while 循环

while (条件) {
   语句
   ...
}

条件为真,就一直执行语句。如果初次条件不为真,语句一次都不会执行。

for 循环

for (初始; 条件; 下一步) {
    语句
    ...
}

更简单的for循环,范围for循环。类似与遍历的效果,序列可以是一个数组,vector,string等迭代器。

for (变量定义 : 序列) {
    语句
}

比如遍历一个vector

vector<int> v = {0,1,2,3,4,5};
for (auto &r: v) {
    r *= 2;
}

do…while 循环

do {
    语句
} while(条件);

异常

try 语句

try用作处理异常,用法

try {
    可能发生异常的语句
} catch (异常声明) {
    处理异常的语句
} catch (异常声明) {
    处理异常的语句
}
...

throw表达式

throw通常用于抛出一个异常,比如

throw runtime_error("error")

C++学习笔记:变量和数据类型

这是我的C++学习笔记第一篇,同所有的程序语言学习路径一样,首先学习的是变量和数据类型。

我的学习路径如下:

1. 变量和数据类型
2. 流程控制
3. 函数声明和调用
4. 面向对象
5. 标准库

这一章,学习的是变量和数据类型,需要了解的有:

1. 变量怎么定义?
2. 常见的都有哪些数据类型,占用的内存是多少?
3. 变量的作用域都有哪些?
4. 变量的生命周期是什么?

了解这些,对于变量基本就够了。

Hello world

在开始之前,先写一个hello world来熟悉一下程序的主要结构以及如何打印一个变量。

#include <iostream>

int main () {
    std::cout << "hello world" << std::endl;
    return 0;
}

iostream提供标准输入输出的头文件,程序以main函数问入口,std为标准库的命名空间,“<<” 为输出操作符,std::cout为标准输出,std::endl为结束符,表示将等待输出的内容从内存传送到标准输出。

(更多…)

Docker保存当前容器镜像

当我们在容器里面安装了一些软件或者修改一些设置之后,我们希望能把修改同步到相关的镜像,下次用这个镜像生成容器的时候,可以略过搭建环境这一步了。

比如我现在有一个容器叫centos

$ docker ps
b58e39dca53d        centos              "/bin/bash"         3 minutes ago       Up 3 minutes        0.0.0.0:4000-4100->4000-4100/tcp   centos-huchao

进入容器

docker exec -it /bin/bash centos-huchao

安装一些软件之后,通过docker commit 容器名称 镜像名称 命令将我们的修改保存的新的镜像。

docker commit centos-huchao centos:web

上面的镜像名称我加了一个标签。

计算机语言学习指南

这篇文章讨论基于语言的基本要素,如何快速入门一种计算机语言。是一篇语言从学习到使用的指导手册,并且这种学习方式是一个系统的学习,相比于碎片化的学习,这种学习更加不容易遗忘。

语言的基本成分

语言的基本成分为数据运算控制传输。想想你学过的语言,是不是都是这样。归结语言的组成成分,学习一门语言可以从这四个方面下手,这四个方面掌握之后,对这个语言就有个最基本的了解了。

(更多…)

Go中使用json.Unmarshal interface{}之后的数据类型

有时候设计不好的情况下,一个json类型很难用固定的数据结构去表示,因此我们会用interface{}去表示它。

在使用inteface的时候,需要了解json的数据类型对应的go的默认类型,使用才会不会出现疑惑,它们的类型关系对应如下

JSONGo
booleanbool
数值float64
字符串string
array[]interface{}
objectmap[string]interface{}
nullnil

了解他们默认的类型转换,使用时候就不会出问题了。

Go语言的 make 和 new

new 和 make 是两个内置函数,主要用来创建并分配类型的内存。在我们定义变量的时候,可能会觉得有点迷惑,不知道应该使用哪个函数来声明变量,其实他们的规则很简单,

new 只分配内存,make 只能用于 slice、map 和 channel 的初始化。

下面我们就来具体介绍一下

new

在Go语言中,new 函数描述如下:

// The new built-in function allocates memory. The first argument is a type,
// not a value, and the value returned is a pointer to a newly
// allocated zero value of that type.
func new(Type) *Type

从上面的代码可以看出,new 函数只接受一个参数,这个参数是一个类型,并且返回一个指向该类型内存地址的指针。同时 new 函数会把分配的内存置为零,也就是类型的零值。

(更多…)

Go单元测试与性能测试

在Go语言中做单元测试和性能测试是一件非常容易的事情——Go自带了测试工具包,testing包。

通常,测试代码和功能代码在同一个包中,测试代码以“_test”结尾。测试有两种类型,一种是单元测试(UnitTest),一种是性能测试(Benchmark)。接下来将会介绍一下如何写这两种测试。

单元测试

首先创建一个测试文件,命名foo_test.go(提示: 以test结尾

接下来是创建测试函数,Test_Foo(提示:测试函数以Test开头,传入*testing.T指针),代码如下:

func Test_Foo(t *testing.T) {

}

这里什么也没做,只是创建了一个空的测试函数,但确实是能运行的测试函数!如果你的编辑器支持测试提示(提示:vscode支持),那么你可以在函数上面看到一行小字,如下:

(更多…)

Go笔记六:常用标准库

这是我的Go学习的第六篇笔记,也是Go入门的最后一篇笔记。在大多数语言中,了解了变量和数据类型,流程控制,函数,面向对象,再加上标准库,就可以用这门语言去写一些项目了。

首先让我想想,在工作中通常会用语言频繁处理什么问题或者处理什么数据?最常见的应该是各种字符串操作,日期和时间,读写文件、socket等IO相关的操作!

字符串处理 — Strings

String提供了一组处理字符串的操作,常用的有:

  1. 判断一个字符串是否在另一个字符串中
  2. 分割字符串为[]string和组合[]string为一个字符串
  3. 字符串替换

太多了,就不一一列举了,这里列出一些常用的字符串操作。

字符串判断

// 判断子串substr是否在s中
func Contains(s, substr string) bool

字符串分割与合并

// 根据sep将字符串分割成一个数组
func Split(s, sep string) []string
// 将数组a用sep拼接成一个字符串
func Join(a []string, sep string) string

字符串转换

// 转换成大写
func ToUpper(s string) string
// 转换成小写
func ToLower(s string) string

字符串清理

// 去除首尾的cut字符串
func Trim(s string, cut string) string
// 去除左侧的cut字符串
func TrimLeft(s string, cut string) string
// 去除右侧的cut字符串
func TrimRight(s string, cut string) string
(更多…)

Go笔记五:goroutine和channel

这是我Go学习的第五篇笔记,学习的是go的语言的其他特性,这些特性是其他语言所不具备的。这次主要学习的是goroutine和channel。

我的语言学习过程一般分为下面几个:

1. 变量和数据类型
2. 流程控制方法
3. 函数声明和调用
4. 面向对象
5. 语言特性
6. 常用标准库

goroutine介绍和使用

Go语言中,每个并发执行的单元称为goroutine(可类比线程)。当一个程序启动时候,main函数在一个main goroutine中运行。如果想要创建新的goroutine,使用go关键字!

语法

创建一个新的 goroutine

go 函数名()

channel是goroutine的通信机制,比如创建一个能够接收int类型的channel,使用make创建:

// 创建一个channel
ch := make(chan int)

// 将i发送到channel
i := 1
ch <- i

// 从channel中接收数据
j := <-ch

// 丢弃channel中的数据
<-ch

同样,可以定义接收任意数据类型的channel

ch := make(chan interface{})

使用

并发通常应用在io操作较密集的地方,比如发起多个网络请求!通常串行发起网络请求是很慢的,大部分时间浪费在等待网络io上了。通过并发去请求能够显著提高整体耗时!

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

// 发起一个http get请求
// 把获取到的内容写入到channel
func httpget(url string, chc chan map[string]string) {
	resp, err := http.Get(url)
	if err != nil {
		// 错误处理
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		// 错误处理
	}
	var i = make(map[string]string)
	i[url] = string(body)
	chc <- i
}

func main() {
	chc := make(chan map[string]string)
	go httpget("http://www.baidu.com/", chc)
	go httpget("http://www.qq.com/", chc)
	// 等待完成
	var content map[string]string
	content = <-chc
	fmt.Println(content)
	content = <-chc
	fmt.Println(content)
}