**这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天**
在学习GO语言的过程中会出一系类的go由浅入深的系列文章,敬请期待!
Go语言是一门**现代编程语言**,规则简单,统一,优雅,吸收了若干编程语言的优点,解决了C,C++, Python等语言一些固有的难点问题
Go是一种过程编程语言,可用于快速机器代码编译。它是一种静态类型的编译语言。它提供了并发机制,可以轻松开发多核和联网的机器级程序。它是快速,动态类型和解释语言;它提供对接口和类型嵌入的支持。
Go语言是由Google的Robert Griesemer,Rob Pike和Ken Thompson 于2007年开发,但于2009年作为开源编程语言推出。
**注:** go语言源代码文件的扩展名必须是.go 。
GO语言的优点:
1高性能、高并发
2语法简单、学习曲线平缓
3丰富的标准库
Go具有强大的标准库,以包的形式分发。
4完善的工具链
5静态链接
Go是静态类型语言。因此,在这个编译器中,不仅可以成功编译代码,还可以确保类型转换和兼容性。由于这个特性,Go避免了我们在动态类型语言中遇到的所有问题。
6快速编译
7跨平台
Go语言就像Java语言一样,支持平台独立。由于其模块化设计和模块化,即代码被编译并转换为尽可能小的二进制形式,因此,它不需要依赖性。它的代码可以在任何平台上编译,也可以在任何服务器和应用程序上编译。
8垃圾回收
Go语言的设计者有意识地保持语言简单易懂。整个细节都在少量(一部分)页面中,并且通过语言中的面向对象支持做出了一些有趣的设计决策。对此,语言是固执的,并推荐一种实现事物的惯用方法。它更喜欢组合而不是继承。在Go语言中,“少花钱多办事”就是口头禅。
一个有开发经验的程序员,仅仅耗费一周就可以由学习阶段转到真正的开发阶段,完成一个高并发的应用开发。
如下图
哪些公司在使用Go语言:
使用Goland,学生可以申请教育免费版:
Hello World:
package main
import (
"fmt"
)
func main() {
fmt.Println("hello world,上进小菜猪")
}
上述代码解释:
package main:程序的入口包。入口文件
import 的fmt控制输入输出文件:
import ( "fmt" )
main函数调用了fmt的Println
运行结果:
声明变量:
1.使用var。
var a = "initial"
var b, c int = 1, 2
var d = true
2.使用变量名:=值。
f := float32(e)
g := a + "foo"
GO会更具上下文的类型来自动确定类型。
3.例子
引用:fmt和math
import (
"fmt"
"math"
)
main函数:
var a = "initial"
var b, c int = 1, 2
var d = true
var e float64
f := float32(e)
g := a + "foo"
fmt.Println(a, b, c, d, e, f) // initial 1 2 true 0 0
fmt.Println(g) // initialapple
const s string = "constant"
const h = 500000000
const i = 3e20 / h
fmt.Println(s, h, i, math.Sin(h), math.Sin(i))
运行结果如下:
1.if后面不需要写括号的:例如
if 7%2 == 0 {
fmt.Println("7 is even")
} else {
fmt.Println("7 is odd")
}
2.import的简单写法:
import "fmt"
3.main函数:
if 7%2 == 0 {
fmt.Println("7 is even")
} else {
fmt.Println("7 is odd")
}
if 8%4 == 0 {
fmt.Println("8 is divisible by 4")
}
if num := 9; num < 0 {
fmt.Println(num, "is negative")
} else if num < 10 {
fmt.Println(num, "has 1 digit")
} else {
fmt.Println(num, "has multiple digits")
}
运行结果如下:
go里面只有for循环,没有while循环,没有do while循环。
简单的for循环如下:
for {
fmt.Println("loop")
break
}
可以使用经典的c语言里的for循环:
for j := 7; j < 9; j++ {
fmt.Println(j)
}
也可以使用continue跳出循环:
for n := 0; n < 5; n++ {
if n%2 == 0 {
continue
}
fmt.Println(n)
}
运行结果如下:
分支结构和c、c++类似。
不同点:
c/c++如果没有break还会跑下面的同级分支,go则不会。
例子:
1.引入time时间库:
import (
"fmt"
"time"
)
2.源码:
先给a赋值为2,然后循环下面的值,运行fmt.Println("two"),没有break语句也会跳出这个switch。
t := time.Now()使用time库,将现在的系统时间赋值给t,然后进行case条件分支,否则抛出It's after noon。
a := 2
switch a {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
case 3:
fmt.Println("three")
case 4, 5:
fmt.Println("four or five")
default:
fmt.Println("other")
}
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("It's before noon")
default:
fmt.Println("It's after noon")
}
运行结果如下:
先定义一个5个长度的数组,然后对第三个位置进行一个赋值,为100.
然后输出a2和a的数组长度。
var a [5]int
a[2] = 100
fmt.Println("get:", a[2])
fmt.Println("len:", len(a))
运行结果如下:
定义数组的时候就给其赋值。然后输出b数组看一眼:
b := [5]int{1, 2, 3, 4, 5}
fmt.Println(b)
输出效果如下:
二维数组:定义一个二维数组。使用双层循环对其赋值。
var twoD [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2d: ", twoD)
输出结果如下:
定义一个数组,指定其类型为字符。3个空间大小。然后对其进行赋值,然后输出第3个位置,和数组长度,代码如下:
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("get:", s[2]) // c
fmt.Println("len:", len(s)) // 3
代码运行结果如下:
数组追加,和pyrhon一样,使用append,但是注意,语法略微不同。
s = append(s, "d")
s = append(s, "e", "f")
fmt.Println(s) // [a b c d e f]
输出结果如下:
数组的拷贝,使用copt函数,我们先创建一个空的c数组,申请一个大小。然后使用copy函数,将s数组拷贝到c数组。然后输出c数组查看一下效果:
c := make([]string, len(s))
copy(c, s)
fmt.Println(c) // [a b c d e f]
输出结果如下:
切片:s2:5:第3个元素开始,到第5个之前(不包括第五个元素)
:5:开头到到第5个之前(不包括第五个元素)
s2::第3个元素开始,到最后一个元素。代码如下:
fmt.Println(s[2:5]) // [c d e]
fmt.Println(s[:5]) // [a b c d e]
fmt.Println(s[2:]) // [c d e f]
输出结果如下:
创建数组的时候,就进行赋值操作:
good := []string{"g", "o", "o", "d"}
fmt.Println(good) // [g o o d]
输出结果如下:
创建一个map。使用make函数,键值对:string:int。对其进行赋值。
然后输出查看效果,打印长度。指定键,查看值。如下代码:
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m) // map[one:1 two:2]
fmt.Println(len(m)) // 2
fmt.Println(m["one"]) // 1
fmt.Println(m["unknow"]) // 0
输出结果如下:
加入ok来看看是否有键存在。如下代码:
r, ok := m["unknow"]
fmt.Println(r, ok) // 0 false
输出结果如下:
删除键值对。使用delete函数,代码如下。
delete(m, "one")
赋值案例:
m2 := map[string]int{"one": 1, "two": 2}
var m3 = map[string]int{"one": 1, "two": 2}
fmt.Println(m2, m3)
输出结果如下:
for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。
首先定义一个numw数组,对其赋值。定义sum用于统计累加和。使用for 循环的 range 格式对其进行迭代循。具体如下:
nums := []int{2, 3, 4}
sum := 0
for i, num := range nums {
sum += num
if num == 2 {
fmt.Println("index:", i, "num:", num) // index: 0 num: 2
}
}
fmt.Println(sum) // 9
输出结果如下:
for 循环的 range 格式对map的遍历案例如下:
m := map[string]string{"a": "A", "b": "B"}
for k, v := range m {
fmt.Println(k, v) // b 8; a A
}
for k := range m {
fmt.Println("key", k) // key a; key b
}
输出结果如下:
go语言的函数,有一些区别。变量名在后面。
先看一下主函数:
res := add(1, 2)
fmt.Println(res) // 3
然后看一下add函数,这个add函数的作用是返回俩个值相加的结果。
func add(a int, b int) int {
return a + b
}
然后我们看一下返回多值的情况:
传入俩个参数,一个map,一个字符a。
v, ok := exists(map[string]string{"a": "A"}, "a")
fmt.Println(v, ok) // A True
看一下exists的函数。这里接受俩个函数,m"a"存在,ok的值为ture。返回给主函数。
func exists(m map[string]string, k string) (v string, ok bool) {
v, ok = m[k]
return v, ok
}
输出结果如下:
go语言的指针功能非常有限,主要的功能是为了对传入的参数进行修改。
这里的传入的参数实际上是一个拷贝。拷贝+1是不起作用的。
func add2(n int) {
n += 2
}
想要起作用只能采用指针类型:
func add2ptr(n \*int) {
\*n += 2
}
为了类型匹配,调用的时候,需要加&:add2ptr(&n)
下面是main函数:
n := 5
add2(n)
fmt.Println(n) // 5
add2ptr(&n)
fmt.Println(n) // 7
运行结果如下:
先定义一个结构体user,定义两个变量:name和password:
type user struct {
name string
password string
}
定义结构体值的几个方法:
下面代码是4种对结构体类型的赋值方法,非常简单。如下:
a := user{name: "wang", password: "1024"}
b := user{"wang", "1024"}
c := user{name: "wang"}
c.password = "1024"
var d user
d.name = "wang"
d.password = "1024"
输出来看一下:
fmt.Println(a, b, c, d) // {wang 1024} {wang 1024} {wang 1024} {wang 1024}
运行结果如下:
使用函数:
普通函数(不使用指针。)
func checkPassword(u user, password string) bool {
return u.password == password
}
使用指针:
func checkPassword2(u \*user, password string) bool {
return u.password == password
}
主函数,调用:
fmt.Println(checkPassword(a, "haha")) // false
fmt.Println(checkPassword2(&a, "haha")) // false
运行结果如下:
这里先把a赋值一个user结构体类型,并且对其进行赋值。
a := user{name: "wang", password: "1024"}
a.resetPassword("2048")
然后直接a.调用方法:
使用指针才能改变其结构体里的值。
func (u \*user) resetPassword(password string) {
u.password = password
}
检查一下结构体里的值是不是等于2048。
fmt.Println(a.checkPassword("2048")) // true
checkPassword函数的内容如下:
func (u user) checkPassword(password string) bool {
return u.password == password
}
运行结果如下:
导入依赖包:errors,代码如下:
import (
"errors"
"fmt"
)
先看一下调用的findUser,我们先传入了应该数组,和一个字符串。
u, err := findUser([]user{{"wang", "1024"}}, "wang")
findUser如下:
这个函数作用是检查结构体的值,是不是我们规定的难搞值,如果是的话返回return &u, nil。否则就是出错了。返回return nil, errors.New("not found"),将not found 写到日志里,代码如下:
func findUser(users []user, name string) (v \*user, err error) {
for \_, u := range users {
if u.name == name {
return &u, nil
}
}
return nil, errors.New("not found")
}
在主函数里,如果err不是nil的话,说明出错了,我们输出错误日志看一眼。
if err != nil {
fmt.Println(err)
return
}
输出u的name
fmt.Println(u.name) // wang
来一个错误案例:
我们调用findUser,但是传入 "li",上面的代码当然会u.name != name,就会有日志存入,err,然后下面进入判断,输出err,代码如下:
if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
fmt.Println(err) // not found
return
} else {
fmt.Println(u.name)
}
运行结果如下:
导入依赖包:strings,代码如下:
import (
"fmt"
"strings"
)
方法列表:
主函数代码,对字符串操作案例:
a := "hello"
fmt.Println(strings.Contains(a, "ll")) // true
fmt.Println(strings.Count(a, "l")) // 2
fmt.Println(strings.HasPrefix(a, "he")) // true
fmt.Println(strings.HasSuffix(a, "llo")) // true
fmt.Println(strings.Index(a, "ll")) // 2
fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
fmt.Println(strings.Repeat(a, 2)) // hellohello
fmt.Println(strings.Replace(a, "e", "E", -1)) // hEllo
fmt.Println(strings.Split("a-b-c", "-")) // [a b c]
fmt.Println(strings.ToLower(a)) // hello
fmt.Println(strings.ToUpper(a)) // HELLO
fmt.Println(len(a)) // 5
b := "你好"
fmt.Println(len(b)) // 6
运行结果如下:
先分别定义一个字符串,整数,指针。分别打印一下,代码如下:
s := "hello"
n := 123
p := point{1, 2}
fmt.Println(s, n) // hello 123
fmt.Println(p) // {1 2}
运行结果如下:
可以使用任意%v来输出任意的的数值。代码如下:
可以使用%+v来输出详细的数值。
可以使用%#v来输出更加详细的数值。
\n标识换行。
fmt.Printf("s=%v\n", s) // s=hello
fmt.Printf("n=%v\n", n) // n=123
fmt.Printf("p=%v\n", p) // p={1 2}
fmt.Printf("p=%+v\n", p) // p={x:1 y:2}
fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2}
运行结果如下:
小数,规定位数,这里和c/c++一模一样。
f := 3.141592653
fmt.Println(f) // 3.141592653
fmt.Printf("%.2f\n", f) // 3.14
导入依赖包: "encoding/json",代码如下:
import (
"encoding/json"
"fmt"
)
定义一个结构体userInfo。
type userInfo struct {
Name string
Age int `json:"age"`
Hobby []string
}
对其进行一个赋值操作。
a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
使用json的Marshal方法。我们先看一下Marshal方法:
func Marshal(v interface{}) ([]byte, error)
从返回值我们可以看到,该函数有两个返回值,一个是传入参数v的json编码,类型为[]byte,另外一个就是error。
将结构体变量a转换为json,代码如下:
buf, err := json.Marshal(a)
如果发送错误,输出错误日志:
if err != nil {
panic(err)
}
我们如果直接输出的话,是一堆为编译的数字。我们输出需要将其转换为字符串(序列化)才能进行输出,代码如下:
fmt.Println(buf) // [123 34 78 97...]
fmt.Println(string(buf)) // {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]}
运行结果如下:
使用MarshalIndent:
func MarshalIndent(v any, prefix, indent string)([]byte, error)
MarshalIndent 类似于 Marshal,但应用缩进来格式化输出。根据缩进嵌套,输出中的每个 JSON 元素都将在以前缀开头的新行开始,后跟一个或多个缩进副本。
buf, err = json.MarshalIndent(a, "", "\t")
if err != nil {
panic(err)
}
fmt.Println(string(buf))
输出如下:
JSON解码函数Unmarshal:
func Unmarshal(data []byte, v interface{}) error
Unmarshal函数解析json编码的数据并将结果存入v指向的值。
Unmarshal和Marshal做相反的操作,必要时申请映射、切片或指针,有如下的附加规则:
要将json数据解码写入一个指针,Unmarshal函数首先处理json数据是json字面值null的情况。此时,函数将指针设为nil;否则,函数将json数据解码写入指针指向的值;如果指针本身是nil,函数会先申请一个值并使指针指向它。
要将json数据解码写入一个结构体,函数会匹配输入对象的键和Marshal使用的键(结构体字段名或者它的标签指定的键名),优先选择精确的匹配,但也接受大小写不敏感的匹配。
var b userInfo
err = json.Unmarshal(buf, &b)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", b) // main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
输出结果如下:
导入依赖包: "time",代码如下:
import (
"fmt"
"time"
)
获取当前的时间并且输出:
now := time.Now()
fmt.Println(now)
运行结果如下:
还可以自己构造一个时间,如下代码:
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
fmt.Println(t) // 2022-03-27 01:25:36 +0000 UTC
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25
然后进行一个输出,也可以指定输出年月日等等。代码运行结果截图如下:
代码格式化:
fmt.Println(t.Format("2006-01-02 15:04:05"))
我们指定输出格式,代码运行结果截图如下:
时间差:使用sub函数,可以得出俩个时间的时间差。
diff := t2.Sub(t)
fmt.Println(diff) // 1h5m0s
fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900
代码运行结果截图如下:
time.Parse()函数
Go语言中的Parse()函数用于解析格式化的字符串,然后查找它形成的时间值。
官方api:
func Parse(layout, value string) (Time, error)
在这里,layout通过以哪种方式显示参考时间(即定义为Mon Jan 2 15:04:05 -0700 MST 2006)来指定格式,如果它是该值的话。但是,先前定义的布局(例如UnixDate,ANSIC,RFC3339等)解释了标准时间以及参考时间的合适表示形式。并且value参数保存字符串。其中,从值中删除的元素假定为零,如果不可能为零,则假定为一。
**返回值:** 它返回它表示的时间值。并且如果不存在时区指示符,则它会返回UTC时间。
t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
if err != nil {
panic(err)
}
fmt.Println(t3 == t) // true
代码运行结果截图如下:
时间戳:
fmt.Println(now.Unix()) // 1648738080
运行结果如下:
导入依赖包:"strconv",代码如下:
import (
"fmt"
"strconv"
)
可以使用ParseFloa或者ParseInt转换小数或者整数。
f, \_ := strconv.ParseFloat("1.234", 64)
fmt.Println(f) // 1.234
n, \_ := strconv.ParseInt("111", 10, 64)
fmt.Println(n) // 111
上面代码整数的第二个参数代表转换数字的进制,这里是10进制。
如果是0的话就是自动转换。代码如下;
n, \_ = strconv.ParseInt("0x1000", 0, 64)
fmt.Println(n) // 4096
使用Atoi快速把字符串转换为数字:
n2, \_ := strconv.Atoi("123")
fmt.Println(n2) // 123
数字不合法处理:
n2, err := strconv.Atoi("AAA")
fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
运行结果如下:
导入依赖包:"os"和"os/exec",代码如下:
import (
"fmt"
"os"
"os/exec"
)
输出命令行参数:
fmt.Println(os.Args)
获取或者写入环境变量:
fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin...
fmt.Println(os.Setenv("AA", "BB"))
快速启动子进程,并且获得输入输出。
buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
if err != nil {
panic(err)
}
fmt.Println(string(buf)) // 127.0.0.1 localhost
本文写了下面几大块:
<!---->
下篇我将撰写Go语言的实战应用的笔记,敬请期待!
大家好,又见面了,我是你们的朋友全栈君。本人发现网上虽然有不少Java相关的面试题,但第一未必全,第二未必有答案,第三虽然有答案,但未必能在面试中说,所以在本文里,会不断收集各种面试题,并站在面试官的立场上,给出我自己的答案。 第一部分、Java基础 1.JDK和JRE有什么区别?JDK是java的开发工具包,有JDK8,9甚至到14的差别,安装以后,不仅包含了java的开发环境,比如java.exe,还包含了运行环境(jre)相关包。JRE是java运行环境,一般装好JDK后,系统里会有对应的JRE环境。 2.说下你对==和equals的认识,它们有什么差别?对于==基本类型,比如int等,==比较的是值是否相同;引用类型,比如自定义对象:比较地址是否相同;尤其地,对常量,由于常量被放在常量池里管理,所以对String等常量,==也是比较值对于equals方法对于String,ArrayList等,equals方法是比较值;但在Object里,equals还是比较地址;如果自己创建了一个类,但没有重写equals方法,还是会比较地址 3.如果两个对象的hashCode值一样,则它们用
背景:神经连接组理论在系统神经科学领域的广泛应用,促进了我们对人类大脑皮层拓扑组织的认识。然而,功能性连接体在小脑中的拓扑结构仍不清楚。 方法:收集1416例健康成人的静息状态功能连接(rs-fcMRI)数据。在样本1(n=976)中,对功能性小脑连接组的体素级和节点级拓扑特性进行了估计。此外,还分别研究了基于网络的小脑和大脑-小脑拓扑映射的拓扑性质。考虑到神经群体的时间特性,我们进一步利用隐马尔可夫模型(HMM)来揭示小脑功能连接组的动态模式。为了测试我们发现的稳健性,我们在一个独立的数据集(样本2;n=440)运行。结果:我们发现小小脑脚I和小小脑脚II在小脑功能连接体中表现出显著的高度中心性(DC)。此外,小脑功能连接组甚至嵌套网络型小脑连接组的组织方式也表现出明显的小世界、模块化和层次化特征。小脑功能连接组中存在注意/执行网络、默认模式网络和任务正向网络三个内在模块。此外,小世界组织与层级结构的大脑-小脑相关性亦显著。通过构建大脑-小脑拓扑图,发现额顶叶和皮层下网络在小脑中的比例高于大脑皮层(3倍)。在时间特性方面,小脑功能连接组具有高度的灵活性和模块化,但在时间动态模式上表现
数据是特斯拉的生命线。作者|来自镁客星球的毛毛据外媒路透社报道,荷兰法庭学院(NetherlandsForensicInstitute,简称NFI)10月21号表示,其已经解密了特斯拉的汽车驾驶数据存储系统。并在数据中发现了大量可用于调查涉及特斯拉车辆的严重事故的信息。据悉,特斯拉CEO伊隆·马斯克一直不愿与监管机构分享其车辆数据,尽管其引以为傲的FSD(FullSelfDriving,全自动辅助驾驶系统)曾因数起交通意外而饱受质疑,但特斯拉坚持认为,应该保密其内部数据。NFI表示,它已经通过"逆向工程"获取到特斯拉的车辆数据日志,从而可以提取存储在车辆中的信息。NFI认为,这是"为了客观地调查他们"。据路透社的报道,NFI发现的数据远远多于调查人员此前所知的数据。据NFI收集的解密数据显示,特斯拉存储了有关自动驾驶仪操作的详细信息,还记录了车速、油门踏板位置、方向盘角度和制动踏板的使用情况,并且这些数据可以存储一年以上。NFI的数字调查员弗朗西斯·胡根迪克(FrancisHoogendijk)在对路透社的一份声明中说:“这些数据包含了大量供法医
使用Node.js和npm构建脚本或命令行工具。 一、包装shell命令第一步:创建一个npm项目npminit;复制第二步:创建一个js文件(index.js),包含要运行的脚本!/usr/bin/envnode console.log('Hello,world!');复制需要注意的是,需要添加片段标识符“!/usr/bin/envnode”,告知脚本使用Node执行。 第三步:在package.json文件中补充bin部分{ ... "author":"ligang", "bin":{ "hi":"./index.js" } }复制本示例中,使用“hi”作为外部调用的命令。 第四步:安装相关脚本,并运行测试$sudonpminstall-g $hi Hello,world!复制其他:查看安装情况#查看链接的位置 $whichhi /usr/local/bin/hi #查看文件实际位置 $readlink/usr/local/bin/hi ../lib/node_m
建造者模式:创建者模式隐藏了复杂对象的创建过程,它把复杂对象的创建过程加以抽象,通过子类继承或者重载的方式,动态的创建具有复合属性的对象。通俗的讲就是创建可装配的复杂对象建造者模式,属于创建类型实际代码我放在了Github:https://github.com/liangtengyu/DesignPatterns-for-Java应用场景:学习一个设计模式之前我们先了解它的使用场景能够帮我们更快的理解它,实现方式:当使用new()时参数过多容易导致混乱和BUG的产生使用set方法赋值时会创建一个可变对象,即对象创建完后还可以使用set方法改变变量,此时应该使用builer使用new关键字创建对象时,对于入参的校验比较混乱使用set方法时,对于入参的校验比较分散,不容易集中管理当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。使用Builder的好处将入参的校验逻辑都封装到build()方法中,进行统一的处理,处理完成才创建对象,否则不创建对象,方便管理校验逻辑使用build方法创建对象后,对象无法通过set方法进行修改参数,保证了对象的不可变实现方式
本文摘自istio学习笔记问题现象所有新启动的Pod无法ready,sidecar报错:warning envoyconfig gRPCconfigfortype.googleapis.com/envoy.config.listener.v3.Listenerrejected:Erroradding/updatinglistener(s)0.0.0.0_15090:erroraddinglistener:'0.0.0.0_15090'hasduplicateaddress'0.0.0.0:15090'asexistinglistener复制同时istiod也报错:ADS:LDS:ACKERRORsidecar~172.18.0.185~reviews-v1-7d46f9dd-w5k8q.istio-test~istio-test.svc.cluster.local-20847Internal:Erroradding/updatinglistener(s)0.0.0.0_15090:erroraddinglistener:'0.0.0.0
理论Python中不存在真正的私有方法。为了实现类似于c++中私有方法,可以在类的方法或属性前加一个“_”单下划线,意味着该方法或属性不应该去调用,它并不属于API。但是,这只是一个形式上的约定,python并不阻止调用。__双下划线的作用是避免覆盖其内容,实现的机制是在带有双下划线的方法或属性前加上_类名的标识。由于,python自动对方法和属性进行了改写,所以直接调用带有双下划线的方法是调用不到的。“xx”经常是操作符或本地函数调用的magicmethods。在上面的例子中,提供了一种重写类的操作符的功能。它是用于Python调用的。1、访问权限(private、public)与继承方式(只有public继承)在面向对象编程语言中,类的属性与方法都会设置访问控制权限,从而满足我们的设计需求。一般而言,我们通常会将对象的属性设置为私有的(private)或受保护的(protected),简单的说就是不允许外界访问,而对象的方法通常都是公开的(public),因为公开的方法就是对象向外界提供的接口。在Python中,属性和方法的访问权限只有两种,也就是公开的和私有的,如果希望属性是私有
1.弹出数字键盘 <!--有"#""*"符号输入--> <inputtype="tel"> <!--纯数字--> <inputpattern="\d*">复制安卓跟IOS的表现形式应该不一样,大家可以自己试试。当运用了正则pattern后,就不用关注input的类型了? 2.调用系统的某些功能<!--拨号--> <ahref="tel:10086">打电话给:10086</a> <!--发送短信--> <ahref="sms:10086">发短信给:10086</a> <!--发送邮件--> <ahref="mailto:839626987@qq.com">发邮件给:839626987@qq.com</a> <!--选择照片或者拍摄照片--> <inputtype=&q
我们在用OpenCV自带的摄像头JavaCameraView时,开启后手机竖屏会是旋转90度的效果,非常不友好,下面的代码即可实现我们用JavaCameraView根据手机横竖屏来获取到对应的图像.我们要修改的主要有两个地方,一个是获取实时帧的事件onCameraFrame,还有一个是OpenCV里面CameraBridgeViewBase类里的deliverAndDrawFrame方法onCameraFrame首先把CameraBridgeViewBase.CvCameraViewFrame里的图像复制到新的Mat里.然后判断当前屏幕是横屏还是竖屏.通过判断当前是前置摄像头还是后置摄像头来改变图像旋转的角度.把旋转完后的图像再缩放至JavaCameraView组件本身的大小.输出图像 publicMatonCameraFrame(CameraBridgeViewBase.CvCameraViewFrameinputFrame){ //获取到显示Mat赋值给frame Matframe=inputFrame.rgba(); //判断横竖屏用于进行图像的旋转 if(getResource
在上文《实践演练PytorchBert模型转ONNX模型及预测》中,我们将Bert的Pytorch模型转换成ONNX模型,并使用onnxruntime-gpu完成了python版的ONNX模型预测。今天我们来把预测搬到C++上,模拟一下模型的部署。对于C++版本模型预测服务,只需要按部就班完成如下三步即可:完成C++版本的中文切词,并向量化的过程使用ONNXRuntime的C++API,完成模型的推理预测过程编写一个简单的bRPC服务,把前面两步集成进去即可。C++中文文本向量化FullTokenizer所谓“他山之石,可以攻玉”。把中文文本向量化,这一步基本是琐细但是模式化的操作,网上肯定有现成的代码,比如这个Githubgist:https://gist.github.com/luistung/ace4888cf5fd1bad07844021cb2c7ecf我们不必把过多精力放到这个实现的源码上,这多少有点本末倒置。我们主要关注它如何使用就可以,看一下main函数:intmain(){ autotokenizer=FullTokenizer("data/chinese_L
想在移动开发大餐中分一杯羹,体验最火最炫的技术?小伙子,很有眼光嘛 毫无疑问,移动开发在目前和未来几年内都会盛极一时。无数开发职位虚位以待。各大公司都在寻找各种层次的程序员——新手级、入门级、中级、老手、专家。本文是写给新手们的——我会帮你们找到第一份iOS开发工作。 “我干嘛听你的?”, 你可能会这么说。是个问题——如果是菜鸟乱给建议,那倒是不听最好。我也不是什么大神,甚至也不算是特别有经验的iOS开发者——但我足够了解市场,因此可以对你有些帮助。 最初我是一个独立开发者,拥有几个收入不高(但也足够让我实现温饱而专心做开发)的应用。之后,我作为初级iOS开发者加入了一家公司,终于能全心全意做应用、甭担心明天吃啥这种问题了。如果我愿意,我完全可以找个公司打工衣食无忧(但可能这并不适合我——我的身体里流着创业的血液)。 现在,少说多做——如何才能成为一名iOS开发者呢? 1.买一个Mac(如果没iPhone的话,还得卖个肾)。 iOS开发需要Mac。 好吧,其实也能退而求其次(比如hackintosh,或MacInCloud),但听我苦口婆心一言——对
LeetCode977有序数组的平方 问题描述: 给定一个按非递减顺序排序的整数数组A,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。 一次遍历 利用数组原本存在的有序性(复数绝对值递减、非负数递增) 执行用时:2ms,在所有Java提交中击败了66.81%的用户 内存消耗:40.8MB,在所有Java提交中击败了15.99%的用户 classSolution{ //双指针 publicint[]sortedSquares(int[]A){ if(A==null||A.length==0){ returnA; } //找到负数最大的位置p1、非负数最小的位置p2 intp1=0,p2=0; for(inti=0;i<A.length;i++){ if(A[i]>=0){ p1=i-1; p2=i; break; } } //由p1、p2向两边遍历 int[]ans=newint[A.length]; intcurr=0; while(curr<A.length){ if(p1>=0&&p2<A.length){ if(
开发中非常多情况下须要将dataGridView控件中显示的数据结果以Excel或者Word的形式导出来,本例就来实现这个功能。因为从数据库中查找出某些数据列可能不是必需显示出来,在dataGridView中将相应的列隐藏了。这时导出时就会将隐藏的列导出来。显然不是我们所预期的。做法是先将dataGridView中显示的部分存进DataTable。然后就DataTable导出到Excel,代码例如以下: 第一步:加入Excel引用 第二步:创建类 usingSystem; usingSystem.Collections; usingSystem.Text; usingSystem.Data; usingSystem.Threading; usingSystem.Windows.Forms; usingSystem.Collections.Generic; usingMicrosoft.Office.Core; usingExcel=Microsoft.Office.Interop.Excel; publicclassExport
理解迭代 在JavaScript中,计数循环是一种最简单的迭代。因为它可以指定迭代次数、每次迭代要执行什么操作;而且每次循环都在下一次迭代开始前完成、每次迭代的顺序都是事先定义好的: for(leti=1;i<=10;i++){ console.log(i) } 复制 迭代会在一个有序集合上进行。“有序”即集合中所有项都可以按照既定顺序被遍历到,数组就是一个有序集合。由于数组有已知长度,且每一项都能通过索引获取,但这种方式并不适用于所有数据类型: letarr=["blue","yellow","green"] for(leti=0;i<arr.length;index++){ console.log(arr[i]) } 复制 迭代器模式 迭代器模式是一个方案。即把实现了iterable接口的结构称为可迭代对象(iterrable),它们能创建迭代器iterator。 实现iterable接口 一个数据结构想要实现iterable接口,就必须具有Symbol.iterator属性。即一个数据结构只要部署了Symbol.iterator属性,就可以认为是“可迭代的”: le
先上效果: 组件源码:slot-modal.vue <template> <viewclass="modal-container"v-if="show"@click.stop="cancel(2)"> <viewclass="modal-content"> <viewclass="modal-headmodal-title-padding"> <slotname="modal-head"></slot> </view> <viewclass="modal-body"> <slotname="modal-body"></slot> </view> <viewclass="modal-footer"> <viewclass="modal-col"hover-class="modal-hover"v-if="cancelText"@click.stop="cancel('cancel
.img{ width:90px; height:90px; border-radius:45px; margin:040%; border:solidrgb(100,100,100)1px;" position:relative; background-size:cover; }复制 1.以上代码实现圆形的css设计,半径:border-radius; 2.带箭头提示框效果 border-style:边框的样式 border-color:边框的颜色 border-width:边框的宽度 (1)实现 position:absolute; border-color:#00f#ff0#0f0#f0f; border-style:dasheddashedsoliddashed; border-width:50px;复制 (2)参考(1),可以去除任何一个三角形 border-color:transparenttransparenttransparent#f0f;复制 取色方向:上右下左 (3)实现空的三角,实现方式:在以上div中再放一个div,以同样的方向取三角,将其边框设为
题目 参考代码 思路: 一个三角形的面积=1/2absinC,即1/2|axb|(ab为向量),利用矩阵,算得S=1/2*abs(x1*y2-x2*y1)(x1,y1,是向量a的横纵坐标。x2,y2是向量b的横纵坐标)。 证明 由此,三角形面积的两倍一定是个整数,所以三角形面积的小数点后面要么.00,要么.50。用double和海伦公式存入数组sort 排序会超时,应该是两两比较的计算次数过多,因为是double。 关于函数nth_element() 优先队列默认从小到大自动排序。 priority_queue<int,vector<int>,greater<int>>q;//从大到小 #include<iostream> #include<cstdio> #include<cctype> #include<algorithm> #include<cstring> #include<cma
华为Liteos和物联网设备侧sdk移植到stm32F03ZE霸道板子上 推荐官方教程:https://liteos.github.io/ 啥是LIteos “开源免费”的实时操作系统,集成了LwM2M、CoAP、mbedTLS、LwIP全套IoT互联协议栈,且在LwM2M的基础上,提供了AgentTiny模块,用户只需关注自身的应用,而不必关注LwM2M实现细节,直接使用AgentTiny封装的接口即可简单快速实现与云平台安全可靠的连接。属于国产的实时操作系统(RTOS) 基于标准库移植 下载源码,https://github.com/LiteOS/LiteOS\ 往裸机工程添加LiteOS源码 打开LiteOS源码文件,可以看见里面有8个文件夹,下面先来了解一下主要的文件夹及其子文件夹的作用,然后将LiteOS源码的核心文件提取出来,添加到工程根目录下的文件夹中,因为工程只需要有用的源码文件,而不是整个LiteOS源码, 添加LiteOS系统的一些配置文件,含原厂芯片驱动 将OS_CONFIG文件夹下面的一些配置文件拷贝到刚刚提取的LiteOS核心文件夹下面,等下在移植工
1、Maven的聚合1.1聚合的配置2、Maven的继承2.1可被继承的POM元素2.2POM中使用继承2.3继承dependency 1、Maven的聚合 在Maven入门-4.Maven的依赖中,我们创建了2个以上的模块,每个模块都是一个独立的mavenproject,在开始的时候我们可以独立的编译和测试运行每个模块,但是随着项目的不断变大和复杂化,模块会越来越多,就不能每一个都编译测试了,这时Maven给出了聚合的配置方式。 所谓聚合,顾名思义,就是把多个模块或项目聚合到一起 现在新建一个专门负责聚合工作的Mavenproject(user-aggregator) 新建好之后的项目是如下状态: 这时我们可以把里面的所有内容都删掉,只保留pom.xml即可。 1.1聚合的配置 在pom.xml中使用modules来聚合其它模块。 user-aggregator的pom.xml文件内容如下: <projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLS
”过去一般时态“对应”一般过去时态“现在分词、过去分词是一个错误的叫法,其一直在误导着中国学生。 下面将分成两节来回答这个问题: 1.现在分词、过去分词是怎么来的; 2.现在分词、过去分词为什么是错误的叫法。 1.现在分词、过去分词是怎么来的; 我们知道世界上一切事物都是有生有灭,从酝酿出生、到出生存续、到死亡消逝,一切事物都遵守 着这样的自然法则,甚至连语言中的”动词“也不能例外。动词是动作的代称,无论这个动作是可 以真实感知的肢体动作,还是不可感知的思维动作,也无论这个动作存续多么短暂或者持续多么长 久,其都遵循着出生、存续、死亡这样的过程。 如下图所示: 上图从左到右依次为: 1.不定态(todo)表达了动作即将发生的状态 2.进行态(doing)表达了动作的发生且可感知的延续; 3.完成态(done)表达了动作的结束。 从这里可以看出三大非谓语动词其实就是动作的三个阶段——出生、存续、结束,这就是非谓语动 词的起源。 2.现在分词、过去分词为什么是错误的叫法。 传统英语中称动词的V—ing形式为“现在分词”,那么这个“现