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;
}

```

解决我的百度统计里top10搜索全是别人的链接,非法的链接

随想录网站管理员 Published the article • 0 comments • 20 views • 2019-08-25 13:35 • 来自相关话题

纯粹的想喷一下百度统计,作为一家上市公司竟然允许别人滥用合作联盟的百度统计代码呢?今天打开百度统计的管理后台,看到的全是一些非法的推广,看了一下全是来自洛阳的IP,不是想地域喷,其实很多朋友都出现了同样的现象,但是百度就是不关,收到遭殃的还有知乎的跳转链接地址,同样是跳到了别人的非法网址。

咨询了一下百度统计的在线咨询,没有人工客服,就只有如下机器人答复:

```
问题:为什么我的百度统计报告中出现了其它网站的网址?
答案:“其它网站”安装了您的百度统计代码。有可能是“其它网站”在制作网页时拷贝了您的网站代码,同时将百度统计代码也拷贝了。请联系该网站建设人员卸除您的百度统计代码。
```

这都是什么答复呢?好了我看后台有个功能”受限域名“,它推荐的真是那几个,上限20个,我试了全部添加,可是没有生效,你能理解,这是一家什么样的公司,连自己产品的功能有没有测试通过就放出来让人使用。

于是乎我决定把这个破烂玩儿下线了。


###如何解决

百度终于上线了过滤规则白名单了,[过滤规则设置](https://tongji.baidu.com/sc-we ... lusion)->受访域名统计规则->白名单,添加你自己的域名就可以了。

终于紧急上线,做了回事了,点赞。 查看全部
纯粹的想喷一下百度统计,作为一家上市公司竟然允许别人滥用合作联盟的百度统计代码呢?今天打开百度统计的管理后台,看到的全是一些非法的推广,看了一下全是来自洛阳的IP,不是想地域喷,其实很多朋友都出现了同样的现象,但是百度就是不关,收到遭殃的还有知乎的跳转链接地址,同样是跳到了别人的非法网址。

咨询了一下百度统计的在线咨询,没有人工客服,就只有如下机器人答复:

```
问题:为什么我的百度统计报告中出现了其它网站的网址?
答案:“其它网站”安装了您的百度统计代码。有可能是“其它网站”在制作网页时拷贝了您的网站代码,同时将百度统计代码也拷贝了。请联系该网站建设人员卸除您的百度统计代码。
```

这都是什么答复呢?好了我看后台有个功能”受限域名“,它推荐的真是那几个,上限20个,我试了全部添加,可是没有生效,你能理解,这是一家什么样的公司,连自己产品的功能有没有测试通过就放出来让人使用。

于是乎我决定把这个破烂玩儿下线了。


###如何解决

百度终于上线了过滤规则白名单了,[过滤规则设置](https://tongji.baidu.com/sc-we ... lusion)->受访域名统计规则->白名单,添加你自己的域名就可以了。

终于紧急上线,做了回事了,点赞。

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

后端开发网站管理员 Published the article • 0 comments • 37 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 • 21 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名的二进制可执行文件。

wepy如何使用typescript来开发自己的项目?

Wepy网站管理员 Published the article • 0 comments • 34 views • 2019-08-05 15:37 • 来自相关话题

how to create wepy applicate writen in typescript?

### install and config

```bash
npm install @wepy/compiler-typescript typescript --save-dev
```

in `wepy.config.js`
```js
const TypeScriptCompiler = require('@wepy/compiler-typescript');

module.exports = {
"plugins": [
TypeScriptCompiler()
]
};
```

### 如何在wepy的文件中引入ts文件和项目

```

{{age}}



```

### ts文件

```ts
import wepy from '@wepy/core'

wepy.page({
data: {
age: 1
},
created() {
console.log(this.age)
},
computed: {

},
hooks: {

},
methods: {

}
})
```


### 引用

1. [compiler-typescript](https://wepyjs.github.io/wepy- ... script) 查看全部

how to create wepy applicate writen in typescript?

### install and config

```bash
npm install @wepy/compiler-typescript typescript --save-dev
```

in `wepy.config.js`
```js
const TypeScriptCompiler = require('@wepy/compiler-typescript');

module.exports = {
"plugins": [
TypeScriptCompiler()
]
};
```

### 如何在wepy的文件中引入ts文件和项目

```



```

### ts文件

```ts
import wepy from '@wepy/core'

wepy.page({
data: {
age: 1
},
created() {
console.log(this.age)
},
computed: {

},
hooks: {

},
methods: {

}
})
```


### 引用

1. [compiler-typescript](https://wepyjs.github.io/wepy- ... script)

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

golang网站管理员 Published the article • 0 comments • 45 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
}
}
}
```

微信小程序云开发可以上传php代码吗?

小程序网站管理员 Published the article • 0 comments • 48 views • 2019-08-04 12:45 • 来自相关话题

微信小程序云开发可以上传php代码吗?

这显然是`不可以的`。为什么这么说?之所以云开发是希望一套javascript代码搞定,所有的前端后端开发只需要你会javascript即可。后台数据库是mongodb,可以帮助我们存储字典对象的数据,对于javascript来说,前端上传什么数据,校验通过直接存储即可,不需要而外的sql或者防范sql注入之类的。

小程序的云开发其实很方便前端的同学,如果你了解MongoDB之类的数据库操作的话,前后端都可以搞定。 查看全部

微信小程序云开发可以上传php代码吗?

这显然是`不可以的`。为什么这么说?之所以云开发是希望一套javascript代码搞定,所有的前端后端开发只需要你会javascript即可。后台数据库是mongodb,可以帮助我们存储字典对象的数据,对于javascript来说,前端上传什么数据,校验通过直接存储即可,不需要而外的sql或者防范sql注入之类的。

小程序的云开发其实很方便前端的同学,如果你了解MongoDB之类的数据库操作的话,前后端都可以搞定。

wepy2.x回滚wepy1.x,wepy2.x从入门到弃坑

小程序网站管理员 Published the article • 0 comments • 717 views • 2019-08-01 15:42 • 来自相关话题

网上有很多开发小程序同学喜欢用官方的开发框架wepy,wepy现在有两个大版本,wepy1.x和wepy2.x。

但是这两个版本差异十分的大,我之前写了一篇文档介绍了,大家可以先看看这一篇[wepy1.x升级wepy2.x,wepy如何实现大的版本升级](https://www.sourcedev.cc/article/188)。

对比一下差异。你会发现当前把wepy的代码从wepy1.x升级到wepy2.x的时候,仿佛进入了新的世界,语法差异十分的大。如果不打算重构自己的代码,需要兼容wepy1.x的话,这将会是一个不小的工程。
我们需要耗费大量的时间重构和调试自己的代码。

那么升级了wepy2.x之后怎么办,我发现自己入坑,想回到wepy1.x怎么办? 这个时候我们也不用着急,应为我们的代码,即使有少量的改动我们也可以恢复的。
将修改的代码放入回收站内,回收站是一个栈。

### 修改的代码恢复保存

```bash
git stash save # 将代码压入栈

git stash pop # 弹出代码
```

### 重新安装wepy1.x的全局包:

```bash
npm install wepy@1.7.x -g
``` 查看全部
网上有很多开发小程序同学喜欢用官方的开发框架wepy,wepy现在有两个大版本,wepy1.x和wepy2.x。

但是这两个版本差异十分的大,我之前写了一篇文档介绍了,大家可以先看看这一篇[wepy1.x升级wepy2.x,wepy如何实现大的版本升级](https://www.sourcedev.cc/article/188)。

对比一下差异。你会发现当前把wepy的代码从wepy1.x升级到wepy2.x的时候,仿佛进入了新的世界,语法差异十分的大。如果不打算重构自己的代码,需要兼容wepy1.x的话,这将会是一个不小的工程。
我们需要耗费大量的时间重构和调试自己的代码。

那么升级了wepy2.x之后怎么办,我发现自己入坑,想回到wepy1.x怎么办? 这个时候我们也不用着急,应为我们的代码,即使有少量的改动我们也可以恢复的。
将修改的代码放入回收站内,回收站是一个栈。

### 修改的代码恢复保存

```bash
git stash save # 将代码压入栈

git stash pop # 弹出代码
```

### 重新安装wepy1.x的全局包:

```bash
npm install wepy@1.7.x -g
```

如何在vim中格式代码?

Linux网站管理员 Published the article • 0 comments • 32 views • 2019-08-01 10:50 • 来自相关话题

如何在vim中格式代码

如何在vim中格式化代码,格式化c/c++/golang/rust/php/js/javascript/css/html/等代码。

按照如下输入,然后回车

```
# 按下`Esc`,然后按下`:`,进入命令模式
gg=G
```
如何在vim中格式代码

如何在vim中格式化代码,格式化c/c++/golang/rust/php/js/javascript/css/html/等代码。

按照如下输入,然后回车

```
# 按下`Esc`,然后按下`:`,进入命令模式
gg=G
```