2017年3月

震惊!彩票的随机机制竟然是这样的...

<?php

$lanList = [];
$hongList = [];

for($i=1;$i<34;$i++){
  if($i<16){
    array_push($lanList,$i);
  }
  array_push($hongList, $i);
}

$res = [
  'red' => [],
  'blue' => []
];

for($i=0;$i<=6;$i++){
  if($i==0){
    $res['blue'] = array_slice($lanList, mt_rand( 0,count($lanList)-1) ,1);
  }
  $res['red'][] = array_splice($hongList, mt_rand( 0,count($hongList)-1),1)[0];

}
sort($res['red']);
echo 'red:'.implode(',',$res['red']).' blue:'.implode(',',$res['blue']).PHP_EOL;

?>

使用hexo和github-pages发布博客

本地搭建 hexo

  • 构建hexo需要在本地安装node.js
brew install node

当前版本的node版本

node -v
v7.7.3
  • 全局安装 hexo
npm install -g hexo

国外镜像慢的话可以搜索找下淘宝的 cnmp

  • 创建一个目录并且安装 hexo
mkdir hexo_blog
cd hexo_blog
hexo init
npm install
  • 新建一个文章
hexo new "your-first-page"

文件在 hexo_blog/source/_post/下进行编辑啊

  • 然后就是生成静态文件
hexo generate
hexo server

这时就可以访问 http://localhost:4000 来查看效果,这个时候hexo已经搭建成功了,
但是我们需要外网能够访问,这就用到了今天的另一个主角:github page

hexo 放到github上

  • 需要一个github账号,具体申请登录看 https://github.com 上的引导就行
  • 创建一个新的 repository 名字格式是固定的,比如我的账户名是 gaopengfei123123 那么这个库的名字就是 gaopengfei123123.github.io 不能改的哦
  • 为了可以直接提交远程文件需要添加 ssh 密匙
    本地操作
ssh-keygen -t rsa -C "5173180@qq.com” -f ~/.ssh/github-rsa
cat ~/.ssh/github_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC3K5mcQxH9mu1cUIu2+byK1iksES/7Tnfh23l2U6y1fOKO4XFhPLdAoMQdePnI51PAF4faXxucOYsiDb6IpQimWPwORKTkEkcglOiZ414eZZ829gY98RAldbFQeT2L9A0l2APfcan1fH4HvrCmZKlY8CNDQDDfRzXub9hfSX3LS5mQlgS9PHiFoXRfrS10hYweere9Cb9OFiEdkdCfMKUBr25ImGahqbaHxE8Vb3QzMT8Q5PBITaqFwYnIE/z6HU6Lok92EZ/uVG81SMJb9A5SQCZdsjWmyDqXj1eDZ1A2YyUlA+/6QM7JjCrLoZAAtZHTH+ylNAG79w9WG0eYAuL GaoPengFeiFiy@github.com

把这一段完整的复制到 https://github.com/settings/keys 这个地址下,添加一条新的ssh-key,这样就能免登录提交版本文件

  • 现在编辑本地hexo根目录下的站点配置文件 path/to/hexo_blog/_config.yml
    查找字段 deploy 编辑成这样
# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
  type: git
  repo: git@github.com:gaopengfei123123/gaopengfei123123.github.io.git
  branch: master

设置好后,就将本地生成的静态文件发到github上

hexo deploy

#如果报错就可能是少个插件
npm install hexo-deployer-git
  • 进入 你的版本库地址/settings 比如我的就是 https://github.com/gaopengfei123123/gaopengfei123123.github.io/settings
    找到 github pages 设置块按照你的需求调整,这时访问 https://gaopengfei123123.github.io就能访问 hexo 上传的内容了

绑定一个自己的域名,通过它来访问github pages

我用的是阿里云的万网来举例

  • 首先进入到万网云解析的页面
记录类型:A
主机记录:blog
记录值:xxx.xxx.xxx  #这里需要 ping -c 3 https://gaopengfei123123.github.io 获取ip地址
  • 然后返回到 你的版本库地址/settings 这里,将 Custom domain 设置成你刚才解析的名字,
    与此同时在github上版本的根目录下添加一个文件 CNAME 内容是
#in CNAME
blog.justwe.site

这时再返回settings中就能看的 github pages 部分的域名绑定的是你的域名了,到这里博客算是搭建成功了

hexo官网

hexo的next模版官网

laravel事物

laravel开启事物有两种方法:

  • 一种是闭包
DB::transaction(function()
{
    DB::table('user')->insert(['username'=>'xxx']);
    DB::table('comment')->insert(['content'=>'zzz']);
});

当闭包内发生错误就会自动回滚

  • 另一种比较灵活
DB::beginTransaction();
//这里执行一些数据库操作,包括 eloquent 的
if(condition){
    DB::commit();
}else{
    DB::rollback();
}

但是我有一次发现两种方法的事物都不起作用,在想掉几根头发之后想到了可能是不同数据库的原因!

如果你采用的是分库存储不同逻辑的方式,执行事物的时候一定要加上连接信息 上面的就要这样写了:

DB::connection('admin_database')->beginTransaction();
//这里执行一些数据库操作,包括 eloquent 的
if(condition){
    DB::connection('admin_database')->commit();
}else{
    DB::connection('admin_database')->rollback();
}

如果逻辑中的 eloquent 连接的数据库和开启事物的数据库不是一个库一样是不起作用的

go语言了解(3) 工作流程

本章将的关键字有 defer,panic,recover,main,init,import

defer

go语言中有一个不错的设计,就是defer。尤其是调用资源时需要打开和关闭两个选项的时候就能凸显出来

它的作用是将指定的语句在函数结束时执行,没明白?咱们举个例子啊

main () {
  for i :=0;i < 5 ; i++{
    defer fmt.Println('输出:',i)
  }
}

输出的结果不是01234而是相反的43210,这样就明白它的功能了吧?再举一个常用的例子

func OpenFile() bool{
  file.Open("file/path")

  if condition1 {
    file.Close()
    return false
  }

  if condition2 {
    file.Close()
    return false
  }

  file.Close()
  return true
}

在别的语言中我们打开文件的逻辑大体是这样的,你会发现打开一个文件需要在每个条件结束的时候去再声明关闭它,
这显得语句很臃肿,而且如果我们哪个地方给忘了很可能就造成内存泄漏,但在go中它变的很简单

func OpenFile() bool{
  file.Open("file/path")
  defer file.Close()
  if condition1 {
    return false
  }

  if condition2 {
    return false
  }
  return true
}

当函数按照从上往下执行的时,执行到最下面准备结束这个函数,go将会再从下往上执行一下标明的defer的命令

panic 和 recover

这两个函数放在一起说,因为他们的作用是相对的

panic会中断控制流程的命令,是go语言的报错机制,一旦执行panic那么当前进程就会终止,
但是我们刚才讲的defer命令还是会执行,等defer执行完了就会结束这个goroutine

recover会恢复panic造成的中断,从而让进程继续进行,而且recover只能在defer中执行,同时在正常进程中执行的recover()将返回false

由于没想到十分合适的场景就先不举例了:p

main 和 init

这两个也能放在一起说

main只能有一个,而且只能在main package当中,而init()每个包里都可以有多个,也可以没有,为了方便维护,建议包里不超过一个init

这两个都是系统自动执行的函数,不用在文件中执行

在平时构建项目的时候我们会导入很多的包(package),多个包中肯定会有重复的,但是不用担心,重复导入的包只会生效一次

main package导入外界的包会优先执行外界包的init和变量初始化,如果外界的包也导入了第三方的包,那么优先执行外界包的第三方包的初始化,再执行外界包的初始化最后执行mian package的初始化

这也很好理解,我们引入包的时候这个包肯定要是完整的形态,为了让他完整就要优先满足它的条件,这也层层向外翻到了最边缘初始化完毕再一层层的向内完成初始化

import

import有几个很方便的特性比如:

import(
  f "fmt"
  . "fmt"
  _ "fmt"
  )

这三种写法

  1. 第一种是引入别名 fmt.Println 就可以简写成 f.Println
  2. 第二种更厉害了,直接就可以把包名给省去 可以当成自己的方法写成 Println
  3. 第三种其实是引入该包,不直接使用包里的函数,而是调用了该包的init函数

go语言了解(2)--切片

切片是一种复合类型,可以是数组也可以是字符串

接下来是一个简单切片使用示例

package main

import "fmt"

func slienceInfo(slience []int, str string) {
    fmt.Println("\n", str, "的长度是:", len(slience))
    fmt.Println(str, "的大小是:", cap(slience), "\n")
    for i, v := range slience {
        fmt.Println(str, "下标", i, "是", v)
    }
}

func main() {
    //定义一个数组
    var arr [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

    //打印一下
    for _, v := range arr {
        fmt.Println("arr element is", v)
    }

    //获取数组 arr 从0 到下标为5(不包含下标5) 的一个切片
    mySlice := arr[:5]
    slienceInfo(mySlice, "mySlice")

    //声明一个包含5个元素的数组切片 此时会创建一个匿名数组
    elementSlience := []int{1, 2, 2, 3, 4}
    slienceInfo(elementSlience, "elementSlience")

    //声明一个默认值0,长度5,预留长度10的切片
    emptySlience := make([]int, 5, 10)
    slienceInfo(emptySlience, "emptySlience")

    //向切片中添加元素 这时数组的长度和占用内存是一致的
    emptySlience = append(emptySlience, 1, 2, 3, 4, 5)
    //如果超过分配的内存,会动态分配足够的内存空间
    //  emptySlience = append(emptySlience, 1, 2, 3, 4, 5)
    slienceInfo(emptySlience, "emptySlience2")

    mySlice = append(mySlice, emptySlience...)
    slienceInfo(mySlice, "mySlice2")

  //内容复制  
    slice1 := []int{1, 2, 3, 4, 5}
    slice2 := []int{6, 6, 6}
    //从slice2复制前三个元素到slice1当中,不同长度的按照较小的来
    copy(slice1, slice2)
    slienceInfo(slice2, "slice")

}

从示例中可以看出切片是动态分配内存大小的,我总结了一下几条规律

  1. 当切片源于一个已有的数组时,切片长度取决于截取的长度,切片分配的内存大小和源数组占用的内存大小一样
  2. 当直接生成一个切片数组时,可以定义长度和预留内存
  3. 当切片超出分配内存大小时,系统将会再分配一块足够大的内存

通常如果直到业务中明确的数组极限长度的时候,就分配足够大的内存,以缓解系统不断计算分配内存的压力,典型的空间换时间