小白要生发

小白要生发 查看完整档案

成都编辑电子科技大学成都学院  |  计算机科学与技术 编辑  |  填写所在公司/组织 itjsz.com 编辑
编辑

PHP工程师

公众号: phpitjsz
juejin: 同名
learnku: 同名

个人动态

小白要生发 发布了文章 · 3月5日

3-5年的PHPer 应该具备~

又到了,金三银四,换工作季。我呢没准变换工作,倒是上网翻了翻招聘信息,由于我做PHP,就看了下当下3-5年的招聘需求,发现这些招聘信息都有如下要求:

3-5年PHP需要具备:

  • TCP/UDP协议, socket 通信,熟练使用workman,swoole,swoft等rpc框架
  • 精通PHP,熟悉golang语言,
  • 熟悉html,css,javascript,会nodejs,vue优先。
  • mysql, 以及SQL优化,熟悉索引应用和优化,独立设计数据库、数据表,
  • nosql,mongodb, redis,memcache缓存。熟悉后端缓存技术、了解缓存使用场景,高并发、高性能服务系统设计经验及能力,熟悉大规模集群系统的开发
  • 常用Linux,shell命令编写,熟悉云、容器使用
  • 精通LNMP架构,熟悉http 协议,RestFul API开发,熟悉tp,laravel,yii主流框架。
  • 熟练使用svn,git,Hg版本管理工具,
  • 良好的书写习惯,注释,设计模式,编写高质量的,整洁简单,可维护性的代码,遵循公司研发规范,产品技术文档的整理
  • 分析和快速排查定位解决线上问题,保障系统功能的稳定性,优化现有系统,提升运作性能
  • 主导/参与项目的架构设计、技术选型、架构原型实现以及服务端核心模块的开发,与各技术人员紧密合作,完成工作任务
  • 有个人博客,个人开源项目,有个人独立完成项目。
  • 乐于持续学习,乐观开朗,抗压性强,良好的沟通能力和合作精神,自我驱动力强,有强烈的事业心和责任感

大家可以看看自己是否达到了主流的用人标准,如果你是超出预期,那么你可以选择跳得更高。3-5年时间,足够把一个学生培养成一个合格的打工人了。可以看到企业还是把PHPer当作多面手看待,希望还会能会一些其他语言。3-5年的phper,企业还希望有一定的带团能力,由此可见phper的成熟期是较短的。

我同时对比了3-5年的NodeJS,Python、Java、Golang就职要求,PHP岗位对技术之外的要求是最多的,这样会,还要那样会,而且范围还广。我自己也觉得phper的成熟时间是较短的,对技术高低的评判主要是对高性能、高并发的设计,这个时候php写的漂不漂亮不重要,会不会用第三方工具(Redis,ES),了不了解限流、队列、削峰、缓存这些原理就尤为重要。所以到这个份上,就别死磕PHP了,多看看周边。

我又查了下5-10年的PHP岗位,数据很少。有的,我看了下任职要求,只有一句话要求了PHP。好到里,我就想从整个职业道路上谈谈,如果你关注过我的博客,会发现,我发布些golang相关的技术博客了。如果你还是坚持——PHP是这世界上最好的语言,你可以把这篇文章关闭了。本来我还是安安心心写PHP,捣鼓捣鼓Swoole,觉得会用Swoole,能玩转PHP协程就很牛皮。这除了自嗨,然并卵。

之前比较喜欢看些别人的博客,php100从断更到关闭。其他综合博客平台,PHP的文章更新占比也很少,这么说吧,有些培训机构都不开班了。我感觉最近php的热度是有所下降的。所以,大家考虑换工作好好考虑下未来5年,10年你准备干什么。同时,别死磕语言,多积累算法、计算机底层、架构方面的知识,这些不随你换语言而过时的。

查看原文

赞 5 收藏 1 评论 7

小白要生发 关注了用户 · 1月18日

煎鱼 @eddycjy

我的公众号:脑子进煎鱼了
博客地址:https://eddycjy.com/
喝口热水,写写代码。

关注 1984

小白要生发 发布了文章 · 1月8日

go mod graph 可视化——gmchart

背景

之前构建 golang 遇到个问题,就是明明指定了依赖的包版本,在构建时,又自动把版本号给升上去了,当时不知道为什么。后面知道有个 go mod graph 的命令能列出所有的依赖,试了下,一点都不直观,还得复制到文本编辑器里面来来检索信息。

于是我就上网查了下相关工具。

别的工具

检索 Go Module 依赖关系 可视化

网上还是有很多工具。大部分方案都 graphvizechart, 或者用绘制图片,我就试了几个。

graphviz 这个工具很强大,但需要通过其他渠道安装,且生成的svg可读性也不那么好,特别是依赖的包多起来之后,例如下面这个:

go mod graphviz

于是乎我转向 echart,

哇哦,看着挺不错的,鼠标悬停反馈也不错,配色也很鲜艳。

go mod echart

echart 方案很漂亮,但没法用。svg我还能搜索包名,echart 这个不显示包名。

好了,吐槽归吐槽,问题还是要解决的。今天给大家介绍个 go mod graph 可视化工具—— gmchart

gmchart

github: https://github.com/PaulXu-cn/...

安装

go get -u github.com/PaulXu-cn/go-mod-graph-chart/gmchart

检查安装情况,如下就是成功了

gmchart --help

Usage of ~\go\bin\gmchart:
  -debug int
        is debug model
  -keep int
        start http server not exit

使用

进入 golang 项目,输入命令:

go mod graph | gmchart
会自动打开浏览器,如果没有就手动一下

访问 http://127.0.0.1:60306 就能看到

可以看到,它将依赖形成了一个 依赖树,你可以知道某个包在第几层被引入的,非常直观。网页内是一个svg,你要找某个包也非常方便,直接 ctr+F 就能检索。

总结

找了那么久,为啥还是没有一个趁手的工具呢?

我想了下,可视化是前端的擅长的啊,前端不用 golang 啊,会的也少,会 Golang 的前端,还对 go mod graph 这个功能感兴趣的就更少了,所以这个工具只能是我们后端来做了

哎~

其他方案

查看原文

赞 4 收藏 3 评论 0

小白要生发 关注了用户 · 2020-12-31

justjavac @justjavac

会写点 js 代码

关注 14506

小白要生发 发布了文章 · 2020-11-29

一文带你入门 Golang

go 语言特点

脚本化的语法,容易上手。

静态类型+编译性,开发、运行效率都有保证

函数式 & 面向对象 两种编程范式,

原生支持并发编程支持,降低开发成本,维护成本,以及更好的兼容性,效率。

劣势:语法糖没有 Python 和 Ruby 多。运行效率不及C,但已赶超C++,Java。第三方库不多,就是轮子少(喜欢造轮子的可以加入golang轮子大军)。

安装

官方: https://golang.org/

官方镜像站: https://golang.google.cn/

国内官方站点: https://go-zh.org/

Linux

http://golang.org/dl/ 下载最新Go语言二进制包

wget https://dl.google.com/go/go1.13.15.linux-amd64.tar.gz

tar -C /usr/local -xzf go1.13.15.linux-amd64.tar.gz

export PATH=$PATH:/usr/local/go/bin

go version

Mac

$ brew install go

## 安装制定版本
$ brew install go@1.13

Windows

访问 官方镜像站 下载 msi 安装文件。

环境变量

安装好 go 后。运行go env就可以得到当前 go runtime 相关的环境变量了,这些变量可以通过

go env -w GO_ENV_NAME='new Value'

或是

$ env GO_ENV_NAME='new Value'

都能影响 go env

目录结构

这里讲一下 $GOPATH 也就是 ~/go 下的目录结果:

$  ls ~/go/
bin     #   go 可执行文件目录
pkg     #   go 归档文件目录
src     #   go 下载的代码包源码文件,存放目录

go命令

go run

go 自带了 runtime,通过 go run file.go 就能运行程序代码了。

参数:

-a : 强制编译相关代码,不论他们的源代码是否有改变,编译结果是否最新。
-n : 打印编译过程中所需要的运行命令,但不真正执行它们
-p n : 并行编译,n为并行数量
-v : 列出被编译的代码包的名称
-work : 显示编译时创建的的临时目录,并且不删除。
-x : 打印编译过程中所需运行的命令

go build

编译出目标文件。

类比 nodejs 就是, npm build, 类比 Java

go build main.go 编译制定的 main.go 代码文件

go build 执行命令就是将当前代码包作为代码包并编译

参数:

-a 所有涉及、被引入的代码都会被重新编译。

go install

编译并安装代码包或源文件。

golang 安装代码包动作就是将编译结果移动到 pkg/平台号编号/归档文件。

如果是可执行文件,则移动到当前工作去的 bin 目录,或者 $GOBIN 目录.

go get

从远程代码仓库上下载、安装代码包。

远程仓科可以是:gitmercurial(HG)svnbazaar

代码下载后会放到 $GOPATH/src 目录中.

-d : 只执行下载动作,不执行安装动作
-fix : 先执行`修正`动作,再进行编译和安装代码包。
-x : 展示命令执行过程
-u : 下载并更新代码包
修正: 指语法向上兼容。

go 代码关键字

break         //退出循环
default     //选择结构默认项(switch、select)
func         //定义函数
interface    //定义接口
select        //channel
case         //选择结构标签
chan         //定义channel
const         //常量
continue     //跳过本次循环
defer         //延迟执行内容(收尾工作)
go         //并发执行
map         //map类型
struct        //定义结构体
else         //选择结构
goto         //跳转语句
package     //包
switch        //选择结构
fallthrough     //??
if         //选择结构
range         //从slice、map等结构中取元素
type        //定义类型
for         //循环
import         //导入包
return         //返回
var        //定义变量

标示符

appendboolbytecapclosecomplexcomplex64complex128uint16
copyfalsefloat32float64imagintint8int16uint32
int32int64iotalenmakenewnilpanicuint64
printprintlnrealrecoverstringtrueuintuint8uintptr

语言特色

不要求缩进,不要求末尾加分号——;,同一行代码中有多个表达式,需要用 分号 分割。没有使用的变量,包,会导致报错。

每个go源文件开头必须是package开头,定义自己的包

一个目录下,只能有一个包名

一个可执行的文件必须要有 main() 函数

import 引入包

两种引入风格

import "package1"
import "package2"
import (
    "package1"
    pa2 "package2"      // 包别名,别名为 pa2
    . "fmt"
    _ "mysql"
)

. "fmt" 方式引入包的化,使用fmt里面的函数就可直接使用,不用带 fmt 前缀了

如果引入的包不使用,会报错, 或者加个前缀 _ 即可,这样的下划线会把引入的包的init函数执行一下。定义的变量不用,也会报错。

包内初始化函数

定义 包内 初始化函数

func init() {
    
}

只导入这个包部分,并运行init函数,由于导入不全,所以在代码中就不能使用这个包了。

import _ "MyPackage" 

数据类型

序号类型和描述
1布尔型 布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。
2数字类型 整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。
3字符串类型: 字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。
4派生类型: 包括: (a) 指针类型(Pointer) (b) 数组类型 (c) 结构化类型(struct) (d) Channel 类型 (e) 函数类型 (f) 切片类型 (g) 接口类型(interface) (h) Map 类型

使用 int 时,根据当前操作系统来的,64位系统对应 int64, 32位操作系统,对应int32.

变量声明

  • 变量声明: var <变量名> [变量类型]
  • 变量赋值: <变量名> = <值,表达式,函数返回>
  • 变量声明赋值:var <变量名> [变量类型] = <值,表达式,函数返回>
  • 变量声明,类型推断,并赋值 <变量名> := <值,表达式,函数返回>
分组声明

var (
    i int
    foo float32
    name string
)

分组批量声明、赋值
var a,b,c,d int = 1,2,3,4
a,b := 1,2

特殊变量 _

变量作用域

  • 函数内定义的变量称为局部变量
  • 函数外定义的变量称为全局变量
  • 全局变量必须使用 var 声明,局部变量可省略

作用域可以分为以下四个类型:

  • 内置作用域:不需要自己声明,所有的关键字和内置类型、函数都拥有全局作用域
  • 包级作用域:必須函数外声明,在该包内的所有文件都可以访问
  • 文件级作用域:不需要声明,导入即可。一个文件中通过import导入的包名,只在该文件内可用
  • 局部作用域:在自己的语句块内声明,包括函数,for、if 等语句块,或自定义的 {} 语句块形成的作用域,只在自己的局部作用域内可用

语句块

语句块是由花括弧({})所包含的一系列语句。

在 Go 中还有很多的隐式语句块:

  • 主语句块:包括所有源码,对应内置作用域
  • 包语句块:包括该包中所有的源码(一个包可能会包括一个目录下的多个文件),对应包级作用域
  • 文件语句块:包括该文件中的所有源码,对应文件级作用域
  • for 、if、switch等语句本身也在它自身的隐式语句块中,对应局部作用域

类型转换

  • 不存在隐式转换,必须是显示
  • 类型转换必须是在两种兼容的类型之间
  • <变量名称> [:]= <目标类型>( <需要转换的变量名> )

类型转换精度丢失

类型断言

断言,顾名思义就是果断的去猜测一个未知的事物。在 go 语言中,interface{} 就是这个神秘的未知类型,其断言操作就是用来判断 interface{} 的类型。

    var foo interface{} = 22

    f, ok := foo.(int)
    if !ok {
        t.Log("Guess wrong ...")
    }
    t.Logf("The type is : %T", f)   

常量

  • 显示 const idenfity [type] = value
  • 隐式 const identify = value () (无类型常量)

变量类型支持: bool, int, float, string

特殊常量 iota

运算

算术运算

运算符描述实例
+相加A + B 输出结果 30
-相减A - B 输出结果 -10
*相乘A * B 输出结果 200
/相除B / A 输出结果 2
%求余B % A 输出结果 0
++自增A++ 输出结果 11
--自减A-- 输出结果 9

关系运算

运算符描述实例
==检查两个值是否相等,如果相等返回 True 否则返回 False。(A == B) 为 False
!=检查两个值是否不相等,如果不相等返回 True 否则返回 False。(A != B) 为 True
>检查左边值是否大于右边值,如果是返回 True 否则返回 False。(A > B) 为 False
<检查左边值是否小于右边值,如果是返回 True 否则返回 False。(A < B) 为 True
>=检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。(A >= B) 为 False
<=检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。(A <= B) 为 True

逻辑运算

运算符描述实例
&&逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。(A && B) 为 False
\\逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。(A \\B) 为 True
!逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。!(A && B) 为 True

位运算

运算符描述实例
&按位与运算符"&"是双目运算符。 其功能是参与运算的两数各对应的二进位相与。(A & B) 结果为 12, 二进制为 0000 1100
\按位或运算符"\"是双目运算符。 其功能是参与运算的两数各对应的二进位相或(A \B) 结果为 61, 二进制为 0011 1101
^按位异或运算符"^"是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。(A ^ B) 结果为 49, 二进制为 0011 0001
<<左移运算符"<<"是双目运算符。左移n位就是乘以2的n次方。 其功能把"<<"左边的运算数的各二进位全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补0。A << 2 结果为 240 ,二进制为 1111 0000
>>右移运算符">>"是双目运算符。右移n位就是除以2的n次方。 其功能是把">>"左边的运算数的各二进位全部右移若干位,">>"右边的数指定移动的位数。A >> 2 结果为 15 ,二进制为 0000 1111

赋值运算

运算符描述实例
=简单的赋值运算符,将一个表达式的值赋给一个左值C = A + B 将 A + B 表达式结果赋值给 C
+=相加后再赋值C += A 等于 C = C + A
-=相减后再赋值C -= A 等于 C = C - A
*=相乘后再赋值C = A 等于 C = C A
/=相除后再赋值C /= A 等于 C = C / A
%=求余后再赋值C %= A 等于 C = C % A
<<=左移后赋值C <<= 2 等于 C = C << 2
>>=右移后赋值C >>= 2 等于 C = C >> 2
&=按位与后赋值C &= 2 等于 C = C & 2
^=按位异或后赋值C ^= 2 等于 C = C ^ 2
\=按位或后赋值C \= 2 等于 C = C \2

优先级

优先级运算符功能
9() [] -> .后缀运算
8! *(指针) & ++ -- +(正号) -(负号)单目运算
7* / % + -算术运算,加减乘除
6<< >>位运算
5== != < <= > >=逻辑运算、不等、等
4& \^按位 逻辑与、或
3\\&&逻辑或、与
2= += -= *= 等等赋值运算
1,逗号

一元赋值 这两大运算符是 从右到左 关联,其他都是 从左到右 关联。

注意:优先级 值越大则优先级越高。为了方便理解、记忆,我对没有严格按照优先级制表,只是做了个大概!!
更详细的

代码控制语句

if, else, else if

    var number int = 37
    if number += 4; 10 > number {
        fmt.Print("less than 10:", number)
    } else if 10 < number {
        number -= 2
        fmt.Print("greater 10:", number)
    } else {
        
    }

switch, select

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    ia := []interface{}{byte(6), 'a', uint(10), int32(-4), "CC"}
    v := ia[rand.Intn(4)]
    
    // 值 switch
    switch v {
        case 'a' :
            fmt.Println("char: ", v)
        case 10 :
            fmt.Println("uint: ", v)
        case -4 :
            fmt.Println("int: ", v)
        case 0.1 :
            fallthrough
        caes "0.1"
            fmt.Println("float: ", v)
        default :
            fmt.Println("byte: ", v)
    }
    
    // 变量类型 switch
    switch interface{}(v).(type) {
    case string :
        fmt.Printf("Case A.")
    case byte :
        fmt.Printf("Case B.")
    case int :
        fmt.Printf("Case B.")
    default:
        fmt.Println("Unknown!")
    }
}

注意,go语言和其他语言不同的时,每个case代码末尾会自动加上break 操作, 如果你需要使用 fallthrough 来抵消默认的 break

select 用于管道

for

是的 golangforforforeachfor inwhile于一体。

do while 表示:golang你这么绕,不优雅
package main

import (
    "fmt"
    "time"
)

func main() {
    map1 := map[int]string{1: "Golang", 2: "Java", 3: "Python", 4: "C"}
    
    n := 1
    for {   // 省略则默认是true
        if n > 3 {
            break;
        }
        fmt.Println("for true map item: ", map1[n])
        time.Sleep(1)
        n++
    }
    
    for i := 1; i < 4; i++ {
        fmt.Println("for i map item: ", map1[i])
    }
    
    for k,v := range map1 {
        fmt.Print(k, ":", v)
    }
}

goto, break, continue

goto 是跳过代码块

package main

import (
    "fmt"
    "time"
)

func main() {
    code:
        fmt.Println("do some thing~")
        time.Sleep(1)
        
    goto code
}

break 跳出并结束循环

continue 跳过当前循环

虽然不能和PHP那样 break 2 跳出多层, 单只要有goto就能干很多事了。

golang给 循环 就分配了一个 for,语句跳转语句却整了那么多花样

复合数据

内建方法 make & new

内建方法就是不需要引入包就能用的

make 可以创建 slice、map、chan,返回指针类型

  • slice 是可变长的数组
  • map 是key-map 数据数组
  • chan 是go独有的 管道
一股c编程风格扑面而来, char ptr = (char )malloc(sizeof(char) * 5);

内建方法 new

内存置0,返回传入类型的指针地址

package main
import fmt
import reflect

func main() {
    mSlice := make([]string, 3)
    mSlice[0] = "dog"
    mSlice[1] = "cat"
    mSlice[2] = "pig"
    fmt.Println("animals: ", mSlice)
    
    mMap := make(map[int]string)
    mMap[10] = "dog"
    mMap['2'] = "cat"
    fmt.Println(reflect.TypeOf(mMap))
    fmt.Println("animals :: ", mMap)
    
        
    nMap := new(map[int]string)
    fmt.Println(reflect.TypeOf(nMap))
}

append copy delete

slice可以使用copy,append 函数

delete 是专门用来删除 map

  • append(src, ele) 追加元素
  • copy(dst, src) 把src元素赋值到dst上,
  • delete() 删除元素

例子:

package main
import "fmt"

func main() {
    mSlice := make([]string, 3)
    mSlice[0] = "dog"
    mSlice[1] = "cat"
    mSlice[2] = "pig"
    fmt.Println("animals: ", mSlice)

    // append(mSlice, "id-3")   // 这样写会导致报错: append(mSlice, "id-3") evaluated but not used
    mSlice = append(mSlice, "id-3")
    fmt.Println("animals update:", mSlice)
    fmt.Println("animals len :", len(mSlice))
    fmt.Println("animals cap:", cap(mSlice))
    
    // newSlice := make([]string)      // 这样写导致报错:missing len argument to make([]string)
    // newSlice := make([]string, 2)       // 这样写会导致数据丢失2个,不会自动扩容
    newSlice := make([]string, 3)       // 不要多次定义初始化:no new variables on left side of :=
    copy(mSlice, newSlice)          // 这样反向copy,会导致前面的几个数组元素被置为空
    // copy(newSlice, mSlice)
    fmt.Println("animals dst:", mSlice)
    fmt.Println("animals copy:", newSlice)
    
    delete(mMap, 50)
    fmt.Println(mMap)
}

panic & recover

异常处理

panic() 抛出异常

recover() 获取异常

报错会导致程序代码中断,不会再执行后续操作

例子:

package main

import "fmt"
import "errors"

func panicFunc() {
    defer func() {
        // recover()
        message := recover()    // 声明了message 变量就需要使用哦,不然报错
        fmt.Println("panice msg: ", message)
        
        switch message.(type) {
            case string:
            case error:
                fmt.Println("panice error msg: ", message)
            default:
        }
    }()
    // panic("报错啦")
    panic(errors.New("I am error."))
}

func main() {

    panicFunc()
}

len & cap & close

len可以计算 string, array, slice, map, chan
cap 可以计算 slice, map, chan

  • len() 获取数组长度
  • cap() 获取占用空间分配
  • close() 用于关闭管道——chan

当声明一个数组时,go会预先分配一部分空间给当前数组,获取实际空间占用大小,使用cap()

不用像PHP那样,strlen(), count(), length 傻傻分不清楚了。

例子:

package main

import "fmt"

func main() {

    mSlice := make([]string, 3)
    mSlice[0] = "dog"
    mSlice[1] = "cat"
    mSlice[2] = "pig"
    fmt.Println("animals: ", mSlice)

    fmt.Println("animals update:", mSlice)
    fmt.Println("animals len :", len(mSlice))
    fmt.Println("animals cap:", cap(mSlice))

    mChan := make(chan int, 1)
    close(mChan)
    mChan <- 1      // 会导致报错: panic: send on closed channel
}

defer

定一个当前方法关闭时,运行的代码, 压栈设计,先声明的后执行。

结构体

package main

import "fmt"

type Dog struct {
    ID int
    Name string
    Age int32
}

func main() {
    
    var dog Dog
    dog.ID = 1
    dog.Name = "haha"
    dog.Age = 3
    fmt.Println("print Dog Struct", dog)

    dog2 := Dog{ID:2, Name:"san", Age:4}
    fmt.Println("print Dog 2 Struct", dog2)
    
    dog3 := new(Dog)
    dog3.ID = 3
    dog3.Name = "Tom"
    dog3.Age = 5
    fmt.Println("print Dog 3 Struct", dog)
}

输出

print Dog Struct {1 haha 3}
print Dog 2 Struct {2 san 4}
print Dog 3 Struct &{3 Tom 5}

属性 & 函数

接口

/* define an interface */
type interface_name interface {
   method_name1 [return_type]
   method_name2 [return_type]
   ...
   method_namen [return_type]
}

/* define a struct */
type struct_name struct {
   /* variables */
}

/* implement interface methods*/
func (struct_name_variable struct_name) method_name1() [return_type] {
   /* method implementation */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
   /* method implementation */
}

并发

指针

json

需要引入包 encoding/json, 两个函数分别是 json.Marshal(), json.Unmarshal().

注意,最后一个是英文字母小写的L,不是1

json 序列化

package main

import "fmt"
import "encoding/json"

type ServerInfo struct {
    SerName string
    SerIp   string
    SerPort uint16
}

func main() {
    server := new(ServerInfo)
    server.SerName = "http-nginx"
    server.SerIp = "127.0.0.1"
    server.SerPort = 8080
    re,err := json.Marshal(server)
    if nil != err {
        fmt.Println("error: ", err.Error())
    } else {
        fmt.Println("struct json bytes: ", re)
        fmt.Println("struct json string: ", string(re))
    }
    
    mServer := make(map[string]interface{})
    mServer["serverName"] = "apache2-http"
    mServer["serIp"] = "192.168.30.133"
    mServer["serPort"] = "3033"
    mRe,err := json.Marshal(mServer)
    if nil != err {
        fmt.Println("error: ", err.Error())
    } else {
        fmt.Println("map json string: ", string(mRe))
    }
}

输出

struct json bytes:  [123 34 83 101 114 78 97 109 101 34 58 34 104 116 116 112 45 110 103 105 110 120 34 44 34 83 101 114 73 112 34 58 34 49 48 46 49 48 48 46 49 55 46 50 55 58 51 48 48 48 49 34 44 34 83 101 114 80 111 114 116 34 58 56 48 56 48 125]
struct json string:  {"SerName":"http-nginx","SerIp":"10.100.17.27:30001","SerPort":8080}
map json string:  {"serIp":"192.168.30.133","serPort":"3033","serverName":"apache2-http"}
ps: 我也不知道 10.100.17.27:30001 是怎么回事

json 反序列化

可以使用 tag 来做 mapping,
package main

import "fmt"
import "encoding/json"

type ServerInfo struct {
    SerName string  `json:"name"`
    SerIp   string  `json:"ip"`
    SerPort uint16  `json:"port"`
}

func main() {
    // jsonStr := "{\"SerName\":\"http-nginx\",\"SerIp\":\"10.100.17.27:30001\",\"SerPort\":8080}"   \\ 双引号注意转义
    jsonStr := "{\"name\":\"http-nginx\",\"ip\":\"10.100.17.27:30001\",\"port\":8080}"
    
    sServer := new(ServerInfo)
    jsonBytes := []byte(jsonStr)
    uerr := json.Unmarshal(jsonBytes, &sServer)
    if nil != uerr {
        fmt.Println("error: ", err.Error())
    } else {
        fmt.Println("uns struct: ", sServer)
    }
    
    jsonStr3 := `{"serIp":"192.168.30.133","serPort":"3033","serverName":"apache2-http"}`   \\ 使用键盘1旁边的 ` 符号包裹双引号就不用转义了
    
    uSer := make(map[string]interface{})
    uErr := json.Unmarshal([]byte(jsonStr3), &uSer)
    if nil != uErr {
        fmt.Println("error: ", uErr.Error())
    } else {
        fmt.Println("unmar map: ", uSer)
    }
}

输出

uns struct:  &{http-nginx 10.100.17.27:30001 8080}
unmar map:  map[serIp:192.168.30.133 serPort:3033 serverName:apache2-http]

tag

tag 这个东东把,就是json的别名,感觉这个功能是go的特色,与encoding/json包紧密结合。

为什么会有这个东西,我估计是这个和 go命名规则 有关,go命名规则,要求public的变量开头要大写,小写开头的变量是private的,所以,json中的变量就会影响一个接口体变量的访问权限,为了不像java那样复杂,提供了方便的tag功能。

package main

import "fmt"
import "encoding/json"

type ServerInfo struct {
    SerName string  `json:"name"`
    SerIp   string  `json:"ip"`
    SerPort uint16  `json:"port"`
}

func main() {
    
    server := new(ServerInfo)
    server.SerName = "http-nginx"
    server.SerIp = "127.0.0.1"
    server.SerPort = 8080
    re,err := json.Marshal(server)
    if nil != err {
        fmt.Println("error: ", err.Error())
    } else {
        fmt.Println("struct json string: ", string(re))
    }
}

输出

struct json string:  {"name":"http-nginx","ip":"10.100.17.27:30001","port":8080}
map json strin

go 特色语法

_

  • _ 变量

这就好比是Linux 里的 /dev/null, 由于go语言要求声明的变量必须被使用,返回的变量必须被接收,那么真有个变量没用但必须要接受怎么办呢,就把返回的参数给他。例如:

package main
import "fmt"

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
    for _, v := range pow {
        fmt.Printf("value is %d\n", v)
    }
}

这里我们只要值,不要key的信息,返回的key不能不收不是,但我也不像把它输出出来,就让 _ 来接收好了。

  • _ 包

引入包, 并不直接使用这个包,运行时执行一次它的 init() 函数,


import (
    _ "github.com/go-sql-driver/mysql"
    "github.com/jinzhu/gorm"
)

参考

查看原文

赞 5 收藏 3 评论 0

小白要生发 发布了文章 · 2020-10-10

Golang 字符串 格式化

golang format

在 Go 语言中,fmt.Sprintf(), fmt.Printf(), fmt.Fprintf(), Log.Printf(), log.Panicf() 等函数常常会用字符串格式化参数,这一篇文章带你熟悉所有参数。

参数介绍

动 词功 能
%v按值的本来值输出
%+v在 %v 基础上,对结构体字段名和值进行展开
%#v输出 Go 语言语法格式的值
%T输出 Go 语言语法格式的类型和值
%%输出 % 本体
%b整型以二进制方式显示
%o整型以八进制方式显示
%d整型以十进制方式显示
%x整型以十六进制方式显示
%X整型以十六进制、字母大写方式显示
%UUnicode 字符
%f浮点数
%p指针,十六进制方式显示

实战例子

// Go 在传统的`printf` 中对字符串格式化提供了优异的支持。
// 这里是一些基本的字符串格式化的人物的例子。

package main

import "fmt"
import "os"

type point struct {
    x, y int
}

func main() {

    // Go 为常规 Go 值的格式化设计提供了多种打印方式。例
    // 如,这里打印了 `point` 结构体的一个实例。
    p := point{1, 2}
    fmt.Printf("%v\n", p)
    // 输出:{1 2}

    // 如果值是一个结构体,`%+v` 的格式化输出内容将包括
    // 结构体的字段名。
    fmt.Printf("%+v\n", p)
    // 输出:{x:1 y:2}

    // `%#v` 形式则输出这个值的 Go 语法表示。例如,值的
    // 运行源代码片段。
    fmt.Printf("%#v\n", p)
    // 输出:main.point{x:1, y:2}

    // 需要打印值的类型,使用 `%T`。
    fmt.Printf("%T\n", p)
    // 输出:main.point

    // 格式化布尔值是简单的。
    fmt.Printf("%t\n", true)
    // 输出:true

    // 格式化整形数有多种方式,使用 `%d`进行标准的十进
    // 制格式化。
    fmt.Printf("%d\n", 123)
    // 输出:123

    // 这个输出二进制表示形式。
    fmt.Printf("%b\n", 14)
    // 输出:1110

    // 这个输出给定整数的对应字符。
    fmt.Printf("%c\n", 33)
    // 输出:!

    // `%x` 提供十六进制编码。
    fmt.Printf("%x\n", 456)
    // 输出:1c8

    // 对于浮点型同样有很多的格式化选项。使用 `%f` 进
    // 行最基本的十进制格式化。
    fmt.Printf("%f\n", 78.9)
    // 输出:78.900000

    // `%e` 和 `%E` 将浮点型格式化为(稍微有一点不
    // 同的)科学技科学记数法表示形式。
    fmt.Printf("%e\n", 123400000.0)
    // 输出:1.234000e+08
    fmt.Printf("%E\n", 123400000.0)
    // 输出:1.234000E+08

    // 使用 `%s` 进行基本的字符串输出。
    fmt.Printf("%s\n", "\"string\"")
    // 输出:"string"

    // 像 Go 源代码中那样带有双引号的输出,使用 `%q`。
    fmt.Printf("%q\n", "\"string\"")
    // 输出:"\"string\""

    // 和上面的整形数一样,`%x` 输出使用 base-16 编码的字
    // 符串,每个字节使用 2 个字符表示。
    fmt.Printf("%x\n", "hex this")
    // 输出:6865782074686973

    // 要输出一个指针的值,使用 `%p`。
    fmt.Printf("%p\n", &p)
    // 输出:0x42135100

    // 当输出数字的时候,你将经常想要控制输出结果的宽度和
    // 精度,可以使用在 `%` 后面使用数字来控制输出宽度。
    // 默认结果使用右对齐并且通过空格来填充空白部分。
    fmt.Printf("|%6d|%6d|\n", 12, 345)
    // 输出:|    12|   345|

    // 你也可以指定浮点型的输出宽度,同时也可以通过 宽度.
    // 精度 的语法来指定输出的精度。
    fmt.Printf("|%6.2f|%6.2f|\n", 1.2, 3.45)
    // 输出:|  1.20|  3.45|

    // 要左对齐,使用 `-` 标志。
    fmt.Printf("|%-6.2f|%-6.2f|\n", 1.2, 3.45)
    // 输出:|1.20  |3.45  |

    // 你也许也想控制字符串输出时的宽度,特别是要确保他们在
    // 类表格输出时的对齐。这是基本的右对齐宽度表示。
    fmt.Printf("|%6s|%6s|\n", "foo", "b")
    // 输出:|   foo|     b|

    // 要左对齐,和数字一样,使用 `-` 标志。
    fmt.Printf("|%-6s|%-6s|\n", "foo", "b")
    // 输出:|foo   |b     |

    // 到目前为止,我们已经看过 `Printf`了,它通过 `os.Stdout`
    // 输出格式化的字符串。`Sprintf` 则格式化并返回一个字
    // 符串而不带任何输出。
    s := fmt.Sprintf("a %s", "string")
    fmt.Println(s)
    // 输出:a string

    // 你可以使用 `Fprintf` 来格式化并输出到 `io.Writers`
    // 而不是 `os.Stdout`。
    fmt.Fprintf(os.Stderr, "an %s\n", "error")
    // 输出:an error
}
  • 结果
{1 2}
{x:1 y:2}
main.point{x:1, y:2}
main.point
true
123
1110
!
1c8
78.900000
1.234000e+08
1.234000E+08
"string"
"\"string\""
6865782074686973
0xc000100010
|    12|   345|
|  1.20|  3.45|
|1.20  |3.45  |
|   foo|     b|
|foo   |b     |
a string
an error

参考

查看原文

赞 1 收藏 0 评论 0

小白要生发 发布了文章 · 2020-10-10

Windows 下 Golang 多版本管理

Windows 下 golang 多版本管理

当前 golang 各个版本还是有些许不兼容,最近遇到 go-micro 框架只能运行在 go 1.13 ~ 1.14 版本,而我Windows 下安装的又是 1.15,所以这时就需要安装 其他版本的golang,那么多版本 golang 如何在 Windows 上共存呢。

如果你在以下操作过程中,发现命令不生效,可以新开一个命令行窗口进行重试。

接下来会给大家介绍我尝试过的 4 种方案。 最好的方案是第四个,第一、三个方案失败了。

建目录 改 PATH

在Windows 安装好 golang,在 cmd 通过运行

$ go verstion
go version go1.15.2 windows/amd64

因为在 PATH 变量中配置了 gobin目录, 所以在 cmd 能直接运行 go.exe

那么可不可以在不删除原有golang的情况下,新创建一个文件夹 C:\Go1.13 来存放我们新版本 golang。

运行新下载的安装程序

选择 Uninstall ,没关系,我们已经把 PATH 去掉了,他找不到删除目录的。

输入我们给他配置的新目录

安装后,我傻眼了,其他文件都安装在 C:\Go1.13 里,而这个却安装在了 C:\Go 目录里

而之前安装的 Go1.15.2 被卸载了。我就想创建个目录 C:\Go1.15.2,来重新安装 go 1.13.14, 我都把 PATH 删除了,它还是找到文件并删除了。

所以通过多个目录安装不同版本golang的办法是行不通的。

go get

这个是官方建议

# 还能 get 其他版本的golang
$ go get golang.org/dl/go1.15.2

# 下载这一步不能少
$ go1.15.2 download

# 检查下吧
$ go1.15.2 version
go version go1.15.2 windows/amd64

# 默认的 golang 版本
$ go version
go version go1.13.14 windows/amd64

新安装的 go1.15.2.exe%USERPROFILE%\go\bin 目录下.

注意以上以上方法需要访问 google 的服务,所以你懂的。

你不仅要设置 http代理,还需要设置 git 的全局代理!

gvm

gvm

以下命令均在 git bash 环境运行,不是 windows cmd 环境!

本文地址

安装

$ bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)

# 代理访问
$ bash < <(curl -x socks5://james:cats@myproxy.com:8080 -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)

Cloning from https://github.com/moovweb/gvm.git to /c/Users/wojia/.gvm
Created profile for existing install of Go at C:\Users\wojia\.g\go
Installed GVM v1.0.22

Please restart your terminal session or to get started right away run
 `source /c/Users/w/.gvm/scripts/gvm`

最后一行提示我们新开一个 terminal, 并运行命令 source /c/Users/w/.gvm/scripts/gvm , 我们来看看里面有什么动作。

$ cat /c/Users/w/.gvm/scripts/gvm

export GVM_ROOT=/c/Users/w/.gvm
. $GVM_ROOT/scripts/gvm-default

这显然是一个配置脚本。

配置

在 Windows 新增 GVM_ROOT 环境变量后,看看这个配置脚本。

cat $GVM_ROOT/scripts/gvm-default
unset GOROOT
unset GOARCH
unset GOOS
unset GOPATH
unset GOBIN

unset gvm_go_name
unset gvm_pkgset_name

mkdir -p "$GVM_ROOT/logs" > /dev/null 2>&1
mkdir -p "$GVM_ROOT/gos" > /dev/null 2>&1
mkdir -p "$GVM_ROOT/archive" > /dev/null 2>&1
mkdir -p "$GVM_ROOT/archive/package" > /dev/null 2>&1
mkdir -p "$GVM_ROOT/environments" > /dev/null 2>&1

export GVM_VERSION=$(cat "$GVM_ROOT/VERSION")
export PATH="$GVM_ROOT/bin:$PATH"
export GVM_PATH_BACKUP="$PATH"
[ -f "$GVM_ROOT/environments/default" ] && . "$GVM_ROOT/environments/default"
. "$GVM_ROOT/scripts/env/gvm"

也就是说需要配置 环境变量: GVM_VERSIONGVM_PATH_BACKUP, PATH

使用

配置好后,试一下。

$ gvm install go1.4
C:\Users\w\.gvm/scripts/functions: line 3: C:\Users\w\.gvm/scripts/function/*: No such file or directory

看来 shell 脚本没有针对 Windows 做调整,看来 gvm 没有对 Windows 做兼容。

g

最后来看看 g

安装

windows 的话,就直接上 github release 页面下载目标文件:

直接将解压后的 g.exe 放入 PATH 目录下即可

$ g -v
g version 1.2.0

# 安装成功!

配置

针对 Windows 需要 将原有的 C:/Go/binPATH 中移除,新增 %USERPROFILE%\.g\go\bin

如果 Goland import 有报错,就需要调整下 GOROOT, GOPATH 配置

这里需要调整为 C:\Users\w\.g\go 目录。

使用

查询当前可供安装的stable状态的go版本

$ g ls-remote stable
  1.13.15
  1.14.7

安装目标go版本1.14.7

$ g install 1.14.7
Downloading 100% |███████████████| (119/119 MB, 9.939 MB/s) [12s:0s]
Computing checksum with SHA256
Checksums matched
Now using go1.14.7

查询已安装到本地的 go版本

$ g ls
  1.7.6
  1.11.13
  1.12.17
  1.13.15
  1.14.6
* 1.14.7

查询可供安装的所有go版本

$ g ls-remote
  1
  1.2.2
  1.3
  1.3.1
  ...    // 省略若干版本
  1.14.5
  1.14.6
* 1.14.7
  1.15rc1

切换到另一个已安装的go版本

$ g use 1.14.6
go version go1.14.6 darwin/amd64

卸载一个已安装的go版本

$ g uninstall 1.14.7
Uninstalled go1.14.7

总结

就目前(2020年10月)来看,gWindows 上最好的 golang 多版本管理软件,golang 的官方方案也不错,不过运行go命令需要加版本号,容易和 shell脚本耦合。

gvm 还未适配 Windows。 而多开文件夹,改PATH就是个笑话了,大家图个乐。

参考

查看原文

赞 0 收藏 0 评论 0

小白要生发 关注了用户 · 2020-08-16

Raymond @_raymond

联系我

email: try-raymond@foxmail.com

vx:gpboyer

关注 280

小白要生发 发布了文章 · 2020-08-15

PHP Javascript 语法对照

PHP、JavaScript 语法对照、速查

php vs JS

全栈工程师看过来,学的计算机语言多了,往往会把不同语言的各个函数搞混。作为一个全栈PHPer,往往PHP、JavaScript 语法傻傻分不清楚,百度一下,查手册要网速。不如收藏下这篇文章,打印出来,贴到一旁快速查阅。

JavaScript 的一些数组map函数有jQuery实现,ES6后,又出了官方实现。PHP 的数组、字符串相关函数的命名随性,这仨一块就更容易混淆了。

编码风格

语言PHPJavaScript
换行; 号 换行符号是必须的换行 \n,以及 号都不是必须的
大小写敏感度只有变量名区分大小写变量名、函数名、类名等 都区分大小写
严格模式declare(strict_types=1); (PHP7新特性)"use strict";(ECMAScript 5 引入)

变量声明

语言PHPJavaScript
常量const VAR_NAME = 12; <br/> define('VAR_NAME', 12);const MY_FAV = 7; (ES6引入的标准)
局部变量$varName = 12; (PHP严格的来讲,只有函数作用域,或者全局作用域)function myFunc() { <br/> var varName = 3; <br/> if (true) {<br/> let varName2 = 2;<br/>}<br/>}<br/> (函数作用域内必须用var声明,否则变量全局可访问.)<br/>(let修饰的变量就是块级别作用域,ES6引入) <br/>
全局变量$varName = 12; <br/> function myFunc() {<br/> global $varName; <br/> } <br/> (函数内使用全局变量,必须要用global变量声明使用外部的全局变量)var varName1 = 3; <br/> varName2 = 2; <br/> function myFunc() {<br/> varName3 = 6; <br/> } (这里写法varName1,2,3都是全局变量)
全局符号表$GLOBALS 数组window 对象
为定义变量nullundefined

变量转换

语言PHPJavaScript
转bool,boolean$bar = (boolean) $foo; <br/> $bar = (bool) $foo; <br/> $bar = boolval($foo);boolVal = Boolean('')
转 int$bar = (int) $foo; <br/> $bar = (integer) $foo; <br/> $bar = intval($foo);intVal = Number("314") <br/> intVal = parseInt("3.14")
转 float$bar = (float) $foo;<br/>$bar = (double) $foo;<br/>$bar = (real) $foo;<br/>$bar = floatval($foo);floatVal = Number("3.14") <br/> flotaVal = parseFloat("12")
转换为 string$bar = (string) $foo; <br/> $bar = strval($foo);str = String(123) <br/> str = (123).toString()
转换为 array$arr = (array) new stdClass();(需要多行函数完成)
转换为 对象$obj = (object) array('1' => 'foo');let arr = ['yellow', 'white', 'black']; <br/> let obj = {...arr}
时间戳转日期$date = new DateTime(); <br/> $date->setTimestamp(1171502725);var date = new Date(1398250549490);
字符转日期$dateObj = new DateTime($dateStr);var myDateObj = new Date(Date.parse(datetimeStr))
转换为 空(unset) $var; \ 不会删除该变量或 unset 其值。仅是返回 NULL 值而已
获取类型$varType = gettype($var);varType = typeof myCar
类判断$boolRe = $a instanceof MyClass;boolRe = a instanceof MyClass <br/> new Date().constructor === Date

运算符

语言PHPJavaScript
三目(三元)运算$a = $a ? $a : 1;//第一种 <br/> $a = $a ? : 1;//第二种 PHP5.3支持re = isMember ? 2.0 : '$10.00'
合并运算符$a = $a ?? 1; // PHP7支持

数组

语言PHPJavaScript
基本$a=array(0 => 1, 1 => 2,4,5,6); <br/> $array = [ "foo" => "bar", "bar" => "foo"]; // PHP 7语法b = [1,2,3]
追加$arr = array(); <br/> $arr[key1] = value1; <br/> $arr[key2] = value2;var mycars=new Array()<br/>mycars[0]="Saab"<br/>mycars[1]="Volvo"<br/>mycars[2]="BMW"
newvar mycars = new Array("Saab","Volvo","BMW")

循环

语言PHPJavaScript
for 循环for ($i=1; $i<=5; $i++) <br/> {<br/> echo $i ; <br/> } <br/>for (var i=0; i < cars.length ; i++) <br/> { <br/>document.write(cars[i]); <br/>}
foreach ,for in 循环$x=array("one","two","three"); <br/> foreach ($x as $value) <br/> { <br/> echo $value; <br/>}var person= {fname:"John",lname:"Doe",age:25}; <br/> for (x in person) // x 为属性名 <br/> { <br/>txt=txt + person[x]; <br/> }
while 循环while($i <= 5) <br/> { <br/> echo $i ; <br/>$i++; <br/> }while (i<5)<br/>{<br/>x=x + "The number is " + i + "
";<br/> i++;<br/>}
do while 循环do {<br/> $i++;<br/> echo $i;<br/>} while ($i<=5);do<br/>{<br/> document.write(i);<br/> i++;<br/>}<br/>while (i<5);

本文来自

数组函数

语言PHPJavaScript
获取数组中元素的数目count($arr);arrayObject.length
拼接两个字符串array_merge($arr1, $arr2);arr1.concat(arr2)
删除数组元素unset($arr[$key]);delete arr1[key]
将数组拼接成字符串implode(',', $arr1);arr.join(‘,’)
删除并返回数组最后元素$re = array_pop($arr1);re = arrayObject.pop()
向数组的末尾添加一个元素array_push($arr1, $var1);len = arrayObject.push(newele1)
将数组的第一个元素删除并返回$re = array_shift($arr1);re = arrayObject.shift()
向数组的开头添加一个或更多元素array_unshift($arr1, $var1);len = arrayObject.unshift(newele1)
从已有的数组中返回选定的元素$newArr = array_splice($arr1,$start,$len);newArr = arrayObject.slice(start,end)
排序sort($arr1);arrayObject.sort(sortByFunc = null)
颠倒数组中元素的顺序array_reverse(&$arr, $keepKeys = true);arrayObject.reverse()
each 函数function map_Spanish($n)<br/>{<br/> echo $n;<br/>}<br/>$b = array("uno", "dos", "tres", "cuatro", "cinco");<br/>$c = array_map("show_Spanish", $a);$.each([ 52, 97 ], function( index, value ) {<br/>alert( index + ": " + value );<br/>}); <br/> jQuery 方式 <br/> const items = ['item1', 'item2', 'item3']; <br/> items.forEach(function(item, index, arr){<br/> console.log('key:' + index + ' value:' + item);<br/>}); <br/> (ES6引入)
回调函数迭代地将数组简化为单一的值function sum($carry, $item) {<br/> $carry += $item;<br/> return $carry;<br/>}<br/>$a = array(1, 2, 3, 4, 5);<br/>var_dump(array_reduce($a, "sum")); // int(15)var numbers = [65, 44, 12, 4];<br/>function getSum(total, num) {<br/> return total + num;<br/>}<br/>console.log(numbers.reduce(getSum));<br/> 始于ECMAScript 3
用回调函数过滤数组中的单元function odd($var) {<br/> // returns whether the input integer is odd<br/> return($var & 1);<br/>}<br/>$array1 = array("a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5);<br/>echo "Odd :\n";<br/>print_r(array_filter($array1, "odd"));function isBigEnough(element) {<br/> return element >= 10;<br/>}<br/>var filtered = [12, 5, 8, 130, 44].filter(isBigEnough); \ JavaScript 1.6 引入

字符

语言PHPJavaScript
创建$str = "a string"; <br/> \\\\比较特殊的是PHP在双引号字符中可以解析变量 <br/> $str2 = 'tow string';var carname = "Volvo XC60"; <br/> var carname = 'Volvo XC60';<br/> (同样的在双引号中可以使用转义字符)
多行字符$bar = <<<EOT<br/> foo<br/>bar<br/>EOT;<br/>var tmpl ='<br/> !!! 5<br/> html<br/> include header<br/> body<br/> include script'
字符拼接$str1 . $str2str1 + str2

字符串函数

语言PHPJavaScript
获取字符长度strlen($str);string.length
获取子字符串substr ( string $string , int $start [, int $length ] ) : stringstring.substr(start,length) <br/> str.slice(1,5);
使用一个字符串分割另一个字符串$pizza = "piece1 piece2 piece3 piece4 piece5 piece6";<br/>$pieces = explode(" ", $pizza);<br/>echo $pieces[0]; // piece1var str="How are you doing today?"; <br/> var n=str.split(" "); <br/>\ output:How,are,you,doing,today?
去除字符串首尾处的空白字符(或者其他字符)trim ( string $str [, string $character_mask = " tnr0x0B" ] ) : string <br/> (PHP 函数的可定制要强一点)var str = " string "; <br/> alert(str.trim());
查找字符串首次出现的位置$mystring = 'abcsdfdsa'; <br/> $pos = strpos($mystring, 'cs');var str="Hello world, welcome to the universe.";<br/>var n=str.indexOf("welcome");
把字符串转换为小写strtolower ( string $string ) : stringstring.toLowerCase()
把字符串转换为大写strtoupper ( string $string ) : stringstring.toUpperCase()

对象

语言PHPJavaScript
空对象$obj = new stdClass();var obj = new Object(); // 或者 <br/> person={firstname:"John",lastname:"Doe",age:50,eyecolor:"blue"};
对象属性$obj = new stdClass(); <br/> $obj->a = 12;var myCar = new Object(); <br/> myCar.year = 1969; // js还可以以数组形式 <br/> myCar["year"] = 1969;
删除属性unset($obj->a);delete object.property <br/> delete object['property']

正则

语言PHPJavaScript
创建正则表达式$pattern = "/.*/i";var re = /ab+c/;
PCRE 正则int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )var myRe = /d(b+)d/g; <br/> var myRe = new RegExp("d(b+)d", "g");
POSIX 正则ereg ( string $pattern , string $string [, array &$regs ] ) : int(无)

数学函数

语言PHPJavaScript
随机函数$re = mt_rand($min, $max); // 返回 min~max 之间的随机整数Math.random() // 返回 0 ~ 1 之间的随机数
x的y次方pow(x,y)Math.pow(x,y)

其他

语言PHPJavaScript
展开,可变函数function add(...$numbers) { <br> foreach ($numbers as $n) { <br> $sum += $n;
}
}
echo add(1, 2, 3, 4); // PHP5.6 开始支持
function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction(...args); (ES6开始支持)
解构$my_array = array('a'=>'Dog','b'=>'Cat','c'=>'Horse'); <br> list($a, $b, $c) = $my_array; <br>// php5, 如果是php7版本支持以下语法 <br> ['a'=>$a, 'c'=>$c] = $my_array;var date1 = [1970, 2, 1];
[ year, mouth ]= date1;
var date2 = {year: 1980, mouth: 3, day: 21};
({ mouth } = date2);
console.log(date1);
console.log(year);
console.log(mouth);

欢迎大家收藏,如果你觉得需要补充的地方,请留言。

查看原文

赞 8 收藏 7 评论 9

小白要生发 发布了文章 · 2020-08-05

Synergy-core 编译 使用 教程

Synergy

如果你平时同时两台或多台电脑,你是如何他们之间协作的,又是如何共享文件的呢?

诚然我知道Windows官方出品的鼠标有 无界 功能。提供文件共享的服务有很多。而今天我想介绍的Synergy,让普通键鼠就能跨屏幕操作,还能复制粘贴文字,图片等。而且还不受平台限制,只两台桌面电脑ip互联互通。

无界鼠标由于是微软出品的,所以只支持 Windows 平台,安装包也是 MSI 文件格式。

Synergy是一个跨平台的 鼠标、键盘、剪切板共享软件,支持Windows,Mac,Linux主流桌面平台。也就是说你可以用连接在Mac电脑上键鼠,操作旁边的Windows电脑。

官网:https://symless.com/synergy

开源地址:https://github.com/symless/synergy-core

下载

GUI版程序只能官网付费上下载,没有登陆App Store, 还有点需要注意1.8.8及以前的版本都是32位的程序,所以这次来折腾下64位的开源版。

Mac OS Cotalina 开始,就完全不能运行32位的程序了

安装

如果是官网下载Synergy GUI版,那双击就完事了。

编译

这里说下github上开源的core版本,编译,安装。

Mac OS 编译

安装依赖,编译软件,编译,安装:

# Install Homebrew

## 安装相关编译软件
$ brew install cmake
$ brew install qt
$ brew install openssh
$ brew install git

## 检查qt 安装信息,以及目录,等下需要用到 /usr/local/Cellar/qt/5.15.0/Frameworks/
$ brew info qt

## 添加一个环境变量
$ export CMAKE_PREFIX_PATH="/usr/local/Cellar/qt/5.15.0/Frameworks/"

# 下载源码并进入源码目录
$ git clone https://github.com/symless/synergy-core.git
$ cd synergy-core
$ mkdir build
$ cd build
## 准备编译参数
$ cmake -DCMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk  -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_OSX_ARCHITECTURES=x86_64 
## 编译
make

Windows 编译

$ cd Projects\synergy
$ mkdir build
$ cd build
$ call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
$ cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_BUILD_TYPE=Debug ..
$ msbuild synergy-core.sln /p:Platform="x64" /p:Configuration=Debug /m
$ cd ..
$ copy ext\openssl\windows\x64\bin\* build\

Linux 编译

$ cd Projects/synergy
$ mkdir build
$ cd build
$ cmake ..
$ make

编译成功,会生成3个可执行文件。编辑后产物在:

./synergy-core/build/bin/

可执行文件

synergy-core

命令行程序:synergy-core, synergyc, synergys.

Synergy Core v1.x

对于1.x版本,client,server是两个程序,也就是分别对应:synergyc,synergys。

OSCommand
Windowssynergyc [server IP]
macOS./synergyc [server IP]
Linux./synergyc [server IP]
OSCommand
Windowssynergys -c [path to config file]
macOS./synergys -c [path to config file]
Linux./synergys -c [path to config file]

Synergy Core v2.x

v2.x,server,client 都是一个程序了,通过不同的命令来确定自己的职责。

OSCommand
Windowssynergy-core --client [server IP]
macOS./synergy-core --client [server IP]
Linux./synergy-core --client [server IP]
OSCommand
Windowssynergy-core --server -c [path to config file]
macOS./synergy-core --server -c [path to config file]
Linux./synergy-core --server -c [path to config file]

Command help

通过一下命令:

$ ./synergyc --help
$ ./synergys --help

你能获取v1.x synergy的帮助信息,但是v2.x不知道是不是忘了把这个加上。

$ ./synergy-core --help     ## 不会显示帮助信息

所以我就把它应有的帮助信息放这里了。

Options for synergy-core --client

Usage: synergy-core --client [--yscroll <delta>] [--daemon|--no-daemon] [--name <screen-name>] [--restart|--no-restart] [--debug <level>] <server-address>

Connect to a synergy mouse/keyboard sharing server.

  -d, --debug <level>      filter out log messages with priority below level.
                             level may be: FATAL, ERROR, WARNING, NOTE, INFO,
                             DEBUG, DEBUG1, DEBUG2.
  -n, --name <screen-name> use screen-name instead the hostname to identify
                             this screen in the configuration.
  -1, --no-restart         do not try to restart on failure.
*     --restart            restart the server automatically if it fails.
  -l  --log <file>         write log messages to file.
      --no-tray            disable the system tray icon.
      --enable-drag-drop   enable file drag & drop.
  -f, --no-daemon          run in the foreground.
*     --daemon             run as a daemon.
      --yscroll <delta>    defines the vertical scrolling delta, which is
                             120 by default.
  -h, --help               display this help and exit.
      --version            display version information and exit.

* marks defaults.

The server address is of the form: [<hostname>][:<port>].  The hostname
must be the address or hostname of the server.  The port overrides the
default port, 24800.

原文来自

Options for synergy-core --server

Usage: synergy-core --server [--address <address>] [--config <pathname>] [--daemon|--no-daemon] [--name <screen-name>] [--restart|--no-restart] [--debug <level>]

Start the synergy mouse/keyboard sharing server.

  -a, --address <address>  listen for clients on the given address.
  -c, --config <pathname>  use the named configuration file instead.
  -d, --debug <level>      filter out log messages with priority below level.
                             level may be: FATAL, ERROR, WARNING, NOTE, INFO,
                             DEBUG, DEBUG1, DEBUG2.
  -n, --name <screen-name> use screen-name instead the hostname to identify
                             this screen in the configuration.
  -1, --no-restart         do not try to restart on failure.
*     --restart            restart the server automatically if it fails.
  -l  --log <file>         write log messages to file.
      --no-tray            disable the system tray icon.
      --enable-drag-drop   enable file drag & drop.
  -f, --no-daemon          run in the foreground.
*     --daemon             run as a daemon.
  -h, --help               display this help and exit.
      --version            display version information and exit.

* marks defaults.

The argument for --address is of the form: [<hostname>][:<port>].  The
hostname must be the address or hostname of an interface on the system.
The default is to listen on all interfaces.  The port overrides the
default port, 24800.

If no configuration file pathname is provided then the first of the
following to load successfully sets the configuration:
  $HOME/.synergy.conf
  /etc/synergy.conf

配置

GUI的配置就不讲了,这里说下cli程序的配置。

原文在这里Synergy Text Config,我这里简单提一下。然后按照我给的模版来改改就能用,需要特殊定制可看看官方wiki,或者留言问我。

Synergy 的配置文件基本格式:

section: ''name''
    ''args''
end

配置类型有4大类:

  • screens
  • aliases
  • links
  • options

aliases

定义 host name 和 屏幕命名的关系。

那么如何获取 host name呢?

mac os 环境下:

$ hostname
## 或者
$ echo $HOSTNAME

screens

定义我们的屏幕,命名,以及在操作各个屏幕时,是否响应一些特殊按键。

Windows,Linux,Mac 都有各自的特殊按键,如win, command, meta按键等,如果不是跨平台,都不需要做特殊处理。

links

定义各个屏幕之间的排列方位,这个很重要。

{left|right|up|down}[<range>] = name[<range>]

关于range参数就比较有意思了,合理配置可是下如下效果。

section: links
     moe:
         right        = larry
         up(50,100)   = curly(0,50)
     larry:
         left         = moe
         up(0,50)     = curly(50,100)
     curly:
         down(0,50)   = moe
         down(50,100) = larry(0,50)
 end

实现了:

#       +-----------+  
#       |   curly   |  
#       |           | 
#       +-----------+ 
# +----------+ +----------+
# |    moe   | |  larry   | 
# |          | |          | 
# +----------+ +----------+ 

也就是在curly屏幕时,鼠标往左下滑,会滑到moe屏幕,往右下滑,会滑到larray屏幕。

options

其他选项,例如定义心跳间隔,屏幕切换粘连时间,

配置样例

好的还是来一个大而全的配置文件例子吧。

启动一个Synergy-core server,配置文件是必须的!

Example textual configuration file
This example comes from doc/synergy-basic.conf

# sample synergy configuration file
#
# comments begin with the # character and continue to the end of
# line.  comments may appear anywhere the syntax permits.
# +----------+  +---------+ +---------+
# | mac-mini |  | macbook | | windows |
# |          |  |         | |         |
# +----------+  +---------+ +---------+

section: screens
    # three hosts named:  mac-mini, macbook, and windows
    # These are the nice names of the hosts to make it easy to write the config file
    # The aliases section below contain the "actual" names of the hosts (their hostnames)
    mac-mini:
    macbook:
    windows:
end

section: links
    # windows is to the right of macbook
    # mac-mini is to the left of macbook
    macbook:
        right(0,100) = windows # the numbers in parentheses indicate the percentage of the screen's edge to be considered active for switching)
        left  = mac-mini
        # shift = shift (shift, alt, super, meta can be mapped to any of the others)

    # macbook is to the right of mac-mini
    mac-mini:
        right = macbook

    # macbook is to the left of windows
    windows:
        left  = macbook
end

section: aliases
    # The "real" name of windows is John-Smiths-windows-3.local. 
    # If we wanted we could remove this alias and instead use John-Smiths-windows-3.local everywhere windows is above. 
    # Hopefully it should be easy to see why using an alias is nicer
    macbook:
        Pauls-MBP.local
    mac-mini:
        jumei-deMac-xp-mini.local
end

section: options
    switchDelay = 400   # 鼠标滑到边缘时,提留多久才能切换屏幕
    clipboardSharing = true # 共享剪切板
    clipboardSharingSize = 10000    # 剪切板共享字节大小限制,单位:千字节
end

启动

## 启动服务端
$ ./synergy-core --server --address 172.20.50.25:24800 --no-daemon --name macbook --config ./synergy.conf

## 启动其中一个客户端
$ ./synergy-core --client --no-daemon --name mac-mini 172.20.50.25:24801

常见问题

问题1:FATAL: An error occurred: assistive devices does not trust this process, allow it in system settings.

这是应为你运行命令行程序调用了系统的敏感接口,所有报错了。你需要给这个命令行软件授予权限.

也就是说,你用iTerm运行Synergy-core,就给iTerm授权,你用系统terminal运行的就给terminal授权。

我用的Mac,就在 系统偏好设置 > 安全性隐私 > 隐私 为其配置上。

赋予权限

如果是第一次授权,一般会有个弹窗,你按照弹框点进去就行了。

问题2: synergy-core[66198:16759205] pid(66198)/euid(501) is calling TIS/TSM in non-main thread environment, ERROR : This is NOT allowed. Please call TIS/TSM in main thread!!!

你是不是还启动 Synergy GUI 程序,把它关掉就好了。

总结

synergy-core程序用着还不错,虽然配置麻烦了一点,不过鼠标,键盘映射都没问题,复制粘贴(图片都能跨屏幕传)也都正常。不过还没试过跨macos,windows使用过。试了再回来

参考

查看原文

赞 0 收藏 0 评论 0

认证与成就

  • 获得 233 次点赞
  • 获得 7 枚徽章 获得 0 枚金徽章, 获得 1 枚银徽章, 获得 6 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2017-12-16
个人主页被 5.6k 人浏览