Rust不安全的代码,编写unsafe rust code需要注意些什么?

Rust网站管理员 Published the article • 0 comments • 20 views • 2019-08-31 14:54 • 来自相关话题

### 不安全的Rust代码 unsafe

Rust隐藏着第二种语言,它不会强制执行这类内存安全保障:这个被称为不安全的Rust(unsafe Rust)。与常规的Rust代码无异,但是它提供了额外的超级力量。
为什么会存在Unsafe Rust代码,其本质就是Rust本身静态分析保守导致。

### 有哪些超级力量呢?

1. 解引用裸指针
2. 调用不安全的函数或者方法
3. 访问或者修改可变静态变量
4. 实现不安全的trait

### 解引用裸指针

裸指针是可变或者不可变的,分别写作`*mut T`和`*const T`。这里的`*`不是解引用运算符,它是类型名称的一部分。在裸指针的上下文中,不可变意味着指针解引用之后不能直接赋值。

与引用和智能指针的区别在于,记住裸指针

1. 允许忽略借用规则,可以同时拥有不可变和可变的指针,或多个指向相同位置的可变指针
2. 不保证指向有效的内存
3. 允许为空
4. 不能实现任何自动清理工作

### 注意

不安全的代码必须用`unsafe`括起来,组成代码块,或者函数前标记该方法或者函数是不安全的
```rust
unsafe {
// your code
}

unsafe fn test(inc: u32) {
// your code
}

// for example
static HELLO_WORLD: &str = "hello world!";

static mut COUNTER: u32 = 0;

fn main() {
println!("name is: {}", HELLO_WORLD);

unsafe {
add_to_count(4);
println!("count is: {}", COUNTER);
}
}

unsafe fn add_to_count(inc: u32) {
COUNTER += inc;
}

``` 查看全部
### 不安全的Rust代码 unsafe

Rust隐藏着第二种语言,它不会强制执行这类内存安全保障:这个被称为不安全的Rust(unsafe Rust)。与常规的Rust代码无异,但是它提供了额外的超级力量。
为什么会存在Unsafe Rust代码,其本质就是Rust本身静态分析保守导致。

### 有哪些超级力量呢?

1. 解引用裸指针
2. 调用不安全的函数或者方法
3. 访问或者修改可变静态变量
4. 实现不安全的trait

### 解引用裸指针

裸指针是可变或者不可变的,分别写作`*mut T`和`*const T`。这里的`*`不是解引用运算符,它是类型名称的一部分。在裸指针的上下文中,不可变意味着指针解引用之后不能直接赋值。

与引用和智能指针的区别在于,记住裸指针

1. 允许忽略借用规则,可以同时拥有不可变和可变的指针,或多个指向相同位置的可变指针
2. 不保证指向有效的内存
3. 允许为空
4. 不能实现任何自动清理工作

### 注意

不安全的代码必须用`unsafe`括起来,组成代码块,或者函数前标记该方法或者函数是不安全的
```rust
unsafe {
// your code
}

unsafe fn test(inc: u32) {
// your code
}

// for example
static HELLO_WORLD: &str = "hello world!";

static mut COUNTER: u32 = 0;

fn main() {
println!("name is: {}", HELLO_WORLD);

unsafe {
add_to_count(4);
println!("count is: {}", COUNTER);
}
}

unsafe fn add_to_count(inc: u32) {
COUNTER += inc;
}

```

服务器突然挂掉了,mysql无法启动

网站管理员 Published the article • 0 comments • 36 views • 2019-08-24 00:01 • 来自相关话题

刚才打算在服务器上跑个项目,因为要记录很多的日志,所有我打算删掉点东西,然后节省空间,方便脚本一直跑下去,不了脚本处理数据多,内存占满了,服务器卡的不行,我只好`killall python`来结束这个脚本。

随后悲剧出现,msyql挂掉了,怎么也启动不了,我使用`mysqld --initialize`来初始化mysql,结果出现如下错误:
```
190823 23:53:07 [Warning] Using unique option prefix key_buffer instead of key_buffer_size is deprecated and will be removed in a future release. Please use the full name instead.
190823 23:53:07 [Note] mysqld (mysqld 5.5.62-0+deb8u1-log) starting as process 3731 ...
mysqld: File '/var/log/mysql/mysql-bin.index' not found (Errcode: 2)
190823 23:53:07 [ERROR] Aborting

190823 23:53:07 [Note] mysqld: Shutdown complete
```

大概看了一下就因为`/var/log/mysql/mysql-bin.index`这个文件找不到,原来是我干才误删的文件,那该怎么办呢?创建一下目录`mkdip -p /var/log/mysql`,然后继续执行上面的命令,果然成功,我的mysql服务终于起来了。

所以还是奉劝大家,删除数据的时候一定要谨慎点,不然半天还摸不着头脑。 查看全部

刚才打算在服务器上跑个项目,因为要记录很多的日志,所有我打算删掉点东西,然后节省空间,方便脚本一直跑下去,不了脚本处理数据多,内存占满了,服务器卡的不行,我只好`killall python`来结束这个脚本。

随后悲剧出现,msyql挂掉了,怎么也启动不了,我使用`mysqld --initialize`来初始化mysql,结果出现如下错误:
```
190823 23:53:07 [Warning] Using unique option prefix key_buffer instead of key_buffer_size is deprecated and will be removed in a future release. Please use the full name instead.
190823 23:53:07 [Note] mysqld (mysqld 5.5.62-0+deb8u1-log) starting as process 3731 ...
mysqld: File '/var/log/mysql/mysql-bin.index' not found (Errcode: 2)
190823 23:53:07 [ERROR] Aborting

190823 23:53:07 [Note] mysqld: Shutdown complete
```

大概看了一下就因为`/var/log/mysql/mysql-bin.index`这个文件找不到,原来是我干才误删的文件,那该怎么办呢?创建一下目录`mkdip -p /var/log/mysql`,然后继续执行上面的命令,果然成功,我的mysql服务终于起来了。

所以还是奉劝大家,删除数据的时候一定要谨慎点,不然半天还摸不着头脑。


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

golang网站管理员 Published the article • 0 comments • 21 views • 2019-08-15 11:01 • 来自相关话题

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

### 实现步骤

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 • 20 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 • 43 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 • 100 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 • 146 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 • 182 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 • 273 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 • 1072 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)