如何使用golang实现一个redis的telnet交互程序

golang网站管理员 Published the article • 0 comments • 5 views • 4 天前 • 来自相关话题

该代码实例只是一个引子,并未实现交互,差一个循环输入,读取用户交互输入的实现。

### 实现步骤

1. 首先我们需要创建一个redis的连接`net.Dial`, 协议是`tcp`,端口6380。
2. `defer conn.Close()` 延迟关闭连接
3. 接下来我们需要做的事情就是发送数据和读取数据`func (conn RedisConn) Command(cmd []byte) ([]byte, error)`


### 代码实例

```go
package main

import (
"bufio"
"fmt"
"net"
"sync"
"unsafe"
)

type RedisConn struct {
RedisConn net.Conn
}

func (conn RedisConn) Command(cmd []byte) ([]byte, error) {
if _, err := conn.RedisConn.Write(cmd); err != nil {
panic(err)
}
reader := bufio.NewReader(conn.RedisConn)
buffer, _, err := reader.ReadLine()
if err != nil {
return nil, err
}
return buffer, nil
}

func main() {

conn, err := net.Dial("tcp", "192.168.1.18:6380")
if err != nil {
panic(err)
}
redis := RedisConn{
RedisConn: conn,
}

defer conn.Close()

if result, err := redis.Command([]byte("Ping\n")); err == nil {
fmt.Println(string(result))
}

if result, err := redis.Command([]byte("set test 2\n")); err == nil {
fmt.Println(string(result))
}

if result, err := redis.Command([]byte("get test\n")); err == nil {
fmt.Println(string(result))
}
}
``` 查看全部

该代码实例只是一个引子,并未实现交互,差一个循环输入,读取用户交互输入的实现。

### 实现步骤

1. 首先我们需要创建一个redis的连接`net.Dial`, 协议是`tcp`,端口6380。
2. `defer conn.Close()` 延迟关闭连接
3. 接下来我们需要做的事情就是发送数据和读取数据`func (conn RedisConn) Command(cmd []byte) ([]byte, error)`


### 代码实例

```go
package main

import (
"bufio"
"fmt"
"net"
"sync"
"unsafe"
)

type RedisConn struct {
RedisConn net.Conn
}

func (conn RedisConn) Command(cmd []byte) ([]byte, error) {
if _, err := conn.RedisConn.Write(cmd); err != nil {
panic(err)
}
reader := bufio.NewReader(conn.RedisConn)
buffer, _, err := reader.ReadLine()
if err != nil {
return nil, err
}
return buffer, nil
}

func main() {

conn, err := net.Dial("tcp", "192.168.1.18:6380")
if err != nil {
panic(err)
}
redis := RedisConn{
RedisConn: conn,
}

defer conn.Close()

if result, err := redis.Command([]byte("Ping\n")); err == nil {
fmt.Println(string(result))
}

if result, err := redis.Command([]byte("set test 2\n")); err == nil {
fmt.Println(string(result))
}

if result, err := redis.Command([]byte("get test\n")); err == nil {
fmt.Println(string(result))
}
}
```

如何将packages中的main.go自动编译安装包go bin目录下?

golang网站管理员 Published the article • 0 comments • 13 views • 2019-08-06 16:48 • 来自相关话题

在我的项目中有个main.go的入口文件,这是一个命令行脚本,编译之后可以生成一个二进制可执行文件。如何在安装该包之后,自动完成安装。

### 命令如下

```bash
go get -u github.com/deliangyang/huge-mysqldump
```

### go get -u命令参数详解

> The -u flag instructs get to use the network to update the named packages
> and their dependencies. By default, get uses the network to check out
> missing packages but does not use it to look for updates to existing packages.

从网络上下载或者更新包,及其依赖的时候,使用参数`-u`,默认情况下,get使用网络取检查丢失的包,但是查找更新已经存在的包。
下载完毕之后,会在`go bin`目录下生成一个package名的二进制可执行文件。 查看全部

在我的项目中有个main.go的入口文件,这是一个命令行脚本,编译之后可以生成一个二进制可执行文件。如何在安装该包之后,自动完成安装。

### 命令如下

```bash
go get -u github.com/deliangyang/huge-mysqldump
```

### go get -u命令参数详解

> The -u flag instructs get to use the network to update the named packages
> and their dependencies. By default, get uses the network to check out
> missing packages but does not use it to look for updates to existing packages.

从网络上下载或者更新包,及其依赖的时候,使用参数`-u`,默认情况下,get使用网络取检查丢失的包,但是查找更新已经存在的包。
下载完毕之后,会在`go bin`目录下生成一个package名的二进制可执行文件。

golang源代码分析之异步通信WaitGroup

golang网站管理员 Published the article • 0 comments • 10 views • 2019-08-05 14:56 • 来自相关话题

Golang source code analysis asynchronous communication WaitGroup.

### 常用方法介绍

WaitGroup主要是阻塞主线程,等待一组goroutine执行完毕。通常我们会用到sync.WaitGroup中的三个函数
```
Add() // 添加计数器
Done() // 减掉计数器,等价于Add(-1)
Wait() // 阻塞,知道计数器减为0
```
上面所述当计数器 Add adds delta, which may be negative, to the WaitGroup counter.
> If the counter becomes zero, all goroutines blocked on Wait are released.
> If the counter goes negative, Add panics.

Add的参数是一个整数,可能是负数,如果计数器变为0了,所有的goroutines会被阻塞等待释放,如果计数器变成负值,则会报错。
从方法`statep, semap := wg.state()`中拿到`statep`,它是一个原子计数器。

```go
func (wg *WaitGroup) Add(delta int) {
statep, semap := wg.state()
if race.Enabled {
_ = *statep // trigger nil deref early
if delta < 0 {
// Synchronize decrements with Wait.
race.ReleaseMerge(unsafe.Pointer(wg))
}
race.Disable()
defer race.Enable()
}
state := atomic.AddUint64(statep, uint64(delta) 32)
w := uint32(state)
if race.Enabled && delta > 0 && v == int32(delta) {
// The first increment must be synchronized with Wait.
// Need to model this as a read, because there can be
// several concurrent wg.counter transitions from 0.
race.Read(unsafe.Pointer(semap))
}
if v < 0 {
panic("sync: negative WaitGroup counter")
}
if w != 0 && delta > 0 && v == int32(delta) {
panic("sync: WaitGroup misuse: Add called concurrently with Wait")
}
if v > 0 || w == 0 {
return
}
// This goroutine has set counter to 0 when waiters > 0.
// Now there can't be concurrent mutations of state:
// - Adds must not happen concurrently with Wait,
// - Wait does not increment waiters if it sees counter == 0.
// Still do a cheap sanity check to detect WaitGroup misuse.
if *statep != state {
panic("sync: WaitGroup misuse: Add called concurrently with Wait")
}
// Reset waiters count to 0.
*statep = 0
for ; w != 0; w-- {
runtime_Semrelease(semap, false)
}
}
```

#### Wait()

```go
// Wait blocks until the WaitGroup counter is zero.
func (wg *WaitGroup) Wait() {
statep, semap := wg.state()
if race.Enabled {
_ = *statep // trigger nil deref early
race.Disable()
}
for {
state := atomic.LoadUint64(statep)
v := int32(state >> 32)
w := uint32(state)
if v == 0 {
// Counter is 0, no need to wait.
if race.Enabled {
race.Enable()
race.Acquire(unsafe.Pointer(wg))
}
return
}
// Increment waiters count.
if atomic.CompareAndSwapUint64(statep, state, state+1) {
if race.Enabled && w == 0 {
// Wait must be synchronized with the first Add.
// Need to model this is as a write to race with the read in Add.
// As a consequence, can do the write only for the first waiter,
// otherwise concurrent Waits will race with each other.
race.Write(unsafe.Pointer(semap))
}
runtime_Semacquire(semap)
if *statep != 0 {
panic("sync: WaitGroup is reused before previous Wait has returned")
}
if race.Enabled {
race.Enable()
race.Acquire(unsafe.Pointer(wg))
}
return
}
}
}
``` 查看全部
Golang source code analysis asynchronous communication WaitGroup.

### 常用方法介绍

WaitGroup主要是阻塞主线程,等待一组goroutine执行完毕。通常我们会用到sync.WaitGroup中的三个函数
```
Add() // 添加计数器
Done() // 减掉计数器,等价于Add(-1)
Wait() // 阻塞,知道计数器减为0
```
上面所述当计数器<=0之后,Add的参数不能为为负值,会出现如下错误`panic("sync: negative WaitGroup counter")`,`sync.WaitGroup`的源码在
如下两个文件中,包含源码和单元测试的源码:
```
src/sync/waitgroup.go
src/sync/waitgroup_test.go
```

### 如何使用

`sync.WaitGroup`主要配置`go func`来使用,阻塞主线程,等到`go func`执行完毕。
如下代码其实是没有任何输出的,因为主线程执行完成先于`go func`。所以里面的代码是不会被执行的。
```go
package main

func main() {

go func() {
for i := 0; i < 10; i++ {
fmt.Println("i: ", i)
}
}()
}
```

那么,我们需要如何解决这个问题呢?这里我们就需要用到`sync.WaitGroup`这个解决方案了。
```go
package main

func main() {
var wg = sync.WaitGroup{}
wg.Add(1)

go func() {
for i := 0; i < 10; i++ {
fmt.Println("i: ", i)
}
wg.Done()
}()

wg.Wait()
}
```


### 源码分析
结构体`WaitGroup`有两个字段,noCopy和state1的一个数组
```go
type WaitGroup struct {
noCopy noCopy

state1 [3]uint32
}
```

主要的方法是`Add()`和`Wait()`。函数`Done()`的实现如下,其实就是`wg.Add(-1)`。
```go
func (wg *WaitGroup) Done() {
wg.Add(-1)
}
```

#### state()

state()是一个私有方法,state()返回指向wg.state1中存储的state和sema字段的指针

```go
// state returns pointers to the state and sema fields stored within wg.state1.
func (wg *WaitGroup) state() (statep *uint64, semap *uint32) {
if uintptr(unsafe.Pointer(&wg.state1))%8 == 0 {
return (*uint64)(unsafe.Pointer(&wg.state1)), &wg.state1[2]
} else {
return (*uint64)(unsafe.Pointer(&wg.state1[1])), &wg.state1[0]
}
}
```

#### Add()

> Add adds delta, which may be negative, to the WaitGroup counter.
> If the counter becomes zero, all goroutines blocked on Wait are released.
> If the counter goes negative, Add panics.

Add的参数是一个整数,可能是负数,如果计数器变为0了,所有的goroutines会被阻塞等待释放,如果计数器变成负值,则会报错。
从方法`statep, semap := wg.state()`中拿到`statep`,它是一个原子计数器。

```go
func (wg *WaitGroup) Add(delta int) {
statep, semap := wg.state()
if race.Enabled {
_ = *statep // trigger nil deref early
if delta < 0 {
// Synchronize decrements with Wait.
race.ReleaseMerge(unsafe.Pointer(wg))
}
race.Disable()
defer race.Enable()
}
state := atomic.AddUint64(statep, uint64(delta)<<32)
v := int32(state >> 32)
w := uint32(state)
if race.Enabled && delta > 0 && v == int32(delta) {
// The first increment must be synchronized with Wait.
// Need to model this as a read, because there can be
// several concurrent wg.counter transitions from 0.
race.Read(unsafe.Pointer(semap))
}
if v < 0 {
panic("sync: negative WaitGroup counter")
}
if w != 0 && delta > 0 && v == int32(delta) {
panic("sync: WaitGroup misuse: Add called concurrently with Wait")
}
if v > 0 || w == 0 {
return
}
// This goroutine has set counter to 0 when waiters > 0.
// Now there can't be concurrent mutations of state:
// - Adds must not happen concurrently with Wait,
// - Wait does not increment waiters if it sees counter == 0.
// Still do a cheap sanity check to detect WaitGroup misuse.
if *statep != state {
panic("sync: WaitGroup misuse: Add called concurrently with Wait")
}
// Reset waiters count to 0.
*statep = 0
for ; w != 0; w-- {
runtime_Semrelease(semap, false)
}
}
```

#### Wait()

```go
// Wait blocks until the WaitGroup counter is zero.
func (wg *WaitGroup) Wait() {
statep, semap := wg.state()
if race.Enabled {
_ = *statep // trigger nil deref early
race.Disable()
}
for {
state := atomic.LoadUint64(statep)
v := int32(state >> 32)
w := uint32(state)
if v == 0 {
// Counter is 0, no need to wait.
if race.Enabled {
race.Enable()
race.Acquire(unsafe.Pointer(wg))
}
return
}
// Increment waiters count.
if atomic.CompareAndSwapUint64(statep, state, state+1) {
if race.Enabled && w == 0 {
// Wait must be synchronized with the first Add.
// Need to model this is as a write to race with the read in Add.
// As a consequence, can do the write only for the first waiter,
// otherwise concurrent Waits will race with each other.
race.Write(unsafe.Pointer(semap))
}
runtime_Semacquire(semap)
if *statep != 0 {
panic("sync: WaitGroup is reused before previous Wait has returned")
}
if race.Enabled {
race.Enable()
race.Acquire(unsafe.Pointer(wg))
}
return
}
}
}
```

Rust 引用变量的生命周期,编译器的借用检查器确保你的代码安全可靠

网站管理员 Published the article • 0 comments • 36 views • 2019-07-28 16:47 • 来自相关话题

## Rust lifetime

### Borrow Checker 借用检查器

#### 代码块

Rust编译器会在编译的时候比较作用域变量的生命周期。
Rust官方文档中有如下示例:
```rust
{
let r; // ---------+-- 'a
// |
{ // |
let x = 5; // -+-- 'b |
r = &x; // | |
} // -+ |
// |
println!("r: {}", r); // |
}
```

从中我们可以看出,里面括号里的代码块,变量x的作用域局限在里面的括号里,所以它的生命周期明显只有在这个括号里,对比变量r,r的生命周期要比x长,这个时候又将x的引用赋值给r,编译器会报错,因为后面的`println!("r: {}", r);`打印的r,其实是x。

### 在函数中分配生命周期

函数传参数,参数为引用,为什么要传引用呢?不想让函数拥有参数的所有权。

```rust
&i32 // 这是一个引用
&'a i32 // 这是一个有着详细生命周期的引用
&'a mut i32 // 这是一个有着详细生命周期的可变引用

fn longest &'a str {
x
}

// 错误案例
fn longest 查看全部

## Rust lifetime

### Borrow Checker 借用检查器

#### 代码块

Rust编译器会在编译的时候比较作用域变量的生命周期。
Rust官方文档中有如下示例:
```rust
{
let r; // ---------+-- 'a
// |
{ // |
let x = 5; // -+-- 'b |
r = &x; // | |
} // -+ |
// |
println!("r: {}", r); // |
}
```

从中我们可以看出,里面括号里的代码块,变量x的作用域局限在里面的括号里,所以它的生命周期明显只有在这个括号里,对比变量r,r的生命周期要比x长,这个时候又将x的引用赋值给r,编译器会报错,因为后面的`println!("r: {}", r);`打印的r,其实是x。

### 在函数中分配生命周期

函数传参数,参数为引用,为什么要传引用呢?不想让函数拥有参数的所有权。

```rust
&i32 // 这是一个引用
&'a i32 // 这是一个有着详细生命周期的引用
&'a mut i32 // 这是一个有着详细生命周期的可变引用

fn longest<'a>(x: &'a str, y: &str) -> &'a str {
x
}

// 错误案例
fn longest<'a>(x: &str, y: &str) -> &'a str {
let result = String::from("really long string");
result.as_str()
}
```
为什么的个函数`longest`会报错呢?原因是result的生命周期要比`'a`短。

### 在结构体定义里标记生命周期

### 哪些规则不需要为引用声明生命周期(lifetime elision rules)生命周期省略

每一个引用都有一个生命周期

在函数或者方法参数中,生命周期被称作输入生命周期,相反,返回值的被称作输出生命周期。

#### 生命周期省略规则

第一条适用于输入生命周期,后面两条则适用于输出生命周期。适用于`fn`和`impl`块。
只有满足如下三点,就可以不用声明生命周期。

1. 每一个引用参数都有自己的一个生命周期。
2. 如果只有一个输入生命周期参数,那么它被赋予所有输出生命周期参数。
3. 多个输入生命周期参数,`&self`或`&mult self`,self的生命周期被赋给所有输出生命周期参数。




【Rust Lang进击之路】如何入门Rust,从配置环境和阅读官方文档开始

网站管理员 Published the article • 0 comments • 55 views • 2019-07-27 00:28 • 来自相关话题

### 如何入门rust-lang,从官方文档阅读开始

为什么要学习Rust?Rust学习曲线高,入门也不简单,看看Rust的自荐。

> 一门赋予每个人
> 构建可靠且高效软件能力的语言。

1. 高性能
- Rust 速度惊人且内存利用率极高。由于没有运行时和垃圾回收,它能够胜任对性能要求特别高的服务,可以在嵌入式设备上运行,还能轻松和其他语言集成。

2. 可靠性
- Rust 丰富的类型系统和所有权模型保证了内存安全和线程安全,让您在编译期就能够消除各种各样的错误。

3. 生产力
- Rust 拥有出色的文档、友好的编译器和清晰的错误提示信息, 还集成了一流的工具 —— 包管理器和构建工具, 智能地自动补全和类型检验的多编辑器支持, 以及自动格式化代码等等。


#### 官方文档

- [中文文档](https://www.rust-lang.org/zh-CN/)
- [英文文档](https://www.rust-lang.org/learn)

#### 安装rust-lang IDE

Jetbrains是一家开发IDE的公司,旗下有很多优秀的IDE,phpstorm、goland、webstore、pyCharm等,今天我们要用到的是Intellij,然后我们可以在他的插件管理器中下载rust的插件,安装完毕之后,我们可以重启IDE,创建rust应用程序。

如果需要研究阅读插件的源代码,跟进插件的特性,可以[在github上](https://intellij-rust.github.io/)讨论。

#### 关于rust-lang的环境配置

官方提供了很优秀的解决方案,[Install Rust](https://www.rust-lang.org/tools/install),不知道从什么时候开始,学习东西喜欢从它的官方文档先开始研究。
> It looks like you’re running macOS, Linux, or another Unix-like OS. To download Rustup and install Rust, run the following in your terminal, then follow the on-screen instructions.
官方提供的方法其实很简单,是一个自动化安装的shell脚本,curl下载shell脚本,一键部署安装环境,十分的简单方便。

```bash
curl https://sh.rustup.rs -sSf | sh
```

#### 阅读文档,从`Hello world`程序开始我们的rust

开始我们的rust`hello world`程序之旅,不得不提一下cargo,rust的包管理工具(Rust's package manager)。

##### 首先我们需要通过`cargo`创建一个rust的项目

在命令行执行`cargo new hello-world`,然后cargo管理器就为我们创建了一个hello-world的目录,这个目录如下:
```
.
├── Cargo.lock
├── Cargo.toml
└── src
└── main.rs
```

其实`cargo new`,会直接给我们自动生成一个hello world的程序,代码如下
```rust
fn main() {
println!("Hello, world!");
}
```
然后我们只需要执行如下脚本,cargo会帮我们自动生成可执行文件,并且执行输出结果。
```bash

cargo run
# Compiling hello-demo v0.1.0 (/Users/demo/project/hello-demo)
# Finished dev [unoptimized + debuginfo] target(s) in 0.78s
# Running `target/debug/hello-demo`
# Hello world
```

##### 使用Rustc编译.rs文件

```bash
Rustc src/main.rs
./main

# Hello world
```

### Rust HelloWorld程序分析

Rust可执行程序一定需要一个入口文件,和C/C++一样,需要一个`manin`函数,关键词`fn`表示函数,宏`println!`可以帮助我们打印输出。
为什么说长得像函数的`println!`是宏,如果你观察仔细的话,你会发现宏是在函数后面增加了一个感叹号`!`,这个标识标识它就是宏。
关于宏的介绍,后面我会弄个专栏来介绍它。宏不管是在C还是Rust中,都十分的强大。相信你也会喜欢这门语言的。 查看全部
### 如何入门rust-lang,从官方文档阅读开始

为什么要学习Rust?Rust学习曲线高,入门也不简单,看看Rust的自荐。

> 一门赋予每个人
> 构建可靠且高效软件能力的语言。

1. 高性能
- Rust 速度惊人且内存利用率极高。由于没有运行时和垃圾回收,它能够胜任对性能要求特别高的服务,可以在嵌入式设备上运行,还能轻松和其他语言集成。

2. 可靠性
- Rust 丰富的类型系统和所有权模型保证了内存安全和线程安全,让您在编译期就能够消除各种各样的错误。

3. 生产力
- Rust 拥有出色的文档、友好的编译器和清晰的错误提示信息, 还集成了一流的工具 —— 包管理器和构建工具, 智能地自动补全和类型检验的多编辑器支持, 以及自动格式化代码等等。


#### 官方文档

- [中文文档](https://www.rust-lang.org/zh-CN/)
- [英文文档](https://www.rust-lang.org/learn)

#### 安装rust-lang IDE

Jetbrains是一家开发IDE的公司,旗下有很多优秀的IDE,phpstorm、goland、webstore、pyCharm等,今天我们要用到的是Intellij,然后我们可以在他的插件管理器中下载rust的插件,安装完毕之后,我们可以重启IDE,创建rust应用程序。

如果需要研究阅读插件的源代码,跟进插件的特性,可以[在github上](https://intellij-rust.github.io/)讨论。

#### 关于rust-lang的环境配置

官方提供了很优秀的解决方案,[Install Rust](https://www.rust-lang.org/tools/install),不知道从什么时候开始,学习东西喜欢从它的官方文档先开始研究。
> It looks like you’re running macOS, Linux, or another Unix-like OS. To download Rustup and install Rust, run the following in your terminal, then follow the on-screen instructions.
官方提供的方法其实很简单,是一个自动化安装的shell脚本,curl下载shell脚本,一键部署安装环境,十分的简单方便。

```bash
curl https://sh.rustup.rs -sSf | sh
```

#### 阅读文档,从`Hello world`程序开始我们的rust

开始我们的rust`hello world`程序之旅,不得不提一下cargo,rust的包管理工具(Rust's package manager)。

##### 首先我们需要通过`cargo`创建一个rust的项目

在命令行执行`cargo new hello-world`,然后cargo管理器就为我们创建了一个hello-world的目录,这个目录如下:
```
.
├── Cargo.lock
├── Cargo.toml
└── src
└── main.rs
```

其实`cargo new`,会直接给我们自动生成一个hello world的程序,代码如下
```rust
fn main() {
println!("Hello, world!");
}
```
然后我们只需要执行如下脚本,cargo会帮我们自动生成可执行文件,并且执行输出结果。
```bash

cargo run
# Compiling hello-demo v0.1.0 (/Users/demo/project/hello-demo)
# Finished dev [unoptimized + debuginfo] target(s) in 0.78s
# Running `target/debug/hello-demo`
# Hello world
```

##### 使用Rustc编译.rs文件

```bash
Rustc src/main.rs
./main

# Hello world
```

### Rust HelloWorld程序分析

Rust可执行程序一定需要一个入口文件,和C/C++一样,需要一个`manin`函数,关键词`fn`表示函数,宏`println!`可以帮助我们打印输出。
为什么说长得像函数的`println!`是宏,如果你观察仔细的话,你会发现宏是在函数后面增加了一个感叹号`!`,这个标识标识它就是宏。
关于宏的介绍,后面我会弄个专栏来介绍它。宏不管是在C还是Rust中,都十分的强大。相信你也会喜欢这门语言的。

福利来了,阿里云一站式企业协同研发云,需求编码测试发布反馈一条龙

网站管理员 Published the article • 0 comments • 154 views • 2019-02-21 21:25 • 来自相关话题

##### 最近上阿里云,看到了他们推广的一款产品叫```一站式企业协同研发云```,顾名思义就是我们以后web流水线都可以基于这款产品来开发完,对与个人和小型工作室团队来讲,这就是福音。但是目前部署发布的流程只支持```Java```和```NodeJs```,相信后面会支持更多的语言。

##### 该网站有的特色就是协同开发,产品在网站提需求,程序员可以在改平台创建```git```仓库,pull、push、merge代码,测试人员或团队可以提交bug到上面,最后运维的同学可以自动化发布代码,整个流程可以节省大量的时间,我们不需要到处去找文档,不需要手动部署或者花费大量的时间搭建环境,整套流程都是现成的,开箱即用。

##### 虽然不太喜欢阿里云吧,但是这个功能还是挺好的,希望能支持更多的语言发布就好了。 查看全部

##### 最近上阿里云,看到了他们推广的一款产品叫```一站式企业协同研发云```,顾名思义就是我们以后web流水线都可以基于这款产品来开发完,对与个人和小型工作室团队来讲,这就是福音。但是目前部署发布的流程只支持```Java```和```NodeJs```,相信后面会支持更多的语言。

##### 该网站有的特色就是协同开发,产品在网站提需求,程序员可以在改平台创建```git```仓库,pull、push、merge代码,测试人员或团队可以提交bug到上面,最后运维的同学可以自动化发布代码,整个流程可以节省大量的时间,我们不需要到处去找文档,不需要手动部署或者花费大量的时间搭建环境,整套流程都是现成的,开箱即用。

##### 虽然不太喜欢阿里云吧,但是这个功能还是挺好的,希望能支持更多的语言发布就好了。

Golang source code complie, missing _Gidle redeclared in this block

golang网站管理员 Published the article • 0 comments • 255 views • 2019-01-31 14:57 • 来自相关话题

_Gidle redeclared in this block

When compile the golang source code, having an error message, which is _Gidle redeclared in this block

```bash
git clean -df // clean your local change
```

if you find some warning, romove it, or ```git clone``` source code again.

and then

```bash
cd src
./all.bash
```

Maybe the problem is having the same source code in your directory 查看全部
_Gidle redeclared in this block

When compile the golang source code, having an error message, which is _Gidle redeclared in this block

```bash
git clean -df // clean your local change
```

if you find some warning, romove it, or ```git clone``` source code again.

and then

```bash
cd src
./all.bash
```

Maybe the problem is having the same source code in your directory


golang如何导出excel表格?

golang网站管理员 Published the article • 0 comments • 960 views • 2018-08-29 10:43 • 来自相关话题

golang如何导出excel表格?
做后台或者数据统计难免需要做数据导入和导出,导出成excel,方便在本地进行数据筛选,对比处理
这个时候我们就需要用到三方库```teatleg/xlsx```了


### 安装使用

[https://github.com/tealeg/xlsx](https://github.com/tealeg/xlsx)

```bash
dep ensure --add github.com/tealeg/xlsx
```

### 文档支持

[https://godoc.org/github.com/tealeg/xlsx](https://godoc.org/github.com/tealeg/xlsx)

### For example

```go
package main

import (
"github.com/tealeg/xlsx"
"fmt"
"log"
)

func main() {
var file *xlsx.File
var sheet *xlsx.Sheet
var row *xlsx.Row
var cell *xlsx.Cell

style := xlsx.NewStyle()

fill := *xlsx.NewFill("solid", "00FF0000", "FF000000")
font := *xlsx.NewFont(20, "Verdana")
border := *xlsx.NewBorder("thin", "thin", "thin", "thin")
style.Fill = fill
style.Font = font
style.Border = border

style.ApplyFill = true
style.ApplyFont = true
style.ApplyBorder = true

file = xlsx.NewFile()
sheet, er := file.AddSheet("SheetName")
if er != nil {
log.Fatal(er)
}
row = sheet.AddRow()

cell = row.AddCell()
cell.Value = "100000"
cell.SetStyle(style)

cell = row.AddCell()
cell.Value = "test"

err := file.Save("D:\\test.xlsx")
if err != nil {
fmt.Printf(err.Error())
}
}
```

### 读取一个文件excel文件

```golang
package main

import (
"fmt"
"github.com/tealeg/xlsx"
)

func main() {
excelFileName := "/home/tealeg/foo.xlsx"
xlFile, err := xlsx.OpenFile(excelFileName)
if err != nil {
...
}
for _, sheet := range xlFile.Sheets {
for _, row := range sheet.Rows {
for _, cell := range row.Cells {
text := cell.String()
fmt.Printf("%s\n", text)
}
}
}
}
```

### 将数据写入到excel中
```golang
package main

import (
"fmt"
"github.com/tealeg/xlsx"
)

func main() {
var file *xlsx.File
var sheet *xlsx.Sheet
var row *xlsx.Row
var cell *xlsx.Cell
var err error

file = xlsx.NewFile()
sheet, err = file.AddSheet("Sheet1")
if err != nil {
fmt.Printf(err.Error())
}
row = sheet.AddRow()
cell = row.AddCell()
cell.Value = "I am a cell!"
err = file.Save("MyXLSXFile.xlsx")
if err != nil {
fmt.Printf(err.Error())
}
}
```

### 参考资料

1. [https://github.com/tealeg/xlsx](https://github.com/tealeg/xlsx)
2. [https://godoc.org/github.com/tealeg/xlsx](https://godoc.org/github.com/tealeg/xlsx) 查看全部

golang如何导出excel表格?
做后台或者数据统计难免需要做数据导入和导出,导出成excel,方便在本地进行数据筛选,对比处理
这个时候我们就需要用到三方库```teatleg/xlsx```了


### 安装使用

[https://github.com/tealeg/xlsx](https://github.com/tealeg/xlsx)

```bash
dep ensure --add github.com/tealeg/xlsx
```

### 文档支持

[https://godoc.org/github.com/tealeg/xlsx](https://godoc.org/github.com/tealeg/xlsx)

### For example

```go
package main

import (
"github.com/tealeg/xlsx"
"fmt"
"log"
)

func main() {
var file *xlsx.File
var sheet *xlsx.Sheet
var row *xlsx.Row
var cell *xlsx.Cell

style := xlsx.NewStyle()

fill := *xlsx.NewFill("solid", "00FF0000", "FF000000")
font := *xlsx.NewFont(20, "Verdana")
border := *xlsx.NewBorder("thin", "thin", "thin", "thin")
style.Fill = fill
style.Font = font
style.Border = border

style.ApplyFill = true
style.ApplyFont = true
style.ApplyBorder = true

file = xlsx.NewFile()
sheet, er := file.AddSheet("SheetName")
if er != nil {
log.Fatal(er)
}
row = sheet.AddRow()

cell = row.AddCell()
cell.Value = "100000"
cell.SetStyle(style)

cell = row.AddCell()
cell.Value = "test"

err := file.Save("D:\\test.xlsx")
if err != nil {
fmt.Printf(err.Error())
}
}
```

### 读取一个文件excel文件

```golang
package main

import (
"fmt"
"github.com/tealeg/xlsx"
)

func main() {
excelFileName := "/home/tealeg/foo.xlsx"
xlFile, err := xlsx.OpenFile(excelFileName)
if err != nil {
...
}
for _, sheet := range xlFile.Sheets {
for _, row := range sheet.Rows {
for _, cell := range row.Cells {
text := cell.String()
fmt.Printf("%s\n", text)
}
}
}
}
```

### 将数据写入到excel中
```golang
package main

import (
"fmt"
"github.com/tealeg/xlsx"
)

func main() {
var file *xlsx.File
var sheet *xlsx.Sheet
var row *xlsx.Row
var cell *xlsx.Cell
var err error

file = xlsx.NewFile()
sheet, err = file.AddSheet("Sheet1")
if err != nil {
fmt.Printf(err.Error())
}
row = sheet.AddRow()
cell = row.AddCell()
cell.Value = "I am a cell!"
err = file.Save("MyXLSXFile.xlsx")
if err != nil {
fmt.Printf(err.Error())
}
}
```

### 参考资料

1. [https://github.com/tealeg/xlsx](https://github.com/tealeg/xlsx)
2. [https://godoc.org/github.com/tealeg/xlsx](https://godoc.org/github.com/tealeg/xlsx)

golang的路由控制器框架chi

golang网站管理员 Published the article • 0 comments • 740 views • 2018-08-27 15:00 • 来自相关话题

### golang的路由控制器框架chi

#### 官方介绍

> chi is a lightweight, idiomatic and composable router for building Go 1.7+ HTTP services. It's especially good at helping you write large REST API services that are kept maintainable as your project grows and changes. chi is built on the new context package introduced in Go 1.7 to handle signaling, cancelation and request-scoped values across a handler chain.

> The focus of the project has been to seek out an elegant and comfortable design for writing REST API servers, written during the development of the Pressly API service that powers our public API service, which in turn powers all of our client-side applications.

> The key considerations of chi's design are: project structure, maintainability, standard http handlers (stdlib-only), developer productivity, and deconstructing a large system into many small parts. The core router github.com/go-chi/chi is quite small (less than 1000 LOC), but we've also included some useful/optional subpackages: middleware, render and docgen. We hope you enjoy it too!


#### 翻译
- Chi是一个轻量级的、惯用的、可组合的路由器,用于构建GO 1.7 + HTTP服务。它特别擅长帮助您编写大型REST API服务,这些服务在项目增长和更改时保持可维护性。chi构建在Go 1.7中引入的新上下文包之上,用于跨处理程序链处理信令、取消和请求范围值。

- 该项目的重点是寻求一种优雅和舒适的设计来编写REST API服务器,该服务器是在Pressly API服务的开发过程中编写的,该服务为我们的公共API服务提供动力,而公共API服务又为我们的所有客户端应用程序提供动力。

- Chi设计的主要考虑因素是:项目结构、可维护性、标准http处理程序(stdlib-only)、开发人员的生产力,以及将大型系统分解为许多小部件。核心路由器github.com/go-chi/chi非常小(小于1000LOC),但是我们也包括了一些有用的/可选的子包:中间件、呈现和docgen。我们希望你也喜欢它!

### 官方地址

```https://github.com/go-chi/chi```

### 如何安装

#### dep
```bash
dep ensure --add github.com/go-chi/chi
```

#### go
```bash
go get -u github.com/go-chi/chi
```

### 示例

#### hello world
```go
package main

import (
"net/http"
"github.com/go-chi/chi"
)

func main() {
r := chi.NewRouter()
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
})
http.ListenAndServe(":3000", r)
}
```

#### 中间件的使用

中间件起承上启下的作用,所有它的实现需要一个context把中间件拿到的值,传递下去,
比如我们需要在request中做处理,那么我们需要调用```r.WithContext(ctx)```,把request传递到server中,
同理,在response中我们仍需要```response.WriteContext(ctx)```
```go
package main

import (
"github.com/go-chi/chi"
"net/http"
"context"
"log"
"encoding/gob"
"bytes"
)

func main() {
r := chi.NewRouter()
r.Use(MyMiddleWare)
r.Get("/test", func(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("hello world\n"))
writer.Write([]byte("hello world\n"))
a := request.Context().Value("user")
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
err := enc.Encode(a)
if err != nil {
log.Fatal(err)
}
//writer.Write([]byte(buf.Bytes()))
log.Println(a)
})
http.ListenAndServe(":3000", r)
}


func MyMiddleWare(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), "user", "123")
log.Println("test")
next.ServeHTTP(w, r.WithContext(ctx))
})
}
```

#### 核心中间件

允许访问的ContentType、是否压缩、获取请求头header、心跳、无缓存、真实ip等等,当然我们也可以扩展自己的中间件

-----------------------------------------------------------------------------------------------------------
| chi/middleware Handler | description |
|:----------------------|:---------------------------------------------------------------------------------
| AllowContentType | Explicit whitelist of accepted request Content-Types |
| Compress | Gzip compression for clients that accept compressed responses |
| GetHead | Automatically route undefined HEAD requests to GET handlers |
| Heartbeat | Monitoring endpoint to check the servers pulse |
| Logger | Logs the start and end of each request with the elapsed processing time |
| NoCache | Sets response headers to prevent clients from caching |
| Profiler | Easily attach net/http/pprof to your routers |
| RealIP | Sets a http.Request's RemoteAddr to either X-Forwarded-For or X-Real-IP |
| Recoverer | Gracefully absorb panics and prints the stack trace |
| RequestID | Injects a request ID into the context of each request |
| RedirectSlashes | Redirect slashes on routing paths |
| SetHeader | Short-hand middleware to set a response header key/value |
| StripSlashes | Strip slashes on routing paths |
| Throttle | Puts a ceiling on the number of concurrent requests |
| Timeout | Signals to the request context when the timeout deadline is reached |
| URLFormat | Parse extension from url and put it on request context |
| WithValue | Short-hand middleware to set a key/value on the request context |
-----------------------------------------------------------------------------------------------------------

### 路由器的设计

> Each routing method accepts a URL pattern and chain of handlers

每个路由的设计都支持URL的正则匹配和```chain```话柄,如```user/{userId}```,```test/*```等,
实例化一个chi的router ```r := chi.NewRouter()```我们就可以实现开始我们的web后端api的开发了 查看全部
### golang的路由控制器框架chi

#### 官方介绍

> chi is a lightweight, idiomatic and composable router for building Go 1.7+ HTTP services. It's especially good at helping you write large REST API services that are kept maintainable as your project grows and changes. chi is built on the new context package introduced in Go 1.7 to handle signaling, cancelation and request-scoped values across a handler chain.

> The focus of the project has been to seek out an elegant and comfortable design for writing REST API servers, written during the development of the Pressly API service that powers our public API service, which in turn powers all of our client-side applications.

> The key considerations of chi's design are: project structure, maintainability, standard http handlers (stdlib-only), developer productivity, and deconstructing a large system into many small parts. The core router github.com/go-chi/chi is quite small (less than 1000 LOC), but we've also included some useful/optional subpackages: middleware, render and docgen. We hope you enjoy it too!


#### 翻译
- Chi是一个轻量级的、惯用的、可组合的路由器,用于构建GO 1.7 + HTTP服务。它特别擅长帮助您编写大型REST API服务,这些服务在项目增长和更改时保持可维护性。chi构建在Go 1.7中引入的新上下文包之上,用于跨处理程序链处理信令、取消和请求范围值。

- 该项目的重点是寻求一种优雅和舒适的设计来编写REST API服务器,该服务器是在Pressly API服务的开发过程中编写的,该服务为我们的公共API服务提供动力,而公共API服务又为我们的所有客户端应用程序提供动力。

- Chi设计的主要考虑因素是:项目结构、可维护性、标准http处理程序(stdlib-only)、开发人员的生产力,以及将大型系统分解为许多小部件。核心路由器github.com/go-chi/chi非常小(小于1000LOC),但是我们也包括了一些有用的/可选的子包:中间件、呈现和docgen。我们希望你也喜欢它!

### 官方地址

```https://github.com/go-chi/chi```

### 如何安装

#### dep
```bash
dep ensure --add github.com/go-chi/chi
```

#### go
```bash
go get -u github.com/go-chi/chi
```

### 示例

#### hello world
```go
package main

import (
"net/http"
"github.com/go-chi/chi"
)

func main() {
r := chi.NewRouter()
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
})
http.ListenAndServe(":3000", r)
}
```

#### 中间件的使用

中间件起承上启下的作用,所有它的实现需要一个context把中间件拿到的值,传递下去,
比如我们需要在request中做处理,那么我们需要调用```r.WithContext(ctx)```,把request传递到server中,
同理,在response中我们仍需要```response.WriteContext(ctx)```
```go
package main

import (
"github.com/go-chi/chi"
"net/http"
"context"
"log"
"encoding/gob"
"bytes"
)

func main() {
r := chi.NewRouter()
r.Use(MyMiddleWare)
r.Get("/test", func(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("hello world\n"))
writer.Write([]byte("hello world\n"))
a := request.Context().Value("user")
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
err := enc.Encode(a)
if err != nil {
log.Fatal(err)
}
//writer.Write([]byte(buf.Bytes()))
log.Println(a)
})
http.ListenAndServe(":3000", r)
}


func MyMiddleWare(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), "user", "123")
log.Println("test")
next.ServeHTTP(w, r.WithContext(ctx))
})
}
```

#### 核心中间件

允许访问的ContentType、是否压缩、获取请求头header、心跳、无缓存、真实ip等等,当然我们也可以扩展自己的中间件

-----------------------------------------------------------------------------------------------------------
| chi/middleware Handler | description |
|:----------------------|:---------------------------------------------------------------------------------
| AllowContentType | Explicit whitelist of accepted request Content-Types |
| Compress | Gzip compression for clients that accept compressed responses |
| GetHead | Automatically route undefined HEAD requests to GET handlers |
| Heartbeat | Monitoring endpoint to check the servers pulse |
| Logger | Logs the start and end of each request with the elapsed processing time |
| NoCache | Sets response headers to prevent clients from caching |
| Profiler | Easily attach net/http/pprof to your routers |
| RealIP | Sets a http.Request's RemoteAddr to either X-Forwarded-For or X-Real-IP |
| Recoverer | Gracefully absorb panics and prints the stack trace |
| RequestID | Injects a request ID into the context of each request |
| RedirectSlashes | Redirect slashes on routing paths |
| SetHeader | Short-hand middleware to set a response header key/value |
| StripSlashes | Strip slashes on routing paths |
| Throttle | Puts a ceiling on the number of concurrent requests |
| Timeout | Signals to the request context when the timeout deadline is reached |
| URLFormat | Parse extension from url and put it on request context |
| WithValue | Short-hand middleware to set a key/value on the request context |
-----------------------------------------------------------------------------------------------------------

### 路由器的设计

> Each routing method accepts a URL pattern and chain of handlers

每个路由的设计都支持URL的正则匹配和```chain```话柄,如```user/{userId}```,```test/*```等,
实例化一个chi的router ```r := chi.NewRouter()```我们就可以实现开始我们的web后端api的开发了


golang websocket解决跨域问题

golang网站管理员 Published the article • 0 comments • 1590 views • 2018-08-24 16:43 • 来自相关话题

### golang websocket解决跨域问题

error: request origin not allowed by Upgrader.CheckOrigin
修改如下配置即可,CheckOrigin return true

```golang
var upgrade = websocket.Upgrader{
// cross origin domain
CheckOrigin: func(r *http.Request) bool {
return true
},
}
```

### 源码分析

在```github.com/gorilla/websocket/server.go:49```行中有这么个定义:```CheckOrigin func(r *http.Request) bool```

这是一个回调函数,当```CheckOrigin``` return true的时候,支持websocket跨域,否者就需要在同一个域名下了。

```golang
type Upgrader struct {
...
// CheckOrigin returns true if the request Origin header is acceptable. If
// CheckOrigin is nil, the host in the Origin header must not be set or
// must match the host of the request.
CheckOrigin func(r *http.Request) bool
...
}
```

在127行有如下判断,如果CheckOrigin非空,则```checkSameOrigin```, 检测是否是请求的是相同的host

```golang
checkOrigin := u.CheckOrigin
if checkOrigin == nil {
// checkSameOrigin returns true if the origin is not set or is equal to the request host.
checkOrigin = checkSameOrigin
}
if !checkOrigin(r) {
return u.returnError(w, r, http.StatusForbidden, "websocket: 'Origin' header value not allowed")
}
```


### golang websocket 小案例

```golang
package main

import (
"github.com/gorilla/websocket"
"net/http"
"fmt"
"log"
)

// 这是支持跨域
var upgrade = websocket.Upgrader{
// cross origin domain
CheckOrigin: func(r *http.Request) bool {
return true
},
}

func main() {
http.HandleFunc("/echo", echo)
http.ListenAndServe("localhost:8080", nil)
log.Fatal("start")
}

// 接收数据并返回
func echo(w http.ResponseWriter, r *http.Request) {
c, err := upgrade.Upgrade(w, r, nil)
if err != nil {
fmt.Println(err)
}

for {
mt, message, _ := c.ReadMessage()
fmt.Println(mt, string(message))
c.WriteMessage(mt, append([]byte("hello "), message[:]...))
}

}
```

### js测试,并与websocket进行通讯案例

```js
// 创建一个websocket实例
var ws = new WebSocket("ws://localhost:8080/echo");
// 发送数据 open connection
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
// 接收数据
ws.onmessage = function(evt) {
console.log("Received Message: " + evt.data);
ws.close();
};
// 关闭websocket连接close connection
ws.onclose = function(evt) {
console.log("Connection closed.");
```

### 参考

1. [https://blog.csdn.net/wangzhan ... 03532](https://blog.csdn.net/wangzhan ... 603532)
2. [https://github.com/gorilla/websocket](https://github.com/gorilla/websocket) 查看全部

### golang websocket解决跨域问题

error: request origin not allowed by Upgrader.CheckOrigin
修改如下配置即可,CheckOrigin return true

```golang
var upgrade = websocket.Upgrader{
// cross origin domain
CheckOrigin: func(r *http.Request) bool {
return true
},
}
```

### 源码分析

在```github.com/gorilla/websocket/server.go:49```行中有这么个定义:```CheckOrigin func(r *http.Request) bool```

这是一个回调函数,当```CheckOrigin``` return true的时候,支持websocket跨域,否者就需要在同一个域名下了。

```golang
type Upgrader struct {
...
// CheckOrigin returns true if the request Origin header is acceptable. If
// CheckOrigin is nil, the host in the Origin header must not be set or
// must match the host of the request.
CheckOrigin func(r *http.Request) bool
...
}
```

在127行有如下判断,如果CheckOrigin非空,则```checkSameOrigin```, 检测是否是请求的是相同的host

```golang
checkOrigin := u.CheckOrigin
if checkOrigin == nil {
// checkSameOrigin returns true if the origin is not set or is equal to the request host.
checkOrigin = checkSameOrigin
}
if !checkOrigin(r) {
return u.returnError(w, r, http.StatusForbidden, "websocket: 'Origin' header value not allowed")
}
```


### golang websocket 小案例

```golang
package main

import (
"github.com/gorilla/websocket"
"net/http"
"fmt"
"log"
)

// 这是支持跨域
var upgrade = websocket.Upgrader{
// cross origin domain
CheckOrigin: func(r *http.Request) bool {
return true
},
}

func main() {
http.HandleFunc("/echo", echo)
http.ListenAndServe("localhost:8080", nil)
log.Fatal("start")
}

// 接收数据并返回
func echo(w http.ResponseWriter, r *http.Request) {
c, err := upgrade.Upgrade(w, r, nil)
if err != nil {
fmt.Println(err)
}

for {
mt, message, _ := c.ReadMessage()
fmt.Println(mt, string(message))
c.WriteMessage(mt, append([]byte("hello "), message[:]...))
}

}
```

### js测试,并与websocket进行通讯案例

```js
// 创建一个websocket实例
var ws = new WebSocket("ws://localhost:8080/echo");
// 发送数据 open connection
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
// 接收数据
ws.onmessage = function(evt) {
console.log("Received Message: " + evt.data);
ws.close();
};
// 关闭websocket连接close connection
ws.onclose = function(evt) {
console.log("Connection closed.");
```

### 参考

1. [https://blog.csdn.net/wangzhan ... 03532](https://blog.csdn.net/wangzhan ... 603532)
2. [https://github.com/gorilla/websocket](https://github.com/gorilla/websocket)