关于golang:golangleetcode中级子集单词搜索

第一题 子集题目 解题思路长度为n的数组的幂集 首先咱们能够想到长度为零的空数组和长度为一单元素解都肯定是数组的幂集 剩下的子集都能够在繁多解的根底上组合而成例如 nums = [1,2,3]则其多元素解 [1,2]由[1]和[2]组成[1,3]由[1]和[3]组成[2,3]由[2]和[3]组成[1,2,3]长度与nums等长,故只有一种可能 再看看长度为4的状况nums = [1,2,3,4]单元素解有[1],[2],[3],[4]双元素解有[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]三要素解为[1,2]+[3]=[1,2,3][1,2]+[4]=[1,2,4][1,3]+[2]=[1,3,2][1,3]+[4]=[1,3,4]........略共能失去不同程序的组合四种[1,2,3],[1,2,4],[1,3,4],[2,3,4]其中例如[1,2,3]与[1,3,2]实质上是反复的 这样咱们就须要退出一个对其分别筛选的函数同时大量反复的计算也占了很大的代价 .为了缩小反复咱们引入一个数组用来存储元素的应用状况鉴于元素的应用状况只有两种, 应用 或者 不被应用 能够用0或者1来示意这样存储元素应用状况的数组就变成了一串二进制数且对应的二进制数正好从 0 到 2^n - 1 ,这样 咱们只需遍历从0到2^n - 1的数,将其二进制示意时数值为1的位退出到数组,就失去了所有不反复的幂集 当然咱们也能够思考标记元素的状态之后再进行递归其中 用残余元素序列存储元素的应用状况https://leetcode-cn.com/probl... 代码func subsets(nums []int) (ans [][]int) { n := len(nums) for mask := 0; mask < 1<<n; mask++ {//从0到n^2-1 set := []int{} for i, v := range nums { //遍历nums数组,如果第i位为1,则将其退出set if mask>>i&1 > 0 { set = append(set, v) } } ans = append(ans,set) } return}复杂度剖析工夫复杂度:O(n×2^n)。一共 2^n个状态,每种状态须要 O(n) 的工夫来结构子集。 ...

February 16, 2022 · 2 min · jiezi

关于golang:Go118-新特性弃用-stringsTitle-方法换个新坑吧

大家好,我是煎鱼。 最近在看 Go1.18 Release Notes 时,发现 strings, bytes 规范库的 Title 办法,居然被弃用了(Deprecated),这是为什么呢? 明天这篇文章就由煎鱼和大家一起看看。 介绍这里以 strings 规范库为例,strings.Title 办法的作用是:将所有单词结尾的 Unicode 字母映射到其 Unicode 题目大小写。 例子如下: import ( "fmt" "strings")func main() { fmt.Println(strings.Title("her royal highness")) fmt.Println(strings.Title("eddy cjy")) fmt.Println(strings.Title(""))}输入后果: Her Royal HighnessEddy Cjy这些单词均被转换为其大写。 问题看上去仿佛所有都很美妙,但其实他现阶段有 2 个显著的缺点。 别离是: 无奈正确处理 Unicode 标点符号。不思考特定人类语言的大写规定。接下来咱们具体开展讲讲。 Unicode 标点符号第一个问题,例子如下: import ( "fmt" "strings")func main() { a := strings.Title("go.go\u2024go") b := "Go.Go\u2024Go" if a != b { fmt.Printf("%s != %s\n", a, b) }}输入后果: ...

February 16, 2022 · 2 min · jiezi

关于golang:Leetcode专题数组219存在重复元素II

力扣链接:https://leetcode-cn.com/probl...解题思路: 首先联合题干剖析分明题目的意思,给定一个数组nums和一个数字k,是否存在下标i,j使得两个不同的下标在相差不超过k的时候想等依据下面提取进去的意思,能够将问题转换为,在一个长度为K+1(i-j<=k,那么算上i自身,滑动窗口最大的长度为k+1)的窗口中寻找是否存在两个雷同的数字,这个时候,解决问题的模型曾经建设有窗口的下限,那么就须要在达到下限时舍弃元素,这个时候就把窗口的最右边元素舍弃,下标为i-k-1(i-k为滑动窗口内的第一个元素,须要舍弃的须要再减一)最初一个问题,如何标记元素曾经呈现过呢?在解决数组问题时,咱们常常借助哈希表来进行标记位的存储func containsNearbyDuplicate(nums []int, k int) bool { numsToFlag := map[int]bool{} for i := 0; i < len(nums); i++ { if i > k { numsToFlag[nums[i-k-1]] = false } if numsToFlag[nums[i]] { return true } numsToFlag[nums[i]] = true } return false}

February 16, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组217存在重复元素

力扣链接:https://leetcode-cn.com/probl...解题思路: 给定一个数组,存在反复元素;首先能够排序整个数组,而后反复的元素肯定是相邻的元素,那么遍历整个数组,若存在相邻元素想等的状况,那么返回true,否则返回falsefunc containsDuplicate(nums []int) bool { sort.Ints(nums) for i := 0; i < len(nums); i++ { if nums[i] == nums[i+1] { return true } } return false}能够应用哈希表进行记录,如果哈希表中存在记录则返回true,否则返回falsefunc containsDuplicate(nums []int) bool { numsToFlag := make(map[int]int, len(nums)) for _, v := range nums { if _, ok := numsToFlag[v]; ok { return true } numsToFlag[v] = 1 } return false}

February 16, 2022 · 1 min · jiezi

关于golang:go-reflect包中abigo

abi是啥具体我也不先说了,先按我的了解翻译了一遍,他就是寄存器还是堆栈调配的规约,我也是在学习,大家审慎观看哦 // Copyright 2021 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package reflectimport ( "internal/abi" "internal/goexperiment" "unsafe")// These variables are used by the register assignment// algorithm in this file.//// They should be modified with care (no other reflect code// may be executing) and are generally only modified// when testing this package.//// They should never be set higher than their internal/abi// constant counterparts, because the system relies on a// structure that is at least large enough to hold the// registers the system supports.//// Currently they're set to zero because using the actual// constants will break every part of the toolchain that// uses reflect to call functions (e.g. go test, or anything// that uses text/template). The values that are currently// commented out there should be the actual values once// we're ready to use the register ABI everywhere.// 这些变量都是用来作为寄存器调配算法的var ( intArgRegs = abi.IntArgRegs * goexperiment.RegabiArgsInt // 整数寄存器的数量 floatArgRegs = abi.FloatArgRegs * goexperiment.RegabiArgsInt // 浮点数寄存器的数量 floatRegSize = uintptr(abi.EffectiveFloatRegSize * goexperiment.RegabiArgsInt) // 浮点数寄存器的宽度。可能为0、4、8。0代表没有,或者是通过softfloat ABI进行传递)// ABI 应用程序二进制接口。go运行时必须恪守的编程约定。ABI总是蕴含一系列的零碎调用和应用这些零碎调用的办法,// 以及对于程序能够应用的内存地址和应用机器寄存器的规定。// abiStep represents an ABI "instruction." Each instruction// describes one part of how to translate between a Go value// in memory and a call frame.// abiStep 就是一个ABI指令的形容。他形容了 go的值和函数栈帧之间的转换type abiStep struct { kind abiStepKind // 分几种类型,栈传递,整数寄存器值传递,整数寄存器指针传递,浮点数寄存器传递 // offset and size together describe a part of a Go value // in memory. // 传递值在内存中的偏移和大小 offset uintptr size uintptr // size in bytes of the part // These fields describe the ABI side of the translation. // 如果是栈传递,他的偏移地址 stkOff uintptr // stack offset, used if kind == abiStepStack // 如果是整数寄存器传递(包含整数指针传递),他的索引 ireg int // integer register index, used if kind == abiStepIntReg or kind == abiStepPointer // 如果是浮点数寄存器传递,他的索引 freg int // FP register index, used if kind == abiStepFloatReg}// abiStepKind is the "op-code" for an abiStep instruction.type abiStepKind intconst ( abiStepBad abiStepKind = iota abiStepStack // copy to/from stack abiStepIntReg // copy to/from integer register abiStepPointer // copy pointer to/from integer register abiStepFloatReg // copy to/from FP register)// abiSeq represents a sequence of ABI instructions for copying// from a series of reflect.Values to a call frame (for call arguments)// or vice-versa (for call results).//// An abiSeq should be populated by calling its addArg method.// abiSeq就是一些列abiStep的总和,加上了堆栈空间,和寄存器的应用type abiSeq struct { // steps is the set of instructions. // // The instructions are grouped together by whole arguments, // with the starting index for the instructions // of the i'th Go value available in valueStart. // // For instance, if this abiSeq represents 3 arguments // passed to a function, then the 2nd argument's steps // begin at steps[valueStart[1]]. // // Because reflect accepts Go arguments in distinct // Values and each Value is stored separately, each abiStep // that begins a new argument will have its offset // field == 0. // 这块就是理论的ABI形容列表,他是一组参数传递,或者是返回值传递 steps []abiStep // 这个标记了第i个参数或返回值的abiStep地位,好比以后是参数传递,要传第一个参数,那么就是steps[valueStart[0]],以此类推 valueStart []int // 栈应用空间 stackBytes uintptr // stack space used // 寄存器应用状况 iregs, fregs int // registers used}// 这个就是调试func (a *abiSeq) dump() { for i, p := range a.steps { println("part", i, p.kind, p.offset, p.size, p.stkOff, p.ireg, p.freg) } print("values ") for _, i := range a.valueStart { print(i, " ") } println() println("stack", a.stackBytes) println("iregs", a.iregs) println("fregs", a.fregs)}// stepsForValue returns the ABI instructions for translating// the i'th Go argument or return value represented by this// abiSeq to the Go ABI.// stepsForValue失去第i个参数产地的ABI指令形容序列// 失去第i个参数的ABI指令形容序列func (a *abiSeq) stepsForValue(i int) []abiStep { // s是开始地位 s := a.valueStart[i] var e int // a.steps和a.valueStart数量不对应,反正目标是为了获取下一个参数传递形容信息的一组ABI序列 if i == len(a.valueStart)-1 { e = len(a.steps) } else { e = a.valueStart[i+1] } return a.steps[s:e]}// addArg extends the abiSeq with a new Go value of type t.//// If the value was stack-assigned, returns the single// abiStep describing that translation, and nil otherwise.// 用一个新的t类型的值扩大abiSeq序列// 如果是栈调配,就返回单个abiStep,不然就返回nil// 给seq增加一个参数传递的ABI序列func (a *abiSeq) addArg(t *rtype) *abiStep { // We'll always be adding a new value, so do that first. // 获取总长度,因为要增加的参数必定是在这个地位开始的。这个就是更新a.valueStart的标记 pStart := len(a.steps) a.valueStart = append(a.valueStart, pStart) // 如果增加的类型的长度为0 if t.size == 0 { // If the size of the argument type is zero, then // in order to degrade gracefully into ABI0, we need // to stack-assign this type. The reason is that // although zero-sized types take up no space on the // stack, they do cause the next argument to be aligned. // So just do that here, but don't bother actually // generating a new ABI step for it (there's nothing to // actually copy). // // We cannot handle this in the recursive case of // regAssign because zero-sized *fields* of a // non-zero-sized struct do not cause it to be // stack-assigned. So we need a special case here // at the top. // 如果这个类型大小为0,为了降级到ABI0(稳固的ABI版本),咱们须要堆栈调配,尽管他 // 不占据空间,但他会影响下一次内存对其,因而咱们还是须要执行此操作,但没有必要生成一个step // 大小尽管为0.然而会影响对齐,咱们还是要对他进行肯定的解决 // align将a.stackBytes舍入为uintptr(t.align)的倍数,就是将a.stackBytes增大到增加元素的对其倍数上 a.stackBytes = align(a.stackBytes, uintptr(t.align)) return nil } // Hold a copy of "a" so that we can roll back if // register assignment fails. // 保留a的正本,不便咱们寄存器调配失败时回滚 aOld := *a // 寄存器调配开始,offset=0,调配失败的话,就须要回滚,而后进行栈调配 if !a.regAssign(t, 0) { // Register assignment failed. Roll back any changes // and stack-assign. *a = aOld // 栈调配胜利会返回最初一个步骤的step a.stackAssign(t.size, uintptr(t.align)) return &a.steps[len(a.steps)-1] } return nil}// addRcvr extends the abiSeq with a new method call// receiver according to the interface calling convention.//// If the receiver was stack-assigned, returns the single// abiStep describing that translation, and nil otherwise.// Returns true if the receiver is a pointer.// 增加一个接受者,这个是办法应用的func (a *abiSeq) addRcvr(rcvr *rtype) (*abiStep, bool) { // The receiver is always one word. // 接受者永远是一个word a.valueStart = append(a.valueStart, len(a.steps)) var ok, ptr bool // 返回rcvr是否在接口中,并且其中是否蕴含指针,如果有指针或者是在接口中,进行寄存器传值,ptrMap 0b1,二进制的1代表这个是一个指针,波及到GC回收 if ifaceIndir(rcvr) || rcvr.pointers() { ok = a.assignIntN(0, ptrSize, 1, 0b1) ptr = true } else { // TODO(mknyszek): Is this case even possible? // The interface data work never contains a non-pointer // value. This case was copied over from older code // in the reflect package which only conditionally added // a pointer bit to the reflect.(Value).Call stack frame's // GC bitmap. ok = a.assignIntN(0, ptrSize, 1, 0b0) ptr = false } if !ok { a.stackAssign(ptrSize, ptrSize) return &a.steps[len(a.steps)-1], ptr } return nil, ptr}// regAssign attempts to reserve argument registers for a value of// type t, stored at some offset.//// It returns whether or not the assignment succeeded, but// leaves any changes it made to a.steps behind, so the caller// must undo that work by adjusting a.steps if it fails.//// This method along with the assign* methods represent the// complete register-assignment algorithm for the Go ABI.// 他将t类型的值保留在偏移量offset的地位上,这就是寄存器调配算法func (a *abiSeq) regAssign(t *rtype, offset uintptr) bool { // 看t的kind switch t.Kind() { // 和指针相干的整数,他们调配都是,0b1 case UnsafePointer, Ptr, Chan, Map, Func: return a.assignIntN(offset, t.size, 1, 0b1) // 一般整数,就是0b0 case Bool, Int, Uint, Int8, Uint8, Int16, Uint16, Int32, Uint32, Uintptr: return a.assignIntN(offset, t.size, 1, 0b0) // 这个就是看大小辨别了,不过个别都是第二个抉择 case Int64, Uint64: switch ptrSize { case 4: return a.assignIntN(offset, 4, 2, 0b0) case 8: return a.assignIntN(offset, 8, 1, 0b0) } case Float32, Float64: return a.assignFloatN(offset, t.size, 1) case Complex64: return a.assignFloatN(offset, 4, 2) case Complex128: return a.assignFloatN(offset, 8, 2) case String: // 字符串,整形寄存器 return a.assignIntN(offset, ptrSize, 2, 0b01) case Interface: // interface是2,其余有指针都是1,一般数据是0 return a.assignIntN(offset, ptrSize, 2, 0b10) case Slice: return a.assignIntN(offset, ptrSize, 3, 0b01) case Array: // 数组的话,首先先把t的rtype类型转换为arrayType类型,他一开始的确是rtype,后续就是本人的类型信息 // 相当于扩大内存了 tt := (*arrayType)(unsafe.Pointer(t)) // 判断tt的长度,如果长度为0,不必调配,长度为1,就调配一下,如果长度大于1,就返回失败,通过栈调配吧 switch tt.len { case 0: // There's nothing to assign, so don't modify // a.steps but succeed so the caller doesn't // try to stack-assign this value. return true case 1: return a.regAssign(tt.elem, offset) default: return false } case Struct: // 构造体数据,也是先映射回去,再把所有的一个一个存进去,如果有一个失败,就返回失败,里面会回滚的 st := (*structType)(unsafe.Pointer(t)) for i := range st.fields { f := &st.fields[i] if !a.regAssign(f.typ, offset+f.offset()) { return false } } return true default: print("t.Kind == ", t.Kind(), "\n") panic("unknown type kind") } panic("unhandled register assignment path")}// assignIntN assigns n values to registers, each "size" bytes large,// from the data at [offset, offset+n*size) in memory. Each value at// [offset+i*size, offset+(i+1)*size) for i < n is assigned to the// next n integer registers.//// Bit i in ptrMap indicates whether the i'th value is a pointer.// n must be <= 8.//// Returns whether assignment succeeded.// 就是调配从offset开始的内存地址,调配n个寄存器,每个寄存器的大小为sizefunc (a *abiSeq) assignIntN(offset, size uintptr, n int, ptrMap uint8) bool { if n > 8 || n < 0 { panic("invalid n") } // ptrMap != 0代表着有指针,须要,并且 if ptrMap != 0 && size != ptrSize { panic("non-empty pointer map passed for non-pointer-size values") } // a.iregs+n 是咱们以后a占有的寄存器数量,intArgRegs是总数量 if a.iregs+n > intArgRegs { return false } // 开始调配 for i := 0; i < n; i++ { kind := abiStepIntReg if ptrMap&(uint8(1)<<i) != 0 { kind = abiStepPointer } a.steps = append(a.steps, abiStep{ kind: kind, offset: offset + uintptr(i)*size, size: size, ireg: a.iregs, }) // 寄存器应用数量 a.iregs++ } return true}// assignFloatN assigns n values to registers, each "size" bytes large,// from the data at [offset, offset+n*size) in memory. Each value at// [offset+i*size, offset+(i+1)*size) for i < n is assigned to the// next n floating-point registers.//// Returns whether assignment succeeded.// 跟下面的差不多func (a *abiSeq) assignFloatN(offset, size uintptr, n int) bool { if n < 0 { panic("invalid n") } if a.fregs+n > floatArgRegs || floatRegSize < size { return false } for i := 0; i < n; i++ { a.steps = append(a.steps, abiStep{ kind: abiStepFloatReg, offset: offset + uintptr(i)*size, size: size, freg: a.fregs, }) a.fregs++ } return true}// stackAssign reserves space for one value that is "size" bytes// large with alignment "alignment" to the stack.//// Should not be called directly; use addArg instead.// 栈调配,这个不应该间接调用,应该调用addArg或者addRcvr// 这个栈调配func (a *abiSeq) stackAssign(size, alignment uintptr) { // 第一步内存对其 a.stackBytes = align(a.stackBytes, alignment) // 增加一个形容到abiSeq a.steps = append(a.steps, abiStep{ kind: abiStepStack, offset: 0, // Only used for whole arguments, so the memory offset is 0. size: size, stkOff: a.stackBytes, }) a.stackBytes += size}// abiDesc describes the ABI for a function or method.// 这个才是为函数和办法定义的一组abi指令形容集type abiDesc struct { // call and ret represent the translation steps for // the call and return paths of a Go function. // 这就是两个局部,调用传参,和返回值俩个步骤,都是abiSeq call, ret abiSeq // These fields describe the stack space allocated // for the call. stackCallArgsSize is the amount of space // reserved for arguments but not return values. retOffset // is the offset at which return values begin, and // spill is the size in bytes of additional space reserved // to spill argument registers into in case of preemption in // reflectcall's stack frame. // stackCallArgsSize参数空间大小 // retOffset返回值偏移地位 // spill额定的空间,避免参数寄存器溢出 // 栈参数空间大小,返回值偏移地址,spill是额定空间,和旧版的栈调配一样,为了避免寄存器放不下了,跟旧版寄存办法一样,好读取数据 stackCallArgsSize, retOffset, spill uintptr // stackPtrs is a bitmap that indicates whether // each word in the ABI stack space (stack-assigned // args + return values) is a pointer. Used // as the heap pointer bitmap for stack space // passed to reflectcall. // 一个位图,指ABI参数和返回值是否是一个指针,用作栈空间反射调用堆指针空间位图 // 与runtime.bitvector.统一 stackPtrs *bitVector // inRegPtrs is a bitmap whose i'th bit indicates // whether the i'th integer argument register contains // a pointer. Used by makeFuncStub and methodValueCall // to make result pointers visible to the GC. // // outRegPtrs is the same, but for result values. // Used by reflectcall to make result pointers visible // to the GC. // inRegPtrs,入参 应用makeFuncStub methodValueCall使对GC可见 // outRegPtrs,返回 应用reflectcall使对GC可见 // 第i位是否蕴含指针 // 这俩个和GC无关,用来裸露给GC // 这个IntArgRegBitmap是[(IntArgRegs + 7) / 8]uint8 inRegPtrs, outRegPtrs abi.IntArgRegBitmap}func (a *abiDesc) dump() { println("ABI") println("call") a.call.dump() println("ret") a.ret.dump() println("stackCallArgsSize", a.stackCallArgsSize) println("retOffset", a.retOffset) println("spill", a.spill) print("inRegPtrs:") dumpPtrBitMap(a.inRegPtrs) println() print("outRegPtrs:") dumpPtrBitMap(a.outRegPtrs) println()}func dumpPtrBitMap(b abi.IntArgRegBitmap) { for i := 0; i < intArgRegs; i++ { x := 0 if b.Get(i) { x = 1 } print(" ", x) }}// 封装一个参数传递过程func newAbiDesc(t *funcType, rcvr *rtype) abiDesc { // We need to add space for this argument to // the frame so that it can spill args into it. // // The size of this space is just the sum of the sizes // of each register-allocated type. // // TODO(mknyszek): Remove this when we no longer have // caller reserved spill space. // 咱们须要调配一个空间,能够将参数溢出到这里 // 这个大小只是每个寄存器调配类型的大小总和 // 当咱们不再有调用者时删除他 spill := uintptr(0) // Compute gc program & stack bitmap for stack arguments // 计算堆栈参数gc程序和堆栈位图 stackPtrs := new(bitVector) // Compute the stack frame pointer bitmap and register // pointer bitmap for arguments. // 计算参数的堆栈帧指针位图和寄存器指针位图。 inRegPtrs := abi.IntArgRegBitmap{} // Compute abiSeq for input parameters. // 计算入参的seq var in abiSeq if rcvr != nil { // rcvr作为第一个参数传递进去 stkStep, isPtr := in.addRcvr(rcvr) if stkStep != nil { if isPtr { stackPtrs.append(1) } else { stackPtrs.append(0) } } else { spill += ptrSize } } for i, arg := range t.in() { stkStep := in.addArg(arg) if stkStep != nil { addTypeBits(stackPtrs, stkStep.stkOff, arg) } else { spill = align(spill, uintptr(arg.align)) spill += arg.size for _, st := range in.stepsForValue(i) { if st.kind == abiStepPointer { inRegPtrs.Set(st.ireg) } } } } spill = align(spill, ptrSize) // From the input parameters alone, we now know // the stackCallArgsSize and retOffset. stackCallArgsSize := in.stackBytes retOffset := align(in.stackBytes, ptrSize) // Compute the stack frame pointer bitmap and register // pointer bitmap for return values. outRegPtrs := abi.IntArgRegBitmap{} // Compute abiSeq for output parameters. var out abiSeq // Stack-assigned return values do not share // space with arguments like they do with registers, // so we need to inject a stack offset here. // Fake it by artificially extending stackBytes by // the return offset. out.stackBytes = retOffset for i, res := range t.out() { stkStep := out.addArg(res) if stkStep != nil { addTypeBits(stackPtrs, stkStep.stkOff, res) } else { for _, st := range out.stepsForValue(i) { if st.kind == abiStepPointer { outRegPtrs.Set(st.ireg) } } } } // Undo the faking from earlier so that stackBytes // is accurate. out.stackBytes -= retOffset return abiDesc{in, out, stackCallArgsSize, retOffset, spill, stackPtrs, inRegPtrs, outRegPtrs}}

February 16, 2022 · 11 min · jiezi

关于golang:golangleetcode中级括号生成全排列

第一题 括号生成题目 动静布局解法咱们能够将括号的生成看作一直的在括号对中退出新的括号这样对于n对括号的生成 咱们便能在n-1对括号中进行操作参考https://leetcode-cn.com/probl...https://leetcode-cn.com/probl... java版本递归实现// 9mspublic List<String> generateParenthesis(int n) { List<String> res = new LinkedList<>(); if (n == 0) { res.add(""); return res; } for (int i = 0; i < n; i++) { int j = n - i - 1; List<String> iRes = generateParenthesis(i); List<String> jRes = generateParenthesis(j); for (String s1 : iRes) { for (String s2 : jRes) { res.add(s1 + "(" + s2 + ")"); } } } return res;}作者:fan-lu-5链接:https://leetcode-cn.com/problems/generate-parentheses/solution/java-0ms-cong-zhao-gui-lu-dao-xuan-ding-2qm9t/起源:力扣(LeetCode)著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。将小于n的计算结果存储起来供后续计算应用,缩小反复计算// 8mspublic List<String> generateParenthesis(int n) { Map<Integer, List<String>> mem = new HashMap<>(); return dp(n, mem);}private List<String> dp(int n, Map<Integer, List<String>> mem) { if (mem.containsKey(n)) return mem.get(n); List<String> res = new LinkedList<>(); if (n == 0) { res.add(""); return res; } for (int i = 0; i < n; i++) { int j = n - i - 1; List<String> iRes = dp(i, mem); List<String> jRes = dp(j, mem); for (String s1 : iRes) { for (String s2 : jRes) { res.add(s1 + "(" + s2 + ")"); } } } mem.put(n, res); return res;}作者:fan-lu-5链接:https://leetcode-cn.com/problems/generate-parentheses/solution/java-0ms-cong-zhao-gui-lu-dao-xuan-ding-2qm9t/起源:力扣(LeetCode)著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。go版本递归实现func generateParenthesis(n int) []string { var res []string if n == 0 { res=append(res,"") return res } //i从0到n-1 j从n-1到0 for i := 0; i < n; i++ { j := n - i - 1 //生成i和j的括号序列 iRes := generateParenthesis(i) jRes := generateParenthesis(j) for _,s1:=range iRes { for _,s2:=range jRes { res=append(res,s1 + "(" + s2 + ")") } } } return res}成果 ...

February 15, 2022 · 4 min · jiezi

关于golang:golang语法小心切片的复制

切片的个性在go的切片中 对基于同一数组的不同切片进行操作的时候,本质上是在同一数组空间进行操作的 如果咱们在复制切片的时候 想当然的应用上面的语句 var nums = []int{1, 2, 3}copy :=nums就有可能导致bug的呈现 让咱们看看这个例子咱们本心愿对正本copy进行操作而不扭转nums的值 为此咱们新建了变量copy 然而后果为 正确的做法是应用copy函数 对于copy函数的应用咱们须要留神参数的长度 如果咱们应用这样的copy 本认为实现了复制操作 但其实 后果如下 因为co被申明时默认初始化为nil 因为copy函数的个性,copy操作不会为co扩充容量 在实现了copy操作之后将仍为nil 这样咱们如果认为实现了copy操作间接应用该切片就会产生异样例如实现替换操作co[1], co[2] = co[2], co[1] 将会提醒下标越界 panic: runtime error: index out of range [1] with length 0正确的做法是将其初始化为长度相等的切片 这样咱们就能失去正确的后果

February 15, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组540有序数组中的单一元素

力扣链接:https://leetcode-cn.com/probl...解题思路: 首先,算法应该造就思维,看到有序数组以及题干要求的logn的解法,那么首先就应该想到的是二分查找,这算是解法的第一步找到算法的思路后,开始找法则,或者能够叫找公式。如数组:[1,1,2,3,3,4,4,8,8],如果数组中没有单个数字,那么该数组就应该是[1,1,2,2,3,3,4,4,8,8];能够找出的一个法则是:下标从0开始,到len(nums) - 1 完结,下标为偶数的和下标为相邻奇数的数字相等。即:nums[0] == nums[1]; nums[2] == nums[3] ....找到第二点所示的法则后,因为咱们须要应用奇偶数下标来判断,那么mid := (high - low) >> 1 + low,mid可能是奇数,也可能是偶数,然而不管mid是奇数还是偶数,遵循的法则都是nums[偶数] == nums[相邻的奇数],基于这一点,当mid是奇数时,那么判断nums[mid - 1] == nums[mid];如果相等,那么阐明只呈现一个的数字在右半局部,那么low = mid + 1,如果不相等,则证实只呈现一个的数字在左半局部,那么high = mid,当mid是偶数时,比拟的是nums[mid] 是否等于 nums[mid + 1];如果相等,阐明单个数字在右半局部,如果不相等,阐明在左半局部通过下面的判断,能够晓得有两个分支:mid是奇数和mid是偶数,每个分支下各自有是否跟相邻数字相等的判断,这里有另外一个优化的技巧,即异或,在查找单个数字的时候见识过异或的威力,实际上异或还有一个定律:奇数和1异或等于减一,偶数异或1等于加一;那么能够优化if-else分支,不必去分奇数偶数,只有相邻想等的,那么单个数在右半局部,不想等则在左半局部func SingleNonDuplicate(nums []int) int { low, high := 0, len(nums) - 1 for low < high { mid := (high - low) >> 1 + low if nums[mid] == nums[mid^1] { low = mid + 1 } else { high = mid } } return nums[low]}

February 15, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode中级算法树和图二叉树的中序遍历递归迭代

题目:给定一个二叉树的根节点 root ,返回它的 中序 遍历。 链接: 力扣Leetcode—中级算法—树和图—二叉树的中序遍历. 示例1 : 输出:root = [1,null,2,3]输入:[1,3,2]示例2 : 输出:root = []输入:[]示例3 : 输出:root = [1]输入:[1]示例4 : 输出:root = [1,2]输入:[2,1]示例5 : 输出:root = [1,null,2]输入:[1,2]标签:栈、树、深度优先搜寻、二叉树 思路:二叉树的中序遍历,依照拜访左子树——根节点——右子树的形式遍历这棵树,而在拜访左子树或者右子树的时候咱们依照同样的形式遍历,直到遍历完整棵树。因而整个遍历咱们能够间接用 递归 函数来模仿这一过程。或者咱们也能够用 迭代 来解决问题,先将整颗树怼进去,在把所有的左子树怼进去,而后遍历左子树,间接右边的最下边。因为先进后出,拿到了最上面的左节点,也怼到数组里,看以右节点为根的还有没有左节点,有就回到下面第1步,没有就走第3步,把根节点怼进去,在怼右节点。 递归Go代码如下: package mainimport "fmt"// TreeNode Definition for a binary tree node.type TreeNode struct { Val int // 根 Left *TreeNode //左节点 Right *TreeNode //右节点}func inorderTraversal(root *TreeNode) (res []int) { var inorder func(node *TreeNode) inorder = func(node *TreeNode) { if node == nil { return // 完结以后递归 } inorder(node.Left) // 间接怼到右边最下边 res = append(res, node.Val) // 增加到数组里 inorder(node.Right) // 看左边还有没有分支,有就持续走,没有就将右节点退出数组 } inorder(root) return}func main() { // 测试用例 root = [1,null,2,3] root := &TreeNode{1, nil, nil} root.Right = &TreeNode{2, nil, nil} root.Right.Left = &TreeNode{3, nil, nil} res := inorderTraversal(root) fmt.Printf("res is: %v\n", res)}提交截图:迭代Go代码如下: ...

February 15, 2022 · 2 min · jiezi

关于golang:Leetcode专题数组169多数元素

力扣链接:https://leetcode-cn.com/probl...解题思路: 解法一:哈希表,间接遍历数组,记录每个数字的个数,而后找出大于个别的数字解法二:因为数组中的少数元素,那么能够排序这个数组,位于两头的元素肯定是最多的超过一半的元素func majorityElement(nums []int) int { sort.Ints(nums) return nums[len(nums) / 2]}

February 15, 2022 · 1 min · jiezi

关于golang:Go118-新特性引入新的-netip-网络库

大家好,我是煎鱼。 写这篇文章时是大年初一,本来想说这个月就要公布 Go1.18 了。然而,好家伙,Go1.18 beta2 公布了,官网告知社区 Go1.18 要拖更到 3 月份了,咕咕咕... 如下图: 所以还是得持续学习新个性,明天煎鱼将联合 Brad Fitzpatrick 写的《netaddr.IP: a new IP address type for Go》带大家理解 Go1.18 的新网络库 net/netip 的原因。 背景大佬到职本来 Go 开发团队中的 Brad Fitzpatrick,在 2010~2020 年都在 Go 团队工作,在 2021 年起换公司了。 如下推特的音讯: 到职的起因是:做了同样的货色太久了,有些腻烦,不想陷在一个舒服的窘境中。 当初来看是换到了 Tailscale,做 WireGuard 相干工作,要常常与网络库打交道。 需要诞生大佬公司写的 Tailscale,实质上是一个网络应用程序,要与网络打交道,又是用 Go 写的,就会波及到规范库 net: 在单个 IP 类型上应用 net.IP。网络示意上应用 net.IPNet。示例代码: import ( "fmt" "net")func main() { fmt.Println(net.IPv4(8, 8, 8, 8))}输入后果: 8.8.8.8Brad Fitzpatrick 在理论编写和应用时,发现 net 规范库的类型有很多问题,很不好用。 ...

February 15, 2022 · 2 min · jiezi

关于golang:第二十期字节跳动-效率工程-后端开发实习生-一面面经

面试软件用的字节本人的飞书。面试官掉线了好几次。。。 开局自我介绍。 1.首先是语言局部:go和java的区别协程与线程的区别java的hashmap的原理java的接口与抽象类的区别。什么时候用抽象类,什么时候用接口2.计算机网络局部tcp与udp的区别tcp如何保障牢靠有序tcp的拥塞管制服务端给客户端发送123个报文,收到了3的ack,下一步发哪一个报文http每个版本的区别http 1.1 中流水线阻塞的原理,http2中多路复用的原理,为什么不阻塞了(这个是真的不会。。)https秘钥替换过程 对称秘钥被黑客截取了咋办(感觉问的有问题,我就答复说对称秘钥不可能被黑客截取,因为对称秘钥是应用服务端公钥加密过的,只能应用服务端的私钥解密)https的公钥被劫持的咋办(ca证书)3.操作系统局部几种io模型 说了同步阻塞,同步非阻塞,异步非阻塞 同步非阻塞与io多路复用的区别?(不晓得,求大佬们解答) io多路复用复用的什么局部(猜了一个发射端缓存,也就是buffer,网络编程这部分真的没咋看,得增强一下。。) 4.数据库局部mysql索引优化(最左准则.....) 聚簇索引与非聚簇索引 非聚簇索引怎么查的(回表) 索引生效 redis(不会redis,问的问题忘了,面试官问了一道发现我不会,也就没问)5.数据结构局部给定一个数据流,流外面是一些单词,要求应用一个数据结构统计单词的个数(hashmap或者字典树)给定一个单向有序链表,要求应用一个数据结构能疾速查出给定节点值(跳表,我感觉在链表上建b+树也能够)6.算法做题应用本人的ide。lc的链表对折那道题。 20分钟不到,须要自建节点,本人 在main函数里实例化链表而后测试这道题不难然而又臭又长。。首先要用快慢指针找到中点,而后将慢指针前面的局部翻转失去另外半个链表,最初将两个链表合并。 写进去了,运行发现有谬误。。。没debug一会儿,面试官叫我停了,把代码复制给他而后就匆匆忙忙完结了。 没有反诘环节。。总体感觉体现的不是很好,很多问题说的语言不顺畅,还好过了。。面试官蛮不错的,遇到不会了就跳过,也不查究。

February 15, 2022 · 1 min · jiezi

关于golang:golang语法map常见错误golang-panic-assignment-to-entry-in-nil-map

map的申明 var map_variable map[key_data_type]`value_data_type`申明后map的值默认为nil map上的大部分操作,包含查找、删除、len和range循环都能够平安工作在nil值的map上,它们的行为和一个空的map相似。然而向一个nil值的map存入元素将导致一个panic异样: golang panic: assignment to entry in nil map在向map存数据前必须先应用golang内置的make函数创立map。 map_variable := make(map[key_data_type]value_data_type)如果不初始化 map,那么就会创立一个 nil map。nil map 不能用来寄存键值对 将以上并为一句 // 初始化 + 赋值一体化m := map[string]string{ "a": "aa", "b": "bb",}

February 15, 2022 · 1 min · jiezi

关于golang:带你十天轻松搞定-Go-微服务系列二

上篇文章开始,咱们通过一个系列文章跟大家具体展现一个 go-zero 微服务示例,整个系列分十篇文章,目录构造如下: 环境搭建服务拆分(本文)用户服务产品服务订单服务领取服务RPC 服务 Auth 验证服务监控链路追踪分布式事务冀望通过本系列带你在本机利用 Docker 环境利用 go-zero 疾速开发一个商城零碎,让你疾速上手微服务。 残缺示例代码:https://github.com/nivin-studio/go-zero-mall 服务拆分一个商城我的项目可拆分用户服务(user)、订单服务(order)、产品服务(product)、领取服务(pay)、售后服务(afterSale)... 每个服务都能够再分为 api 服务和 rpc 服务。api 服务对外,可提供给 app 调用。rpc 服务是对内的,可提供给外部 api 服务或者其余 rpc 服务调用。整个我的项目服务依赖流程图大抵如下: 1 用户服务(user)api 服务端口:8000rpc 服务端口:9000login用户登录接口login用户登录接口register用户注册接口register用户注册接口userinfo用户信息接口userinfo用户信息接口............2 产品服务(product)api 服务端口:8001rpc 服务端口:9001create产品创立接口create产品创立接口update产品批改接口update产品批改接口remove产品删除接口remove产品删除接口detail产品详情接口detail产品详情接口............3 订单服务(order)api 服务端口:8002rpc 服务端口:9002create订单创立接口create订单创立接口update订单批改接口update订单批改接口remove订单删除接口remove订单删除接口detail订单详情接口detail订单详情接口list订单列表接口list订单列表接口 paid订单领取接口............4 领取服务(pay)api 服务端口:8003rpc 服务端口:9003create领取创立接口create领取创立接口detail领取详情接口detail领取详情接口callback领取回调接口callback领取回调接口............5 创立我的项目目录创立 mall 工程$ mkdir mall && cd mall$ go mod init mall创立 common 目录$ mkdir common创立 service 目录$ mkdir service && cd service创立 user api,user rpc,user model 目录$ mkdir -p user/api$ mkdir -p user/rpc$ mkdir -p user/model创立 product api,product rpc,product model 目录$ mkdir -p product/api$ mkdir -p product/rpc$ mkdir -p product/model创立 order api,order rpc,order model 目录$ mkdir -p order/api$ mkdir -p order/rpc$ mkdir -p order/model创立 pay api,pay rpc,pay model 目录$ mkdir -p pay/api$ mkdir -p pay/rpc$ mkdir -p pay/model最终我的项目目录├── common # 通用库├── service # 服务│ ├── order│ │ ├── api # order api 服务│ │ ├── model # order 数据模型│ │ └── rpc # order rpc 服务│ ├── pay│ │ ├── api # pay api 服务│ │ ├── model # pay 数据模型│ │ └── rpc # pay rpc 服务│ ├── product│ │ ├── api # product api 服务│ │ ├── model # product 数据模型│ │ └── rpc # product rpc 服务│ └── user│ ├── api # user api 服务│ ├── model # user 数据模型│ └── rpc # user rpc 服务└── go.mod一些思考微服务拆分并没有对立的规范,雷同的业务在不同的公司很可能拆分形式会有所区别,用户规模、团队大小、组员能力等都会是思考因素。但咱们还是有一些根本准则能够遵循: ...

February 15, 2022 · 2 min · jiezi

关于golang:带你十天轻松搞定-Go-微服务系列一

本文开始,咱们会出一个系列文章跟大家具体展现一个 go-zero 微服务示例,整个系列分十篇文章,目录构造如下: 环境搭建(本文)服务拆分用户服务产品服务订单服务领取服务RPC 服务 Auth 验证服务监控链路追踪分布式事务冀望通过本系列带你在本机利用 Docker 环境利用 go-zero 疾速开发一个商城零碎,让你疾速上手微服务。 残缺示例代码:https://github.com/nivin-studio/go-zero-mall 1 环境要求Golang 1.15+EtcdRedisMysqlPrometheusGrafanaJaegerDTM2 Docker 本地开发环境搭建为了不便开发调试,咱们应用 Docker 构建本地开发环境。Windows 和 macOS 零碎可下载 Docker Desktop 装置应用,具体下载安装办法可自行搜寻相干教程。 这里咱们应用 Docker Compose 来编排治理咱们的容器,创立如下目录: gonivinck├── dtm # DTM 分布式事务管理器│ ├── config.yml # DTM 配置文件│ └── Dockerfile├── etcd # Etcd 服务注册发现│ └── Dockerfile├── golang # Golang 运行环境│ └── Dockerfile├── grafana # Grafana 可视化数据监控│ └── Dockerfile├── jaeger # Jaeger 链路追踪│ └── Dockerfile├── mysql # Mysql 服务│ └── Dockerfile├── mysql-manage # Mysql 可视化治理│ └── Dockerfile├── prometheus # Prometheus 服务监控│ ├── Dockerfile│ └── prometheus.yml # Prometheus 配置文件├── redis # Redis 服务│ └── Dockerfile├── redis-manage # Redis 可视化治理│ └── Dockerfile├── .env # env 配置└── docker-compose.yml2.1 编写 Dockerfile在 go-zero 的微服务中采纳 grpc 进行服务间的通信,而 grpc 的编写就须要用到 protoc 和翻译成 go 语言 rpc stub 代码的插件 protoc-gen-go。 ...

February 15, 2022 · 4 min · jiezi

关于golang:golang语法containsKey在go中的实现

javacontainsKey() 是Java中查看 hashMap 中是否存在指定的 key 对应的映射关系的办法返回值为布尔变量应用办法为 if (mem.containsKey(n)) return mem.get(n);go值在go中,对map的个别操作,咱们能够通过key作为索引下标来拜访map 通过key作为索引下标将产生一个value。如果key在map中是存在的,那么将失去与key对应的value;如果key不存在,那么将失去value对应类型的零值 `value := map[n]`判断在golang的map中,如果想要获取是否存在指定的 key咱们能够再退出一个布尔值判断 `value, ok := map[n]`map的下标语法将产生两个值;第二个是一个布尔值,用于报告元素是否真的存在。布尔变量个别命名为ok,特地适宜马上用于if条件判断局部 用于if语句golang的if语句有一种快捷不便的写法能够在if的条件判断之前退出一个布尔变量的赋值语句,用“;”号隔开格局如下 if value, ok := mem[n];ok{ return value }这样就实现了与之前java中if (mem.containsKey(n)) return mem.get(n);同样的成果

February 15, 2022 · 1 min · jiezi

关于golang:Golang-匿名函数

匿名函数的概念匿名函数,就是没有名字的函数 两种应用形式在定义匿名函数的时候就间接应用(不论有没有传参,匿名函数体之后都要加上括号) x := func(i int) int { return i }(10)把匿名函数赋值给另一个变量(函数变量),这个变量相当于函数名,能够间接调用(匿名函数体之后不要加括号) x := func(i int) int { return i } fmt.Println(x(10))

February 15, 2022 · 1 min · jiezi

关于golang:Go语言切片面试真题7连问

前言哈喽,大家好,我是asong。最近没事在看八股文,总结了几道常考的切片八股文,以问答的形式总结进去,心愿对正在面试的你们有用~ 本文题目不全,对于切片的面试真题还有哪些?欢送评论区补充~ 01. 数组和切片有什么区别?Go语言中数组是固定长度的,不能动静扩容,在编译期就会确定大小,申明形式如下: var buffer [255]intbuffer := [255]int{0}切片是对数组的形象,因为数组的长度是不可变的,在某些场景下应用起来就不是很不便,所以Go语言提供了一种灵便,性能强悍的内置类型切片("动静数组"),与数组相比切片的长度是不固定的,能够追加元素。切片是一种数据结构,切片不是数组,切片形容的是一块数组,切片构造如下: <img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/93958be1acdb4eb8867d307e92ad1d17~tplv-k3u1fbpfcp-zoom-1.image" style="zoom:50%;" /> 咱们能够间接申明一个未指定大小的数组来定义切片,也能够应用make()函数来创立切片,申明形式如下: var slice []int // 间接申明slice := []int{1,2,3,4,5} // 字面量形式slice := make([]int, 5, 10) // make创立slice := array[1:5] // 截取下标的形式slice := *new([]int) // new一个切片能够应用append追加元素,当cap有余是进行动静扩容。 02. 拷贝大切片肯定比拷贝小切片代价大吗?这道题比拟有意思,原文地址:Are large slices more expensive than smaller ones? 这道题实质是考查对切片实质的了解,Go语言中只有值传递,所以咱们以传递切片为例子: func main() { param1 := make([]int, 100) param2 := make([]int, 100000000) smallSlice(param1) largeSlice(param2)}func smallSlice(params []int) { // ....}func largeSlice(params []int) { // ....}切片param2要比param1大1000000个数量级,在进行值拷贝的时候,是否须要更低廉的操作呢? 实际上不会,因为切片实质内部结构如下: ...

February 14, 2022 · 4 min · jiezi

关于golang:golangleetcode中级岛屿数量电话号码的字母组合

第一题 岛屿数量题目 解题思路 代码//dfs函数通过深搜遍历一个岛屿,并将岛屿的1全都置0func dfs(grid [][]byte,r int,c int) { nr := len(grid) nc := len(grid[0]) if r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0' { return } grid[r][c] = '0' dfs(grid, r - 1, c) dfs(grid, r + 1, c) dfs(grid, r, c - 1) dfs(grid, r, c + 1)}func numIslands(grid [][]byte) int { if grid == nil || len(grid)== 0 { return 0 } nr := len(grid) nc := len(grid[0]) numIslands := 0 //遍历gird数组为岛屿计数 for r := 0; r < nr; r++ { for c := 0; c < nc; c++ { if grid[r][c] == '1' { numIslands++ dfs(grid, r, c) } } } return numIslands}复杂度剖析复杂度剖析 ...

February 14, 2022 · 2 min · jiezi

关于golang:Leetcode专题数组136只出现一次的数字

力扣链接:https://leetcode-cn.com/probl...解题思路: 惯例思路:应用哈希/汇合来进行去重判断,然而须要从新开拓空间,导致空间复杂度回升异或:英文为exclusive OR,缩写成xor,它有如下运算法令:如上所示,在题目中,只有一个数字只呈现了一次,依据结合律&交换律&自反定律克可知,两个雷同的数字异或后果为0,0与任何数字异或等于数字自身,所以所有的数字与初始化数字0抑或,最初的值就是指呈现一次的数字func singleNumber(nums []int) int { single := 0 for _, v := range nums { single ^= v } return single}

February 14, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组121买卖股票的最佳时机

力扣链接:https://leetcode-cn.com/probl...解题思路:1、这道题目能够应用贪婪算法的策略来解决,贪婪算法是具备非后效性的问题找部分最优解的算法。2、贪婪策略:在交易股票的时候,咱们晓得最赚钱的必定是最低点的时候买入,而后最高点的时候卖出。所以咱们记录一个最低价格,而后记录一个最大利润,从前往后遍历的时候不断更新这个价格,直到得出最大的利润 func maxProfit(prices []int) int { max := 0 minPrice := prices[0] for i := 1; i < len(prices); i++ { if minPrice > prices[i] { minPrice = prices[i] } if prices[i] - minPrice > max { max = prices[i] - minPrice } } return max}

February 14, 2022 · 1 min · jiezi

关于golang:golangleetcode中级填充每个节点的下一个右侧节点指针二叉搜索树中第k小的元素

第一题 填充每个节点的下一个右侧节点指针题目 解题思路因为是在同一档次的操作,本题也可看作为层序遍历的变种,只须要在层序遍历的过程中,退出每一档次节点的串联即可、 代码func connect(root *Node) *Node { if root == nil { return root } // 初始化队列同时将第一层节点退出队列中,即根节点 queue := []*Node{root} // 循环迭代的是层数 for len(queue) > 0 { tmp := queue queue = nil // 遍历这一层的所有节点 for i, node := range tmp { // 连贯 if i+1 < len(tmp) { node.Next = tmp[i+1] } // 拓展下一层节点 if node.Left != nil { queue = append(queue, node.Left) } if node.Right != nil { queue = append(queue, node.Right) } } } // 返回根节点 return root}复杂度剖析工夫复杂度:O(N)。每个节点会被拜访一次且只会被拜访一次,即从队列中弹出,并建设 next 指针。 ...

February 13, 2022 · 2 min · jiezi

关于golang:第十八期分享一个网易go面经

自我介绍将来的次要方向介绍下之前的我的项目用到的优化点、难点为什么不要大量应用goroutinegpm模型go外面goroutine创立数量有限度吗?线程和协程有什么区别golang反对哪些并发机制go利用channel通信的形式有缓冲和无缓冲channel的区别channel实现原理被close的channel会有什么问题分布式锁晓得哪些?用channel如何实现?集群用channel如何实现分布式锁并行goroutine如何实现go用共享内存的形式实现并发如何保障平安?go的锁是可重入的吗?获取不到锁会始终期待吗?那如何实现一个timeout的锁?go切片是如何实现的次要用redis实现哪些性能缓存穿透如何解决罕用限流算法令牌桶和漏桶有什么区别不同服务之间通信有哪些形式一次rpc要通过哪些过程rpc框架如何做性能调优用过哪些rpc框架说下熔断、限流、降级、雪崩熔断降级晓得哪些开源框架吗?docker和虚拟机有什么区别serviceMash用来解决什么问题的?devops相干技术有哪些

February 13, 2022 · 1 min · jiezi

关于golang:必火一天转职Go工程师不火倒立唱征服连载中

一天工夫转职Go工程师Go官网网址Go官网中国镜像网址Go中文爱好者网址 驯服之路1、Go开发环境搭建2、HelloWorldGo开发环境搭建官网参考 # download go-archive$ wget https://golang.google.cn/dl/go1.17.7.linux-amd64.tar.gz# Extract the archive you downloaded into /usr/local, creating a Go tree in /usr/local/go$ sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.17.7.linux-amd64.tar.gz# 配置GO相干环境变量$ export GOROOT=/usr/local/go # 源码包所在门路$ export GOPATH=$HOME/go # 开发者的Go我的项目所在门路$ export PATH=$PATH:$GOROOT/bin:$GOPATH/bin # 把下面的门路增加到PATH环境变量# 验证是否装置胜利$ go versiongo version go1.17.7 linux/amd64HelloWorld$ mkdir -p $GOPATH/src/helloworld && cd $GOPATH/src/helloworld$ vim helloworld.go// helloworldpackage mainimport ( "fmt")func main() { fmt.Println("Hello World!")}$ go run helloworld.goHello World!... ...

February 13, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组119杨辉三角II

力扣链接:https://leetcode-cn.com/probl...解题思路: 解法一:应用杨辉三角的解法,返回固定下标的一位数组,该解法须要二维数组func getRow(rowIndex int) []int { res := make([][]int, rowIndex + 1) for i := range res { res[i] = make([]int, i + 1) res[i][0] = 1 res[i][i] = 1 for j := 1; j < i; j++ { res[i][j] = res[i-1][j-1] + res[i-1][j] } } return res[rowIndex]}2.优化一:其实咱们在计算row+1行时,只应用了第row行的数据,所以能够用滚动数组来进行空间上的优化 func getRow(rowIndex int) []int { pre, cur := []int, []int for i := range rowIndex { cur[i] = make([]int, i + 1) cur[i][0] = 1 cur[i][i] = 1 for j := 1; j < i; j++ { cur[j] = pre[j-1] + pre[j] } pre = cur } return pre}

February 13, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组118杨辉三角

力扣链接:https://leetcode-cn.com/probl...解题思路: 杨辉三角这道题其实是对我来说十分有意义的题目,因为所有的算法到最初,可能都是数学模型的形象后应用某种计算机语言作为载体翻译进去,做算法题跟读书的时候做数学题是没有什么区别的。然而谁让我数学很烂。。。思路具体分析如下: 这里的杨辉三角能够认为是二维数组,行示意输出的行数,列是每行生成的元素,能够晓得的是行数与输出无关,每列中蕴含的元素等于本人所处的列数(从1起始)每一列的数字中,第一个和最初一个数字均为1(第一列既能够认为是第一个,同时也是最初一个),其余数字fi = fi-1 + fi-1有了以上的剖析,那么解法也就跃然纸上了func yanghuiTriangle(numRows int) [][]int { res := make([][]int, numRows) for i := range res { res[i] = make([]int, i+1) res[i][0] = 1 res[i][i] = 1 for j := 1; j < i; j++ { res[i][j] = res[i-1][j] + res[i-1][j-1] } } return res}

February 13, 2022 · 1 min · jiezi

关于golang:golangleetcode中级二叉树的锯齿形层次遍历从前序与中序遍历序列构造二叉树

第一题 二叉树的锯齿形档次遍历题目 解题思路题目为一般的树的档次遍历用广搜能够轻松的实现该题具体思路与该题相似 https://segmentfault.com/a/11...区别只是在于 退出了对从左到右与从右到左的判断 代码变量介绍queue:双端队列level:以后遍历所在的档次q:保留以后队列的数据val:数组切片,每遍历一层节点由它带回该层的数据,若为奇数,则反转 具体代码func zigzagLevelOrder(root *TreeNode) (ans [][]int) { if root == nil { return } queue := []*TreeNode{root} for level := 0; len(queue) > 0; level++ { vals := []int{} q := queue queue = nil //遍历队列q生成下一层的节点队列,并且将以后队列的值退出val数组筹备输入 for _, node := range q { vals = append(vals, node.Val) if node.Left != nil { queue = append(queue, node.Left) } if node.Right != nil { queue = append(queue, node.Right) } } // 实质上和层序遍历一样,咱们只须要把奇数层的元素翻转即可 if level%2 == 1 { for i, n := 0, len(vals); i < n/2; i++ { vals[i], vals[n-1-i] = vals[n-1-i], vals[i] } } ans = append(ans, vals) } return}复杂度剖析工夫复杂度:O(N),其中 N 为二叉树的节点数。每个节点会且仅会被遍历一次。 ...

February 12, 2022 · 1 min · jiezi

关于golang:golangleetcode中级相交链表二叉树的中序遍历

第一题 相交链表题目 解题思路哈希查找 func getIntersectionNode(headA, headB *ListNode) *ListNode { vis := map[*ListNode]bool{} //将链表A的节点存入哈希表中 for tmp := headA; tmp != nil; tmp = tmp.Next { vis[tmp] = true } //在哈希表中搜寻链表B的第一个雷同节点 for tmp := headB; tmp != nil; tmp = tmp.Next { if vis[tmp] { return tmp } } return nil}复杂度剖析 工夫复杂度:O(m+n),其中 m 和 n 是别离是链表 headA 和 headB 的长度。须要遍历两个链表各一次。 空间复杂度:O(m),其中 m 是链表 headA 的长度。须要应用哈希汇合存储链表 headA 中的全副节点。 双指针 func getIntersectionNode(headA, headB *ListNode) *ListNode { if headA == nil || headB == nil { return nil } pa, pb := headA, headB for pa != pb {//退出循环的条件为找到雷同的节点或实现第二遍遍历,两者皆为空 if pa == nil { pa = headB } else { pa = pa.Next } if pb == nil { pb = headA } else { pb = pb.Next } } return pa}复杂度剖析 ...

February 12, 2022 · 3 min · jiezi

关于golang:Go数据结构破冰之路三循环队列

队列定义// 线性表的一种,构造上两端都是凋谢的// 容许删除的一端,称为队首// 容许插入的一端,称为队尾// 依据定义写出队列的结构构造体(假设队列中都是整型元素)type Queue struct { // 寄存队列元素的容器 container []int // 队首标记 front int // 队尾标记 tail int // 容量限度 size int}// 依据构造体写出队列的构造方法func NewQueue(size int) *Queue{ return &Queue{ container: make([]int, size) front: 0, tail: 0, // size不为font-tail // 是为了不便循环队列判空、满操作 size: 0, }}循环队列的个性 因为队首、尾永远在[0, size-1]之间打转,所以切片的长度在超过默认size后就不会再动静增长啦基本操作队列判空:队列size为0队列判满:队列size等于len(container)入队:队尾插入data后,队尾标记加一并对len(container)取余出队:取出队首元素后,队首标记加一并对len(container)取余// 队列判空func (q *Queue) IsEmpty() bool { if q.size == 0{ return true }else{ return false }}// 队列判满func (q *Queue) IsFull() bool { if q.size == len(q.container){ return true }else{ return false }}// 入队func (q *Queue) EnQueue(data int) bool { if q.IsFull(){ return false }else{ q.container[q.tail] = data q.tail = (q.tail + 1)%len(q.container) q.size++ return true }}// 出队func (q *Queue) DeQueue() (flag bool, ret int) { if q.IsEmpty(){ return false,ret }else{ ret = q.container[q.front] q.front = (q.front + 1)%len(q.container) q.size-- return true,ret }}测试func main(){ c := CircleQueue(6) c.EnQueue(1) c.EnQueue(2) c.EnQueue(3) c.EnQueue(4) c.EnQueue(5) c.EnQueue(6) fmt.Println(c.DeQueue()) fmt.Println(c.DeQueue()) fmt.Println(c.DeQueue()) fmt.Println(c.DeQueue()) fmt.Println(c.DeQueue()) fmt.Println(c.DeQueue()) fmt.Println(c.DeQueue()) fmt.Println(c.DeQueue()) c.EnQueue(1) c.EnQueue(2) fmt.Println(c.DeQueue()) fmt.Println(c.DeQueue())}// 运行后果true 1true 2true 3true 4true 5true 6false 0false 0true 1true 2

February 12, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组108将有序数组转换为二叉搜索树

力扣链接:https://leetcode-cn.com/probl...解题思路:这道题自身比较简单,是一个简略递归就能够解决的,首先找到有序队列的中位数,作为二叉树的根节点,而后右边数组为左子树的节点,左边数组为左子树的节点,顺次递归即可 /** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */func sortedArrayToBST(nums []int) *TreeNode { return helper(nums, 0, len(nums) - 1)}func helper(nums []int, low, high int) *TreeNode { if low > high { return nil } mid := (high - low) >> 1 + low root := &TreeNode{Val:nums[mid]} root.Left = helper(nums, low, mid - 1) root.Right = helper(nums, mid + 1, high) return root}

February 12, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组88合并两个有序数组

力扣链接:https://leetcode-cn.com/probl...解题思路: 第一种最天然的解法:将两个数组合并而后从新排序,这个解法最容易想到也最简略,运行的工夫复杂度也较高队列法:能够将两个数组看做两个队列,依照从小到大的形式入一个新的队列,那么就须要两个指针,别离指向两个队列的队首开始遍历func merge(nums1 []int, m int, nums2 []int, n int) { sorted := make([]int, 0, m+n) p1, p2 := 0, 0 for { if p1 == m { sorted = append(sorted, nums2[p2:]...) break } if p2 == n { sorted = append(sorted, nums1[p1:]...) break } if nums1[p1] < nums2[p2] { sorted = append(sorted, nums1[p1]) p1++ } else { sorted = append(sorted, nums2[p2]) p2++ } } copy(nums1, sorted)}

February 12, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组66加一

力扣链接:https://leetcode-cn.com/probl...解题思路:这道题其实是十分奇妙的一道题,也再次感叹算法真的是十分训练思维的。在解决数组加一的过程中,咱们晓得十进制是满十进位,所以须要非凡解决的就是9这个数字,那么如何解决呢?有哪些状况呢? 状况一:数组的最初一位数字不为9,这种状况下间接加1即可状况二:最初一位/多位数字为9,这种状况下,从后往前找到第一位不为9的,而后将其加一,从这位从前往后的都置为0,第一种状况能够认为是状况二的特例,前面没有置为0的位数状况三:全副为9,起始地位新增一位,其余的位数全副值为零func plusOne(digits []int) []int { n := len(digits) for i := n - 1; i >= 0; i-- { if digits[i] != 9 { digits[i]++ for j := i + 1; j < n; j++ { digits[j] = 0 } return digits } } newDigits := make([]int, n+1) newDigits[0] = 1 return newDigits}

February 11, 2022 · 1 min · jiezi

关于golang:面试官Context携带数据是线程安全的吗

原文链接:面试官:Context携带数据是线程平安的吗? 前言哈喽,大家好,我是asong。最近一个群里看到一个乏味的八股文,问题是:应用context携带的value是线程平安的吗?这道题其实就是考查面试者对context实现原理的了解,如果不晓得context的实现原理,很容易答错这道题,所以本文咱们就借着这道题,再从新了解一遍context携带value的实现原理。context携带value是线程平安的吗?先说答案,context自身就是线程平安的,所以context携带value也是线程平安的,写个简略例子验证一下: func main() { ctx := context.WithValue(context.Background(), "asong", "test01") go func() { for { _ = context.WithValue(ctx, "asong", "test02") } }() go func() { for { _ = context.WithValue(ctx, "asong", "test03") } }() go func() { for { fmt.Println(ctx.Value("asong")) } }() go func() { for { fmt.Println(ctx.Value("asong")) } }() time.Sleep(10 * time.Second)}程序失常运行,没有任何问题。然而context对携带的数据没有类型限度,所以任何数据类型都是用context携带,在携带的数据类型是指针类型时,就不是线程平安的,来看一个例子: func main() { m := make(map[string]string) m ["asong"] = "Golang梦工厂" ctx := context.WithValue(context.Background(), "asong", m) go func() { for { m1 := ctx.Value("asong") mm := m1.(map[string]string) mm["asong"] = "123213" } }() go func() { for { m1 := ctx.Value("asong") mm := m1.(map[string]string) mm["asong"] = "123213" } }() time.Sleep(10 * time.Second)}运行后果: ...

February 11, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组53最大子数组和

力扣连贯:https://leetcode-cn.com/probl...解题思路: 看到题的第一眼,只有状态是须要动静决定的,那么大概率就是DP动静布局了动静布局基本上是须要三架马车或者三板斧来决定的 (1)确定数组元素的意义:即dp[]数组是什么含意 (2)定义数组元素间的关系式,即状态转移方程:即 dp[n] = dp[n-1] + x (3)确定初始值:学过数学归纳法的都晓得,尽管咱们晓得了数组元素之间的关系式,如dp[n] = dp[n-1] + dp[n-2],然而咱们须要晓得最开始的值,dp[1]和dp[2]的值,这就是所谓的初始值3.回到这道题自身:(1)动静数组元素的意义:dp[i](0 <= i <= n)示意在下标为i的时候,0~i之间数组元素和的最大值 (2)状态转移方程:dp[i] = dp[i - 1] + nums[i],思考到数组中会有正数,那么方程进一步为:dp[i] = max(dp[i - 1] + nums[i], nums[i]) (3)初始值:因为初始值必定是从数组第一个元素开始,所以初始值应该为数组第一个元素的值,那么求和就从第二个下标开始遍历 func maxSubArray(nums []int) int { max := nums[0] // 初始值 for i := 1; i < len(nums); i ++ { if nums[i] + nums[i -1] > nums[i] { // 状态转移方程 nums[i] += nums[i-1] } if nums[i] > max { max = nums[i] } } return max}

February 11, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组27移除元素

力扣链接:https://leetcode-cn.com/probl...解题思路: 跟26题相比,这个数组是无序的,然而多了一个val参数,所以能够用单指针来解决从第一个数字开始,如果这个数字不等于val,那么该地位就是此数字,如果相等,那么始终往后遍历,直到找到不想等的第一个数字放在此地位要留神返回数组时的下标长度问题func removeElement(nums []int, val int) int { left := 0 for _, v := range nums { if v != val { nums[left] = v left++ } } return left}

February 11, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组26删除有序数组中的重复项

力扣链接:https://leetcode-cn.com/probl...解题思路: 题目中数组为升序数组,升序这个前提保障了雷同的元素肯定是相邻的要原地删除,就不能变换位置或者借用长期空间要保障元素的绝对地位不变动在数组解题中,快慢指针是常常会用到的解法,首先应用一个慢指针指向数组的结尾,快指针指向慢指针的下一个地位,快指针开始遍历,若遇见与慢指针相等的数字,则将快指针持续遍历,直到遇到第一个不相等的数字,将该值替换慢指针的下一个地位,同时慢指针右移一位,顺次循环,最初返回数组长度时留神加1,因为慢指针下标从0开始func removeDuplicates(nums []int) int { lower := 0 for fast := 1; fast < len(nums); fast++ { if nums[fast] == nums[lower] { continue } nums[lower+1] = nums[fast] lower++ } return lower + 1}

February 11, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组01TwoSum两数之和

力扣链接:https://leetcode-cn.com/probl...解题思路: 双循环暴力解法:比拟容易想到的就是双循环暴力解法,该算法工夫复杂度为o(n平方)哈希表:应用哈希表,以数组值为key,索引下标为value,记录在哈希表中,若target减去value失去的key在哈希表中存在,即找到这两个数字,拜访哈希表返回下标即可func twoSum(nums []int, target int) []int { numToIndex := make(map[int]int, len(nums)/2) for i, v := range nums { if _, ok := numToIndex[target - v]; ok { return []int{numToIndex[target - v], i} } numToIndex[v] = i } return []int{}}

February 11, 2022 · 1 min · jiezi

关于golang:go语言下tcp粘包分包的简单处理

go在网络编程中真的很香 什么是粘包分包: 集体了解,TCP的流式传输会因为网络情况而导致接收端每次收到的数据和发送端每次发送的数据略有差异 e.g. 发送时为 {123} {456} 承受时为 {12} {3456}办法1:应用websocket,无需解决办法2:失常tcp流程下应用长度法:利用time.Sleep(time.Nanosecond)来重现网络卡顿状况,复现粘包服务端 func main(){ listen , _ := net.Listen("tcp", "127.0.0.1:8888") fmt.Println("start listen") for { conn, err := listen.Accept() if err!=nil { continue } go process(conn) }}func process(conn net.Conn) { fmt.Printf("new conn %d", conn.RemoteAddr()) // var buffer = make([]byte, 100) for { reader := bufio.NewReader(conn) peek, _ := reader.Peek(4) buffer := bytes.NewBuffer(peek) var length int32 binary.Read(buffer, binary.BigEndian, &length) if int32(reader.Buffered()) < length+4 { continue } data := make([]byte, length+4) _, err := reader.Read(data) if err!=nil { continue } fmt.Println(string(data[4:])) }}客户端 ...

February 10, 2022 · 1 min · jiezi

关于golang:golangleetcode中级两数相加奇偶链表

第一题 两数相加题目 解题思路 具体代码func addTwoNumbers(l1, l2 *ListNode) (head *ListNode) { var tail *ListNode carry := 0 for l1 != nil || l2 != nil { n1, n2 := 0, 0 if l1 != nil { n1 = l1.Val l1 = l1.Next } if l2 != nil { n2 = l2.Val l2 = l2.Next } sum := n1 + n2 + carry sum, carry = sum%10, sum/10 if head == nil { head = &ListNode{Val: sum} tail = head } else { tail.Next = &ListNode{Val: sum} tail = tail.Next } } //如果两数相加之后产生了进位,则减少一个新的节点 if carry > 0 { tail.Next = &ListNode{Val: carry} } return}复杂度剖析工夫复杂度:O(max(m,n)),其中 m 和 n 别离为两个链表的长度。咱们要遍历两个链表的全副地位,而解决每个地位只须要 O(1) 的工夫。 ...

February 10, 2022 · 1 min · jiezi

关于golang:golangleetcode中级最长子回文串递增的三元子序列

第一题 最长子回文串题目 解题思路动静布局其中 golang的二维数组切片初始化见如下https://studygolang.com/artic... 具体代码 func longestPalindrome(s string) string { dp := make([][]bool, len(s)) for i := 0; i < len(s); i++ { dp[i] = make([]bool, len(s)) } ans := "" for i := 0; i < len(s); i++ { for k := 0; k <= i; k++ { dp[i][k] = s[i] == s[k] && (i-1 < k+1 || dp[i-1][k+1]) if dp[i][k] && i-k+1 > len(ans) { ans = s[k : i+1] } } } return ans}作者:lllxxx链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/dong-tai-gui-hua-zui-jian-dan-xie-fa-by-6qd36/起源:力扣(LeetCode)著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。核心扩大算法 ...

February 10, 2022 · 2 min · jiezi

关于golang:golang常见错误

channel常见谬误1.向一个channel发送一个nil,编译是能够通过,运行的时候会报错。 ch := make(chan int)ch <- nil运行的时候会揭示 cannot use nil as type int in send 谬误。 2.channel的len和cap有区别的。 ch := make(chan int,) //无缓冲的通道又称为阻塞的通道,默认长度len为0,容量cap为0。fmt.Println("len", len(ch))fmt.Println("cap", cap(ch))ch2 := make(chan int,1) //创立一个容量为1的有缓冲区通道,长度len为0,容量cap为1。fmt.Println("len", len(ch2))fmt.Println("cap", cap(ch2))3.向一个敞开的channel发送数据,会引起panic谬误。 ch := make(chan int,1)fmt.Println("len", len(ch))fmt.Println("cap", cap(ch))close(ch)ch <- 1 defer常见谬误1.panic之后的代码都不会再执行,包含defer函数。 defer func() { if err := recover();err != nil{ fmt.Println("test") }}()ch := make(chan int,) //无缓冲的通道又称为阻塞的通道,默认长度len为0,容量cap为0。fmt.Println("len", len(ch))fmt.Println("cap", cap(ch))close(ch)ch <- 1defer func() { fmt.Println("*****")}()

February 10, 2022 · 1 min · jiezi

关于golang:golanggo语言中map导致的内存泄漏问题

go语言的map回收机制在 Golang 中的 map 构造,在删除键值对的时候,并不会真正的删除,只是标记以后的key状态为empty。咱们上面的程序作为例子,看看当咱们在删除map中键值对时的内存变动,并理解如能力真正实现对键值对的垃圾回收。 程序根本流程为:在initMap()中,向map构造中插入10000对键值对,而后在全副删除,通过runtime.MemStats打印内存应用状况。 package mainimport ( "log" "runtime")var lastFreed uint64type element struct { X int Y int}var EleMap map[int]*elementconst Num = 10000func main() { printMemory() runtime.GC() initMap() runtime.GC() printMemory() delMap() runtime.GC() printMemory() EleMap = nil runtime.GC() printMemory()}func initMap() { EleMap = make(map[int]*element) for i := 0; i < Num; i++ { EleMap[i] = &element{i * 2, i * 3} }}func delMap() { for i := 0; i < Num; i++ { delete(EleMap, i) }}func printMemory() { var m runtime.MemStats runtime.ReadMemStats(&m) log.Printf("Alloc=%v||TotalAlloc=%v||Just_Freed=%v||Sys=%v||numGc=%v\n", m.Alloc/1024, m.TotalAlloc/1024, ((m.TotalAlloc-m.Alloc)-lastFreed)/1024, m.Sys/1024, m.NumGC) lastFreed = m.TotalAlloc - m.Alloc}程序运行后果如下: ...

February 9, 2022 · 1 min · jiezi

关于golang:Go数据结构破冰之路一数组和队列

数组(定长,值传递)数组申明// 只申明不赋值var arr [10]int //长度为10的整型数组// 申明并赋值arr1 := [3]int{1,2,3} //长度为3的整型数组,赋值{1,2,3}arr2 := [...]int{1,2,3,4,5} //赋值{1,2,3}, 由编译器计算长度为5的整型数组// 申明二维数组var plane [3][5]int // 3行5列的整型二维数组数组遍历// 第一种for i := 0; i < len(arr), i++{ fmt.Println(i, arr[i])}// 第二种for i, v := range arr { fmt.Println(i, v)}切片(不定长,援用传递)切片申明// make([ ]Type, length, capacity)s := make([]int, 1)s1 := make([]int, 5)动静扩容for i := 0;i < 11; i++{ s = append(s, i)}切片宰割// 取s[2,8)s2 := s[2:8]

February 9, 2022 · 1 min · jiezi

关于golang:RabbitMQ中三个TTL的探讨

TTL各自含意在实现提早队列的生产者代码中,一共呈现了三个TTL,这三个TTL值得探讨一下,这或者对你实现一个高可用的音讯队列有帮忙。 x-message-ttl 在创立队列时设置的音讯TTL,示意音讯在队列中最多能存活多久(ms);Expiration 公布音讯时设置的音讯TTL,音讯自产生后的存活工夫(ms);x-delay 由rabbitmq_delayed_message_exchange插件提供TTL,从交换机提早投递到队列的工夫(ms);用例音讯积压在本文中指以后音讯后面还有其余音讯。 用例一x-message-ttl = 60000Expiration = 20000x-delay = 0x-delay = 0 示意无rabbitmq_delayed_message_exchange插件烦扰下。 在音讯无积压的状况下,以后音讯将在 20s 后过期并被抛弃(抛弃指没设置死信队列状况下,下文同)。在音讯积压的状况下,若工夫在 20s~60s 之间,尽管曾经超过了 Expiration 设置的TTL,但以后音讯是不会被抛弃的。因为 RabbitMQ 仅判断队列中第一个音讯是否过期,抉择生产还是抛弃。在音讯积压的状况下,若工夫在大于 60s,曾经 x-message-ttl 设置的 TTL,音讯会被抛弃。x-message-ttl 示意一个音讯在本队列中最多能存活多久。 用例二x-message-ttl = 60000Expiration = 20000x-delay = 10000在音讯无积压的状况下,以后音讯将在 20s 后过期被抛弃。以后音讯的生命周期将是产生后进入交换机,期待 10s 后投递到队列,20s 后过期抛弃。在音讯积压的状况下,以后音讯将在 20s 后过期后不肯定会被抛弃。直到音讯不积压,RabbitMQ 判断它已过期将其抛弃。在音讯积压的状况下,以后音讯将在 10+60s 后肯定会被抛弃。队列不让音讯“待了”。 用例三x-message-ttl = 5000Expiration = 20000x-delay = 10000无论音讯是否积压,以后音讯将在 10+5s 后肯定被抛弃。以后音讯的生命周期将是产生后进入交换机,期待 10s 后投递到队列,进入队列 5s 后,队列不让音讯“待了”,音讯被抛弃。只管 Expiration 设置的TTL还未到,队列就是如此“王道”。 此外x-message-ttl和Expiration,如果不设置示意永不过期;设置 0,须要有消费者立刻生产,否则将会被抛弃。

February 9, 2022 · 1 min · jiezi

关于golang:网易传媒Go语言探索

网易传媒于2020年底开始尝试Go语言的摸索,用于解决内存资源使用率偏高,编译速度慢等问题,本文将详细描述传媒在Go语言方面的所做的工作和获得的收益。 网易传媒于2020年将外围业务全副迁入容器,并将在线业务和离线业务混部,CPU利用率晋升到了50%以上,获得了较大的收益,但在线业务方面,接入容器后仍存在一些问题: 在线业务内存使用量偏高:传媒次要开发语言是Java,应用SpringBoot框架,广泛内存使用量都在2G以上,和Go语言相比,占用内存资源很大。在线业务编译速度和启动速度偏慢,占用空间较大:因为应用Java,JVM在镜像实例都须要上百兆的空间,同时,SpringBoot在编译速度和启动速度和Go语言相比,都比较慢。Go语言于2009年由Google推出,通过了10多年的倒退,目前曾经有很多互联网厂商都在踊跃推动Go语言利用,网易传媒于2020年底开始尝试Go语言的摸索,用于解决内存资源使用率偏高,编译速度慢等问题。本文将详细描述传媒在Go语言方面的所做的工作。 1 Go语言介绍相比1995年公布的Java,Go语言是一个比拟年老的语言。年老带来了正反两方面的后果。从好的一方面来说,Go汲取了过来多种语言的长处,也没有C++这种悠久历史的语言向前兼容的枷锁;另一方面,Go因为呈现的工夫不算长,编译器、运行时、语法等都还在一直调整和优化,还未达到相似Java的成熟状态,而且开源类库也比不上诸如Python的老语言。 然而瑕不掩瑜,上面就来谈谈Go语言有哪些个性吸引咱们去应用。 编译速度快 从其它动态语言转到Go的开发者最先体验到的可能就是编译的速度。一般来说,Go的编译速度比Java和C++快5倍以上。很多C++大型项目可能须要编译10分钟以上,而雷同规模的Go我的项目很可能1分钟都不到。这个个性使代码编写者能够轻易用go run迅速编译测试,甚至间接开启IDE的主动后盾单测,在多人开发迭代时CI/CD的工夫基本上只够去一次厕所。 这种个性的次要起因官网文档里曾经提到了:Go编译模型让依赖剖析更简略,防止类C语言头文件和库的很多开销。不过这个也引入了一个解放——包之间无奈递归依赖,如果遇到相似的问题只能通过提取公共代码或者在内部初始化包等等形式来解决。 语法简略 Go语言起源于Google中一次C++新个性的分享会,一伙人(包含C语言创始人、UTF8发明人、V8 JS引擎开发者)感觉C++切实是太臃肿,索性发明一种语言来简化编程。因为Google外部员工次要应用类C语法的语言,所以Go也根本放弃了简直与C统一的语法,只有学过C就非常容易上手。另外因为Go在语法上汲取了各种语言多年的经验教训,各方面都有不少让人眼前一亮的小优化。 像动静语言一样开发 应用过动静语言的应该接触过上面这种Python代码: def biu(toy): toy.roll()o = new_ball()roll(o)roll函数能够传入任何类型的对象,这种动静语言特色使开发及其灵便不便。然而大家可能都据说过“动静一时爽,重构火葬场”的名言,相似的实现会给其它维护者造成微小的阻碍,如果不是这个起因Python3也就不会退出type hints的个性了。 那么有没有既能应用动静类型,又能限度传入的对象类型的形式呢?Go的interface就是用来解决这个问题的。interface相似一个强制性的泛化type hints,尽管它不强求特定的类型,但对象必须满足条件。上面看个简略的例子,首先申明了两种interface,并将它们组合成ReadWriteIF: type ReadIF interface { Read()}type WriteIF interface { Write()}type ReadWriteIF interface { ReadIF WriteIF}接下来应用这个interface,留神只有一个对象的类型满足interface里的全副函数,就阐明匹配上了。 func rw(i ReadWriteIF) { i.Read() i.Write()}type File struct{}func (*File) Read(){}func (*File) Write(){}rw(&File{})能够看到rw函数基本没有固定传入参数的具体类型,只有对象满足ReadWriteIF即可。 如果心愿一个函数能像脚本语言一样承受任何类型的参数,你还能够应用interface{}作为参数类型,比方规范库的fmt.Print系列函数就是这样实现的。 资源耗费少 Go与C/C++耗费的CPU差距不大,但因为Go是垃圾回收型语言,消耗的内存会多一些。因为以后指标是应用Go取代Java,这里就将Go与同为垃圾回收型语言的Java简略比拟一下。 Java当年诞生时最大的卖点之一是“一次编写,到处运行”。这个个性在20年前很棒,因为市场上简直没有虚拟化解决方案。然而到了明天呈现了Docker之类一系列跨平台工具,这种卖点可能被看做一种短板,次要起因如下: Java须要启动JVM过程来运行中间代码,程序须要预热堆内存较大时,垃圾回收器须要进行人工深刻调优,但在一些对实时性要求高的场景下,可能无解,Full GC一触发就是劫难JDK体积宏大, Spring Boot jar包体积大,在微服务架构下问题最突出Spring全家桶越来越重,导致应用全家桶的利用,性能较差抛去JVM启动和预热工夫,运行一个最简略的HTTP程序,与Go比照,Java在CPU上的耗费多约20%,内存上的耗费约高两个数量级。 为并发IO而生 练习过开发网络库的读者可能都晓得Unix的epoll零碎调用,如果理解Windows应该据说过IOCP,这两种接口别离对应网络的Reactor和Proactor模式。简略来说前者是同步的事件驱动模型,后者是异步IO。不管你应用任何语言只有波及到高性能并发IO都逃不过这两种模式开发的折磨——除了Go。 为了展现应用Go开发并发IO有如许简略,我先从大家相熟的一般程序的线程模型讲起。下图是一个常见的程序线程图,一般来说一个服务过程蕴含main、日志、网络、其余内部依赖库线程,以及外围的服务解决(计算)线程,其中服务线程可能会按CPU核数配置开启多个。 服务启动后RPC申请到来,此申请的发动端可能是客户端或者另一个服务,那么它在服务线程解决过程中将阻塞并期待回复事件。留神这里的RPC蕴含狭义上的网络协议,比方HTTP、Redis、数据库读写操作都属于RPC。 此时的状况就如下图所示,服务调用端的申请要通过网络往返和服务计算的提早后能力取得后果,而且服务端很可能还须要持续调用其它服务。 大多数开发者都会想:反正调用个别也就几十毫秒嘛,最多到秒级,我开个线程去同步期待回复就行,这样开发最不便。于是状况就会变成下图这样,每个申请占用一个连贯和一个线程。如果网络和计算提早加大,要放弃服务器性能被充分利用,就须要开启更多的连贯和线程。 为了偷懒咱们偏向于防止应用Reactor和Proactor模式,甚至都懒得去理解它们,就算有人真的心愿优化并发IO,相似Jedis这种只反对同步IO的库也能阻止他。 当初有Go能援救咱们了,在Go里没有线程的概念,你只须要晓得应用go关键字就能创立一个相似线程的goroutine。Go提供了用同步的代码来写出异步接口的办法,也就是说咱们调用IO时间接像上图冀望的一样开发就行,Go在后盾会调用epoll之类的接口来实现事件或异步解决。这样就防止了把代码写得系统难懂。上面展现一个简略的RPC客户端例子,RPC调用和后续的计算解决代码能够顺畅地写在一起放入一个goroutine,而这段代码背地就是一个epoll实现的高性能并发IO解决: func process(client *RPCClient) { response := client.Call() // 阻塞 compute(response) // CPU密集型业务}func main() { client := NewRPCClient() for i := 0; i < 100; i++ { go process(client) } select {} //死等}服务器的代码更简略,不须要再去监听事件,当获取到一个IO对象时,只有应用go就能在后盾开启一个新的解决流程。 ...

February 9, 2022 · 4 min · jiezi

关于golang:读-Go-源码可以试试这个工具

原文链接: 读 Go 源码,能够试试这个工具 编程倒退至今,从面向过程到面向对象,再到当初的面向框架。写代码变成了一件越来越容易的事件。 学习根底语法,看看框架文档,几天工夫搞出一个小我的项目并不是一件很难的事件。 但工夫长了就会发现,始终这样飘在外表是不行的,技术永远得不到晋升。 想要技术水平有一个质的飞跃,有一个很好的办法,就是读源码。 但读源码真的是一件很有挑战的事件。 想想当年本人读 Django 源码,从启动流程开始看,没走几步就放弃了,而且还放弃了很屡次。 这么说吧,我对 Django 启动局部的代码,就像对英文单词 abandon 那么相熟。 起初总结经验,发现是办法不对。 次要起因是一上来就深刻细节了,事无巨细,每个函数都不想错过。后果就导致对整体没有概念,抓不住重点,又深陷无关紧要的代码。最初就是看不进去,只能放弃。 最近看了一点 Go 源码,缓缓也摸索出了一些心得。有一个办法我感觉挺好,能够带着问题去读源码,比方: Go Error 嵌套到底是怎么实现的?为什么要防止在 Go 中应用 ioutil.ReadAll?[如何在 Go 中将 []byte 转换为 io.Reader?](https://mp.weixin.qq.com/s/nF...)在解决问题的过程中也就对源码更相熟了。 还有一点要留神的就是,先看整体,再看细节。 在这里举荐给大家一个工具,这个工具能够帮咱们梳理出代码的整体构造,我感觉还是挺有用的。是一个开源我的项目: 我的项目地址: https://github.com/jfeliu007/... 这个我的项目能够剖析一个 Go 我的项目,而后生成接口和构造体的 UML 图。有了这个图之后,基本上也就对我的项目整体关系有了一个基本概念,再读代码的话,相对来说会容易一些。 我的项目具体怎么用我倒是没认真钻研,因为老哥十分贴心的写了一个 WEB 页面: 网站链接: https://www.dumels.com/ 应用起来很不便,首先在页面最上方输入框输出我的项目地址,而后在左侧输出要剖析的代码目录就能够了。默认生成的图中会包含 Fields 和 Methods。 填写好信息之后就能够生成 UML 图了。比方我输出的 src/sync,就失去了上面这张图,有了这张图,对代码构造之间的关系就更清晰了。 还能够一次剖析多个目录,多个目录用英文逗号宰割。 如果不填写要剖析的目录,则会剖析整个我的项目,也能够抉择是否要疏忽某个目录。 情谊提醒一点,不要试图剖析整个 Go 我的项目,可能是我的项目太大了,页面是不会给你返回的。 好了,本文就到这里了。你有什么好用的工具吗?欢送给我留言交换。 往期举荐: Go 学习路线(2022)开始读 Go 源码了举荐三个实用的 Go 开发工具

February 8, 2022 · 1 min · jiezi

关于golang:Golang-实现-RabbitMQ-的延迟队列

读本文之前,你应该曾经理解 RabbitMQ 的一些概念,如队列、交换机之类。提早队列简介一个队列中的音讯在提早一段时间后才被消费者生产,这样的队列能够称之为提早队列。 提早队列的利用场景非常宽泛,如:下单后30分钟内未付款则勾销订单;在某个工夫下发一条告诉等。 通过死信实现提早队列通过Golang 实现 RabbitMQ 的死信队列的介绍,咱们能够很容易的实现一个提早队列。 将失常队列的消费者勾销;发消息时设置TTL;通过下面两点,失常队列的音讯始终不会被生产,而是期待音讯TTL到期,进入死信队列,让死信消费者进行生产,从而达到提早队列的成果。 下面看上去仿佛没什么问题,实测一下就会发现音讯不会“如期死亡”。 当先生产一个TTL为60s的音讯,再生产一个TTL为5s的音讯,第二个音讯并不会再5s后过期进入死信队列,而是须要等到第一个音讯TTL到期后,与第一个音讯一起进入死信队列。这是因为RabbitMQ 只会判断队列中的第一个音讯是否过期。 通过插件实现提早队列架构对于上文的问题,天然有解决办法,那就是通过 RabbitMQ 的 rabbitmq_delayed_message_exchange 插件来解决。本文不赘述 RabbitMQ和插件的装置,你能够参考此文装置或应用Docker来装置。 此插件的原理是将音讯在交换机处暂存储在mnesia(一个分布式数据系统)表中,提早投递到队列中,等到音讯到期再投递到队列当中。 简略理解了插件的原理,咱们便能够如此设计提早队列。 实现生产者实现的关键点: 1.在申明交换机时不在是direct类型,而是x-delayed-message类型,这是由插件提供的类型; 2.交换机要减少"x-delayed-type": "direct"参数设置; 3.公布音讯时,要在 Headers 中设置x-delay参数,来管制音讯从交换机过期工夫; err = mqCh.Publish(constant.Exchange1, constant.RoutingKey1, false, false, amqp.Publishing{ ContentType: "text/plain", Body: []byte(message), //Expiration: "10000", // 音讯过期工夫(音讯级别),毫秒 Headers: map[string]interface{}{ "x-delay": "5000", // 音讯从交换机过期工夫,毫秒(x-dead-message插件提供) },})生产者残缺代码: // producter.gopackage mainimport ( "fmt" "github.com/streadway/amqp" "learn_gin/go/rabbitmq/delayletter/constant" "learn_gin/go/rabbitmq/util" "strconv" "time")func main() { // # ========== 1.创立连贯 ========== mq := util.NewRabbitMQ() defer mq.Close() mqCh := mq.Channel // # ========== 2.设置队列(队列、交换机、绑定) ========== // 申明队列 var err error _, err = mqCh.QueueDeclare(constant.Queue1, true, false, false, false, amqp.Table{ // "x-message-ttl": 60000, // 音讯过期工夫(队列级别),毫秒 }) util.FailOnError(err, "创立队列失败") // 申明交换机 //err = mqCh.ExchangeDeclare(Exchange1, amqp.ExchangeDirect, true, false, false, false, nil) err = mqCh.ExchangeDeclare(constant.Exchange1, "x-delayed-message", true, false, false, false, amqp.Table{ "x-delayed-type": "direct", }) util.FailOnError(err, "创立交换机失败") // 队列绑定(将队列、routing-key、交换机三者绑定到一起) err = mqCh.QueueBind(constant.Queue1, constant.RoutingKey1, constant.Exchange1, false, nil) util.FailOnError(err, "队列、交换机、routing-key 绑定失败") // # ========== 4.公布音讯 ========== message := "msg" + strconv.Itoa(int(time.Now().Unix())) fmt.Println(message) // 公布音讯 err = mqCh.Publish(constant.Exchange1, constant.RoutingKey1, false, false, amqp.Publishing{ ContentType: "text/plain", Body: []byte(message), //Expiration: "10000", // 音讯过期工夫(音讯级别),毫秒 Headers: map[string]interface{}{ "x-delay": "5000", // 音讯从交换机过期工夫,毫秒(x-dead-message插件提供) }, }) util.FailOnError(err, "音讯公布失败")}因为在生产者端建设队列和交换机,所以消费者并不需要非凡的设置,间接附代码。 ...

February 8, 2022 · 2 min · jiezi

关于golang:基础版跳跃表实现golang

跳跃表入门跳跃表这个货色,始终在据说,但从未手动实现过,所以了解的也不是很透彻。最近闲来无事,用golang实现了一个根底版本,加深一下了解。 跳跃表的逻辑构造如下: 这里不解释根底原理了,网上大把的材料,总结几点加深了解: 跳跃表的底层还是链表,而且是有序链表,在结构跳跃表的时候就必须保证数据有序;跳跃表用的是空间换工夫的思维;有点相似有序数组的二分查找;跳表的查问,插入和删除操作的冀望工夫复杂度都为 O(logN);代码实现跳跃表的实现并不固定,能够有很多不同的版本,我这里仅实现了一个根底版本,并没有各种优化操作。 根底构造: // 单个节点type SkipNode struct { Val int Level int Nexts []*SkipNode}// 跳跃表type SkipList struct { Head *SkipNode //Tail *SkipNode MaxLevel int}源码: package mainimport ( "errors" "fmt" "math/rand" "time")// 单个节点type SkipNode struct { Val int Level int Nexts []*SkipNode}// 跳跃表type SkipList struct { Head *SkipNode //Tail *SkipNode MaxLevel int}// 初始化func (obj *SkipList) Init(maxLevel int) { obj.MaxLevel = maxLevel head := new(SkipNode) head.Level = 1 head.Val = -99999 head.Nexts = make([]*SkipNode, 1, maxLevel) obj.Head = head}// 获取新节点的最大层数func (obj *SkipList) GetNodeLevel() int { level := 1 for rand.Intn(2) == 1 { level++ if obj.MaxLevel <= level { break } } return level}// 插入节点func (obj *SkipList) insert(val int) error { preNodes := make([]*SkipNode, obj.Head.Level, obj.Head.Level) currNode := obj.Head // 查找定位地位 for i := obj.Head.Level - 1; i >= 0; i-- { for currNode.Nexts[i] != nil && currNode.Nexts[i].Val < val { currNode = currNode.Nexts[i] } if currNode.Nexts[i] != nil && currNode.Nexts[i].Val == val { return errors.New("same item") } preNodes[i] = currNode } // 创立新节点 node := new(SkipNode) node.Val = val node.Level = obj.GetNodeLevel() node.Nexts = make([]*SkipNode, node.Level, node.Level) for i := 0; i < node.Level; i++ { if i < obj.Head.Level { node.Nexts[i] = preNodes[i].Nexts[i] preNodes[i].Nexts[i] = node } else { node.Nexts[i] = nil obj.Head.Nexts = append(obj.Head.Nexts, node) } } obj.Head.Level = len(obj.Head.Nexts) return nil}// 查找跳表func (obj *SkipList) find(val int) *SkipNode { currNode := obj.Head // 查找定位地位 for i := obj.Head.Level - 1; i >= 0; i-- { for currNode.Nexts[i] != nil && currNode.Nexts[i].Val < val { currNode = currNode.Nexts[i] } if currNode.Nexts[i] != nil && currNode.Nexts[i].Val == val { return currNode.Nexts[i] } } return nil}// 删除节点func (obj *SkipList) del(val int) { preNodes := make([]*SkipNode, obj.Head.Level, obj.Head.Level) currNode := obj.Head // 查找定位地位 for i := obj.Head.Level - 1; i >= 0; i-- { for currNode.Nexts[i] != nil && currNode.Nexts[i].Val < val { currNode = currNode.Nexts[i] } if currNode.Nexts[i] != nil && currNode.Nexts[i].Val == val { preNodes[i] = currNode } } // 删除节点 for i := 0; i < obj.Head.Level; i++ { if preNodes[i] == nil { continue } preNodes[i].Nexts[i] = preNodes[i].Nexts[i].Nexts[i] }}// 打印跳表func (obj *SkipList) printf() { fmt.Println("skip list:") node := obj.Head for i := obj.Head.Level - 1; i >= 0; i-- { fmt.Printf(" skip list level %d: ", i) tmpNode := node.Nexts[i] for tmpNode != nil { fmt.Printf("%d->", tmpNode.Val) tmpNode = tmpNode.Nexts[i] } fmt.Println("\b\b ") }}// 结构func (obj *SkipList) build() { for i := 1; i < 70; i += 2 { obj.insert(i) }}func main() { rand.Seed(time.Now().UnixNano()) skipObj := SkipList{} skipObj.Init(10) skipObj.build() skipObj.printf() err := skipObj.insert(3) if err != nil { fmt.Printf("insert 3 failed, %s\n", err.Error()) } res := skipObj.find(37) if res == nil { fmt.Printf("not found 37\n") } else { fmt.Printf("found 37, %+v\n", res) } skipObj.del(37) skipObj.del(33) skipObj.del(4) skipObj.printf() res = skipObj.find(37) if res == nil { fmt.Printf("not found 37\n") } else { fmt.Printf("found 37, %+v\n", res) }}运行后果如下: ...

February 8, 2022 · 3 min · jiezi

关于golang:golangleetcode中级字母异位词分组无重复字符的最长子串

第一题 字母异位词分组题目 解题思路题目线索给到了 排序 和 哈希表排序实现之后能够存入哈希表之中,题目要求的任意程序返回后果序列刚好与遍历哈希表的特色相符 排序的具体实现对于字母的排序,咱们能够应用sort.Slice函数 sort.Slice(s, func(i, j int) bool { return s[i] < s[j] })函数的第一个参数必须为切片,第二个参数为匿名函数,定义排序的规定 代码func groupAnagrams(strs []string) [][]string { m := map[string][]string{} for _, str := range strs { s := []byte(str) sort.Slice(s, func(i, j int) bool { return s[i] < s[j] }) sortedStr := string(s) m[sortedStr] = append(m[sortedStr], str) } ans := make([][]string, 0, len(m)) for _, v := range m { ans = append(ans, v) } return ans}复杂度剖析工夫复杂度:O(nklogk),其中 n 是 strs 中的字符串的数量,k 是strs 中的字符串的的最大长度。须要遍历 n 个字符串,对于每个字符串,须要O(klogk) 的工夫进行排序以及 O(1) 的工夫更新哈希表,因而总工夫复杂度是O(nklogk)。 ...

February 8, 2022 · 2 min · jiezi

关于golang:Go多线程下载优化滑动窗口并发控制

应用p2p下载的时候有用户问是否核心节点下载实现后,能力开始p2p下载,尤其是几GB 甚至几十GB的大文件。理论中核心节点的文件是一边下载一边共享给其余节点的,从分片的角度看,下载完第一个分片,全节点共享下载过程就开始了。本文介绍p2p核心节点作为初始节点下载文件提速的一些优化改良,同时借此分享下golang中的一些并发管制的思考 间接下载最简略的间接下载,应用默认的http client发动申请,将数据流写入writer即可,实现相干的writer即可实现一边下载一边记录分片信息,从而提供给其余节点下载社区Dragonfly我的项目的下载源文件的办法 // 间接下载文件// writer一边拷入文件会一边计算分片,每实现一个分片便能够共享给其余节点下载func directDownload(url string, headers map[string]string, writer io.Writer) error { req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return err } for k, v := range headers { req.Header.Set(k, v) } resp, err := http.DefaultClient.Do(req) if err != nil{ return err } defer resp.Body.Close() if _, err := io.Copy(writer, resp.Body); err != nil { return err } return nil}多线程下载然而当文件很大,单链接限速时,文件下载较慢,在http下载中通常提供了Ranges:bytes=a-b来指定本次申请下载a~b字节的局部,因而能够利用该性能来做多线程下载指定线程数,文件大小,实现多线程下载一个文件,这也是golang中根底的并发执行子工作,搭配应用sync.WaitGroup{}来检测所有的子工作是否实现,实现所有的子工作后即可退出 多线程下载在单线程速度无限时提速显著,例如单链接限速5MB/s时,能够通过多线程来减速下载,取得几倍速度,一些开源的百度云下载减速也是多线程减速。 // 文件过大时,每个协程下载的分片仍旧很大,中断后重试的老本略高func downloadWithMultiThreadsV1(url string, headers map[string]string, filePath string, threads int, size int64) error { pieceSize := size / int64(threads) wg := sync.WaitGroup{} for i := 0; i < threads; i++ { wg.Add(1) go func(pieceNum int64, pieceSize int64, headers map[string]string) { defer wg.Done() if err := downloadWithPiece(url, headers, filePath, pieceNum, pieceSize); err != nil { panic(err) } }(int64(i), pieceSize, copyHeader(headers)) } wg.Wait() return nil}// 下载分片写入文件func downloadWithPiece(url string, headers map[string]string, filePath string, pieceNum int64, pieceSize int64) error { startRange := pieceNum * pieceSize endRange := (pieceNum+1)*pieceSize - 1 byteRanges := fmt.Sprintf("bytes=%d-%d", startRange, endRange) headers["Range"] = byteRanges fw, err := os.OpenFile(filePath, os.O_WRONLY, os.ModePerm) if err != nil { return err } // 关上文件偏移至该写入的地位 _, err = fw.Seek(startRange, 0) if err != nil { return err } err = directDownload(url, headers, fw) if err != nil { return err } return nil}基于小分片多线程下载大文件在跨region、跨国传输时,网络稳定容易导致链接断开后,间接开固定线程数去均分文件下载失败后须要重试下载的分片很大,重试老本较高。因而能够分较小的分片去多线程下载,失败后重试老本也较低,实现断点续传也简略。一个1GB的文件以16MB分片去下载,须要60次,显然像上一个办法那样间接for循环启动去下载会导致协程过多,且源站压力也会大,因而须要管制并发。 ...

February 8, 2022 · 3 min · jiezi

关于golang:第十三期B站后端开发实习生一二面经

写在最前:非科班渣硕去年转码一年,不是什么大佬,纯小白(go语言开发)。 一面(大略70min)首先是自我介绍。(比拟传统,就是形容下本人的技术栈)线程和过程的关系。线程之间如何进行通信。死锁产生的条件。简述go语言GMP调度模型。简略的问了下go语言的援用类型有什么。数据库ACID准则,别离代表什么意思,别离举个例子。为什么Mysql默认是可反复读,如何实现的。提交读,如何实现的。Mysql 索引的分类,聚簇索引与非聚簇索引区别谈到了锁,而后写了两个情景题,更新一条记录时,需不需要加锁,此时有一个事务须要插入一条记录是否胜利。谈谈MVCC。计算机网络三次握手,四次挥手。syn攻打,为什么是四次挥手不是三次挥手。进行了算法题:树的层序遍历。 反诘: 还有一些题目有点遗记了,然而总体难度不高,面试官会疏导你,一步一步深刻。(下午五点面的,早晨七点半邮件约二面) 二面(大略60min)上来也是先自我介绍。(楼主认为二面会问很多我的项目,后果全程都是根底,并且越问越深)问除go之外还会什么语言,大学学过Java(早忘了),问go和java的区别,并且说是开发题,让我想好在答复。go语言的GMP模型,全局队列中的G会不会饥饿,为什么?P的数量是多少?能批改吗?M的数量是多少?P和M的数量肯定是1:1吗?如果一个G阻塞了会怎么样?讲一讲GC的原理,三色标记法?还懂其余的GC原理吗?逃逸剖析说下?为什么要逃逸剖析?如何防止逃逸并发管制的办法?chan、sync包chan的相干问题,如敞开一个已敞开的chan会如何,有缓存和没缓存的区别是什么?等等。。。Map的底层?查问的工夫复杂度多少?hashmap如何进行扩容?产生哈希碰撞如何解决?将链表改成红黑树?红黑树与AVL比拟Mysql索引讲一下,为什么B+树更好?B+树与差异在哪?用B树查问时候如何遍历?前序?层序?为什么查问优化?explain,有什么内容?计算机网络:TCP IP 有什么区别,作用是什么?TCP 和UDP 的区别。四次挥手细节,time_wait 的状态 为什么2MLS?大量处于Close wait 是什么场景,如何解决?工夫不是很多了,进行算法:间断子序列的最大和。反诘总的面试体验是很好的,都会在你不懂的中央疏导你,让你思考。

February 8, 2022 · 1 min · jiezi

关于golang:golangleetcode中级三数之和amp矩阵置零

第一题 三数之和题目 解题思路 代码func threeSum(nums []int) [][]int { n := len(nums) sort.Ints(nums) ans := make([][]int, 0) // 枚举 a for first := 0; first < n; first++ { // 须要和上一次枚举的数不雷同 if first > 0 && nums[first] == nums[first - 1] { continue } // c 对应的指针初始指向数组的最右端 third := n - 1 target := -1 * nums[first] // 枚举 b for second := first + 1; second < n; second++ { // 须要和上一次枚举的数不雷同 if second > first + 1 && nums[second] == nums[second - 1] { continue } // 须要保障 b 的指针在 c 的指针的左侧 for second < third && nums[second] + nums[third] > target { third-- } // 如果指针重合,随着 b 后续的减少 // 就不会有满足 a+b+c=0 并且 b<c 的 c 了,能够退出循环 if second == third { break } if nums[second] + nums[third] == target { ans = append(ans, []int{nums[first], nums[second], nums[third]}) } } } return ans}作者:LeetCode-Solution链接:https://leetcode-cn.com/problems/3sum/solution/san-shu-zhi-he-by-leetcode-solution/起源:力扣(LeetCode)著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。第二题 矩阵置零题目 ...

February 7, 2022 · 2 min · jiezi

关于golang:Golang实现简单的LRU缓存

LRU缓存容器有最大的缓存应用限度,超出限度的新增操作会淘汰掉最近起码应用的内容。 实现的思路就是,应用链表来保护淘汰key的优先级,达到最大容量限度就淘汰优先级最低的。 type LRU struct { size int // 限度应用缓存数据个数 ll *list.List // 保护淘汰优先级 m map[string]*list.Element // 存储kv mu sync.Mutex // 竞争同步}type keyValue struct { key string val interface{}}func New(size int) *LRU { lru := &LRU{ size: size, ll: list.New(), m: make(map[string]*list.Element), mu: sync.Mutex{}, } return lru}func (lru *LRU) Add(key string, value interface{}) error { lru.mu.Lock() defer lru.mu.Unlock() if _, ok := lru.m[key]; ok { return errors.New("key already exists in LRU") } if len(lru.m) == lru.size { lru.removeOldest() } val := &keyValue{ key: key, val: value, } ele := lru.ll.PushFront(val) lru.m[key] = ele return nil}func (lru *LRU) removeOldest() { ele := lru.ll.Back() lru.ll.Remove(ele) kv := ele.Value.(*keyValue) delete(lru.m, kv.key)}func (lru *LRU) Get(key string) interface{} { ele, ok := lru.m[key] if ok { lru.ll.MoveToFront(ele) kv := ele.Value.(*keyValue) return kv.val } return nil}

February 7, 2022 · 1 min · jiezi

关于golang:Go-Quiz-从Go面试题看panic注意事项第1篇

面试题这是Go Quiz系列里对于panic的第1篇,次要考查同一个goroutine在屡次panic场景下recover的机制。 // quiz0.gopackage mainimport "fmt"func main() { defer func() { fmt.Println(recover()) }() defer func() { fmt.Println(recover()) }() defer panic(1) panic(2)}A: 2 <nil>B: 1 <nil>C: 2 1D: 1 2E: 间接panic解析被defer的函数调用会被延后到函数return或者panic退出之前执行,因而本题的执行后果如下: Step 1: 执行panic(2),触发被defer的函数的执行 Step 2: 执行代码里第9行被defer的函数调用panic(1),panic(1)会笼罩panic(2),能够当做panic(2)没有了 Step 3: 执行代码里第8行被defer的函数调用,recover()捕捉panic(1),打印1 Step 4: 执行代码里第7行被defer的函数调用,recover()返回的是nil,因为panic曾经被第8行的recover()捕捉,所以打印nil 所以本题的答案是B 思考题留一道思考题,想晓得答案的能够给自己vx公众号发送音讯panic获取答案和题目解析。 // quiz1.gopackage mainimport "fmt"func main() { defer func() { fmt.Println(recover()) }() defer panic(1) panic(2)}A: 1B: 2C: 先打印1,而后panicD: 先打印2,而后panic加餐Go Quiz: Google工程师的Go语言面试题Go Quiz: 从Go面试题看slice的底层原理和注意事项Go Quiz: 从Go面试题搞懂slice range遍历的坑Go Quiz: 从Go面试题看channel的注意事项Go Quiz: 从Go面试题看channel在select场景下的注意事项Go Quiz: 从Go面试题看defer语义的底层原理和注意事项Go Quiz: 从Go面试题看defer的注意事项第2篇Go Quiz: 从Go面试题看defer的注意事项第3篇Go Quiz: 从Go面试题看分号规定和switch的注意事项官网教程:Go泛型入门一文读懂Go泛型设计和应用场景开源地址文章和示例代码开源在GitHub: Go语言高级、中级和高级教程。 ...

February 7, 2022 · 1 min · jiezi

关于golang:Go-泛型变更约束太丑了先移动到-xexp-做实验性功能

大家好,我是煎鱼。 Go 泛型配套了各种规范库,像是常见的 maps、slices 泛型库。 晚期他们是长这样的: package mapsfunc Keys[M constraints.Map[K, V], K comparable, V any](m M) []Kfunc Values[M constraints.Map[K, V], K comparable, V any](m M) []V...又或是: package slicesfunc Compare[E constraints.Ordered](s1, s2 []E) int ...关注到外面的规范库 constraints,他就是明天变更的配角。他咋了呢? 背景规范库 constraints 是个陈腐事物,由泛型扛把子 Ian Lance Taylor 在 2021 年 9 月 24 日提交《constraints: new package to define standard type parameter constraints》 所增加。 如下图: 次要作用是增加一个束缚(constraints)包来定义一些规范有用的束缚,所以咱们会在通用库看到这些规范束缚的应用。 原因新提案在社区一番热烈探讨中,有人提了一个提案《proposal: constraints: rename package to "of"》,心愿对 constraints 包进行更名。 ...

February 7, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode初级算法其他缺失数字

题目:给定一个蕴含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范畴内没有呈现在数组中的那个数。 链接: 力扣Leetcode—高级算法—其余—缺失数字. 示例 1: 输出:nums = [3,0,1]输入:2解释:n = 3,因为有 3 个数字,所以所有的数字都在范畴 [0,3] 内。2 是失落的数字,因为它没有呈现在 nums 中。示例 2: 输出:nums = [0,1]输入:2解释:n = 2,因为有 2 个数字,所以所有的数字都在范畴 [0,2] 内。2 是失落的数字,因为它没有呈现在 nums 中。示例 3: 输出:nums = [9,6,4,2,3,5,7,0,1]输入:8解释:n = 9,因为有 9 个数字,所以所有的数字都在范畴 [0,9] 内。8 是失落的数字,因为它没有呈现在 nums 中。示例 4: 输出:nums = [0]输入:1解释:n = 1,因为有 1 个数字,所以所有的数字都在范畴 [0,1] 内。1 是失落的数字,因为它没有呈现在 nums 中。标签:位运算、数组、哈希表、数学、序 思路:首项加末项乘以项数/2,就是蕴含 [0, n] 中 n 个数的数组的总和,而后减掉 nums 外面的数组和,就是缺失的那个数 ...

February 7, 2022 · 1 min · jiezi

关于golang:Golang中int-int8-int16-int32-int64和uint区别

前言在学习go语言时,做算法题会很常常遇到go语言的各种int类型,为什么会有int、int8、int16等等的类型呢?为什么不像java一样,只个int类型呢? 测试unsafe.Sizeof() 只返回数据类型的大小,不论援用数据的大小,单位为Byte package mainimport ( "fmt" "unsafe")func main() { var a int = 1 var b int8 = 2 var c int16 = 3 var d int32 = 4 var e int64 = 5 fmt.Println(unsafe.Sizeof(a)) fmt.Println(unsafe.Sizeof(b)) fmt.Println(unsafe.Sizeof(c)) fmt.Println(unsafe.Sizeof(d)) fmt.Println(unsafe.Sizeof(e))}后果F:\go\bin\go.exe build -o C:\Users\wang3\AppData\Local\Temp\GoLand\___go_build_test_go.exe G:\Gospace\leetcode\test.go #gosetupC:\Users\wang3\AppData\Local\Temp\GoLand\___go_build_test_go.exe81248论断int类型的大小为 8 字节int8类型大小为 1 字节int16类型大小为 2 字节int32类型大小为 4 字节int64类型大小为 8 字节咱们看一下官网文档 int is a signed integer type that is at least 32 bits in size. It is a distinct type, however, and not an alias for, say, int32. 意思是 int 是一个至多32位的有符号整数类型。然而,它是一个不同的类型,而不是int32的别名。int 和 int32 是两码事。uint is a variable sized type, on your 64 bit computer uint is 64 bits wide.uint 是一种可变大小的类型,在64位计算机上,uint 是64位宽的。uint 和 uint8 等都属于无符号 int 类型。uint 类型长度取决于 CPU,如果是32位CPU就是4个字节,如果是64位就是8个字节。 ...

February 6, 2022 · 1 min · jiezi

关于golang:golangleetcode初级有效的括号amp缺失数字

第一题 无效的括号题目 解题思路显然,要使所有的括号匹配,最容易想到的办法就是栈每读到一个左括号,便将其入栈,每读到一个右括号,便将其出栈如果读完字符串之后栈内仍有元素,阐明有多余的左括号如果读到右括号时栈为空,阐明有多余的右括号 代码func isValid(s string) bool { n := len(s) //如果是奇数,能够间接断定字符串是错的 if n % 2 == 1 { return false } //字符串的匹配 pairs := map[byte]byte{ ')': '(', ']': '[', '}': '{', } stack := []byte{} for i := 0; i < n; i++ { if pairs[s[i]] > 0 { if len(stack) == 0 || stack[len(stack)-1] != pairs[s[i]] { return false } //出栈 stack = stack[:len(stack)-1] } else { //出栈 stack = append(stack, s[i]) } } return len(stack) == 0}复杂度剖析工夫复杂度:O(n),其中 n 是字符串 s 的长度。 ...

February 6, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode初级算法其他汉明距离

题目:两个整数之间的 汉明间隔 指的是这两个数字对应二进制位不同的地位的数目。给你两个整数 x 和 y,计算并返回它们之间的汉明间隔。 链接: 力扣Leetcode—高级算法—汉明间隔. 示例1 : 输出:x = 1, y = 4输入:2解释:1 (0 0 0 1)4 (0 1 0 0)        ↑    ↑下面的箭头指出了对应二进制位不同的地位。示例2 : 输出:x = 3, y = 1输入:1标签:位运算 思路:异或运算 0^0=0; 0^1=1; 1^0=1; 1^1=0(只有雷同的相异或为0,不雷同的为1) 次要Go代码如下: package mainimport ( "fmt" "math/bits")func hammingDistance(x int, y int) int { return bits.OnesCount(uint(x ^ y))}func main() { var x, y int fmt.Scanf("%d,%d", &x, &y) fmt.Println(hammingDistance(x, y))}提交截图:

February 6, 2022 · 1 min · jiezi

关于golang:golangleetcode初级颠倒二进制位杨辉三角

第一题 颠倒二进制位题目 解题思路 代码const( m1=0x55555555 //0101 0101 0101 0101 0101 0101 0101 0101 m2=0x33333333 //0011 0011 0011 0011 0011 0011 0011 0011 m4=0x0f0f0f0f m8=0x00ff00ff)func reverseBits(num uint32) uint32 { num = num>>1&m1 | num&m1<<1 num = num>>2&m2 | num&m2<<2 num = num>>4&m4 | num&m4<<4 num = num>>8&m8 | num&m8<<8 return num>>16 | num<<16}复杂度剖析工夫复杂度:O(1) 空间复杂度:O(1) 第二题 杨辉三角题目 解题思路杨辉三角每一行除第一个数和最初一个数为一以外其余每个数都是上一行两个数之和咱们能够以此为外围设计代码 具体代码//难点在golang中的二维数组的应用func generate(numRows int) [][]int { ans := make([][]int, numRows)for i := range ans { ans[i] = make([]int, i+1) ans[i][0] = 1 ans[i][i] = 1 for j := 1; j < i; j++ { ans[i][j] = ans[i-1][j] + ans[i-1][j-1] }}return ans} ...

February 5, 2022 · 1 min · jiezi

关于golang:第十一期三年Go面经之好未来-一面

一面 自我介绍说一个我的项目的架构go次要用的框架对go的中间件和工作机制有理解吗?对数据库操作有什么理解吗对连接池有理解吗?go的垃圾回收机制gmp模型go的sync.Map理解吗channel次要做什么事件数据库这块儿mysql用的多吗?存储引擎理解哪些对mysql索引理解哪些redis的过期策略是什么?微服务这边用到哪些?算法:两个无序数组找到他们的交加算法:分层遍历二叉树常见的http状态码tcp和udp区别tcp三次握手四次挥手业务迭代遇到过早晨上线的事件吗?上线的时候业务中断有什么形式去躲避吗?k8spod切换策略二面 自我介绍做过的我的项目说一下怎么查看go问题将来技术方向怎么选gmp模型切片的底层实现go和node的差异三面 自我介绍k8s如何找到一个节点上的所有pod如何通过goclient写代码获取日志监控怎么做的?dockerfilecmd和entrypoint有什么区别我的项目外面有本人独立负责的吗?说下在线教室如何保障连贯的平衡?不至于所有连贯连到一个中央?调研的ocr辨认是做什么?做个题,看下这个这么写有什么问题写个channel相干的题,并发模型,爬虫url,管制并发量context包外部如何实现的?四面 自我介绍你在第一家公司服务的用户是谁?素质教育还是应试教育?你在外面用技术解决什么问题?这外面有什么你感觉做得比拟好的我的项目?视频用的什么服务?信令用wss还是ws?调度哪个用户连贯哪个机器?如果业务量大,如何让客户端可能平衡的连贯服务器wss是基于tcp的,tcp有个半连贯队列,有没有遇到发了信令然而服务器没收到的状况?自习和用户增长?题拍拍次要做拍搜服务的,题拍拍次要做增长,前面会做微服务架构k8s等思考问题的时候从用户角度去思考?用户是谁?为谁服务?五面 自我介绍devops是怎么做的?会保留一些tag、镜像之类的货色吗?服务的属性配置用的什么?docker是怎么做隔离的?docker和宿主机有几种网络通信形式k8s和pod什么关系?k8s定义了什么规范来操纵dockerk8s有几种service类型报警这边怎么做的?为什么没有用ELKgo怎么实现封装继承多态为什么go的变量申请类型是为了什么?

February 5, 2022 · 1 min · jiezi

关于golang:golangleetcode初级位1的个数amp汉明距离

第一题 位1的间隔题目 解题思路对于二进制数的操作位运算无疑是最高效的最间接的思路是间接用与运算读取1的个数循环32次后返回计数器的值 代码func hammingWeight(num uint32) int { var count int k := 32 for i := 0; i < k; i++ { a := num & 1 count += int(a) num = num >> 1 } return count}复杂度剖析及优化 第二题 汉明间隔题目 解题思路能够发现在将x与y进行异或之后咱们把一个简单的问题转换成为了已解决的问题 代码func hammingDistance(x int, y int) int { return hammingWeight(uint32(x)^uint32(y))}func hammingWeight(num uint32) int { var count int k := 32 for i := 0; i < k; i++ { a := num & 1 count += int(a) num = num >> 1 } return count}优化 ...

February 4, 2022 · 1 min · jiezi

关于golang:重磅Go-118将移除用于泛型的constraints包

背景Go官网团队在Go 1.18 Beta 1版本的规范库里因为泛型设计而引入了contraints包。 constraints包里定义了Signed,Unsigned, Integer, Float, Complex和Ordered共6个interface类型,能够用于泛型里的类型束缚(type constraint)。 比方咱们能够用constraints包写出如下泛型代码: // test.gopackage mainimport ( "constraints" "fmt")// return the min valuefunc min[T constraints.Ordered](a, b T) T { fmt.Printf("%T ", a) if a < b { return a } return b}func main() { minInt := min(1, 2) fmt.Println(minInt) minFloat := min(1.0, 2.0) fmt.Println(minFloat) minStr := min("a", "b") fmt.Println(minStr)}函数min是一个泛型函数,接管2个参数,返回其中的较小者。 类型参数T的类型束缚contraints.Ordered的定义如下: type Ordered interface { Integer | Float | ~string}下面代码的执行后果为: int 1float64 1string a备注:如果对Go泛型和constraints包还不太理解的同学,能够翻看我之前写的一文读懂Go泛型设计和应用场景。 ...

February 4, 2022 · 2 min · jiezi

关于golang:第十期go面经-映客

goslice和map的区别,slice和数组的区别go构造体和构造体指针的区别go深拷贝,什么时候须要深拷贝如何拿到多个goroutine的返回值,如何区别他们go如何防止panic设计用户详情的表,如何生成主键分库之后唯一性如何保障实现一个队列拜访复杂度为O(1)设计一个日榜零碎,分布式下如何做说下我的项目外面遇到的优化问题说下我的项目过后的实现形式哪些键能够设置惟一索引如何实现一个短链接服务一个SQL语句的执行过程问了很多我的项目相干问题为什么选型redis构造体创立优化两头各个链条呈现问题怎么办?如何解决,有没有什么其余计划gochannel实现排序连接池读过什么go源码没有linux常用命令列举一下用正则去掉空行四次挥手go语言gc理解吗?redis设计稳定性协程线程区别你有什么单薄的中央?本人将来的技术布局是什么go什么场景应用接口构造体传递场景技术积攒技术打算让你最有成就感的事件对加班怎么看最近在看什么书?

February 4, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode初级算法其他位1的个数

题目:编写一个函数,输出是一个无符号整数(以二进制串的模式),返回其二进制表达式中数字位数为 '1' 的个数(也被称为汉明分量)。 提醒: 请留神,在某些语言(如 Java)中,没有无符号整数类型。在这种状况下,输出和输入都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其外部的二进制示意模式都是雷同的。在 Java 中,编译器应用二进制补码记法来示意有符号整数。因而,在下面的 示例 3 中,输出示意有符号整数 -3。输出必须是长度为 32 的 二进制串 。链接: 力扣Leetcode—高级算法—其余—位1的个数. 示例1 : 输出:00000000000000000000000000001011输入:3解释:输出的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。示例2 : 输出:00000000000000000000000010000000输入:1解释:输出的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。示例3 : 输出:11111111111111111111111111111101输入:31解释:输出的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。标签:位运算 思路:利用num & (num - 1)去清二进制数 num 的最初一个 1。计数直到num变为0,清了多少次1。 次要Go代码如下: func hammingWeight(num uint32) int { var n int for ; num != 0; n++ { num = num & (num - 1) } return n}提交截图:

February 3, 2022 · 1 min · jiezi

关于golang:第九期PingCap研发实习面经

集体状况自己目前是计算机专业研二,集体对开源十分感兴趣,也退出了一些开源组织做开源内容,次要应用语言是golang,我的项目次要和分布式相干,学习过MIT 6.824的局部内容。一面在面试前会有hr小姐姐来和你分割,跟你确认面试工夫,有任何问题都会帮忙进行协调,十分nice。面试开始之后,面试官会首先介绍集体状况以及公司的业务状况,包含现阶段在做的一些次要工作有哪些还有如果将来入职你能接触到哪些内容。接下来就是正式开始面试:自我介绍。 介绍我的项目。 分布式一些实践概念,分布式锁的概念,如何实现分布式锁。 应用ETCD是如何实现分布式锁的,都用到了哪些API,如何学习应用的?能够介绍一下ETCD的原理么? 应用Redis如何实现分布式锁,怎么保障Redis锁的失常开释,如何评估工作的执行工夫主动续约锁。 有没有做过一些破坏性的测试,例如计算机故障,网络短掉了?你是怎么解决的? 事务的隔离级别?并发事务会带来的问题?举几个例子阐明一下 当写一个程序申请内存时,会做哪些操作?中断,页面置换,堆,栈等。 力扣随机一道题。工夫复杂度,空间复杂度,剖析最差状况。 一道设计题,给你10k个工作,其中1%低优先级工作,其余为高优先级工作,双核CPU如何调度最为高效。 反诘。 一面的面试官人很好,有一些问题你不分明会给你解释,也会做一些疏导,全程都没有很压抑。而且最初还说了pingcap给他的一些感触,而且也给了一些倡议十分真挚二面一面完结的第二天中午hr小姐姐就来约二面了。面试开始之前同样面试官也会简要介绍一下状况。自我介绍。 感觉本人一面体现怎么样。 一个程序从写的代码文件到最初输入后果,两头经验的整个过程是怎么样的?编译连贯装入以及内存的一些相干操作。 程序运行起来后,被CPU执行调度,这个过程说一下?过程,线程以及调度。 go协程调度模型,GC(记不清问没问这些了) A要给B发送数据,两头经验了哪些流程,从传输到从网卡整个来说一下。网络连接,传输层,中断,内核态用户态,IO多路复用。 IO多路复用具体说一下。 力扣随机一道题。工夫复杂度,空间复杂度。 反诘。 二面的面试官常识储备十分丰富,而且从问的问题上能够看出,更多的是从整个计算机整体的执行层面将各种常识进行串联的,如果对于某个中央说的不是很分明会持续探讨。而且反诘环节中面试官对于个人成长和常识的了解都比拟有深度,还具体的介绍了公司整体在做的几条主线,让你对公司做的内容进一步有了更分明的理解,而且也介绍了一些技术栈看你对哪个更感兴趣。hr面同样是二面完结之后的第二天中午就约了hr面试。面试开始之前同样面试官也会简要介绍一下状况。自我介绍 有没有什么比拟骄傲的事件 有没有哪些是本人比拟遗憾的事件 面对一些突发状况是怎么解决的 和小伙伴意见分歧怎么解决 如何了解开源 等等记不太清了 总结hr面没过多久之前对接的小姐姐就来谈offer的一些细节了,整体面试感触十分好,对于整个面试来说我集体感觉不是特地难,没有那些很惯例的套路,还是看你对这块的了解是怎么样的,还有你集体的学习能力是怎么样的。而且面试也是学习和成长的过程,面试你的人也都是在这个畛域做了比拟久的前辈,能够从和他们的对话中学到很多常识。pingcap反对近程办公当初也是一家分布式单干的公司,hr面的时候提到如果在一个城市能够凑够一桌麻将的人,那么就会在那个城市开一个office,当初北上广深,杭州,成都都能够选,还不来试试吗?

February 3, 2022 · 1 min · jiezi

关于golang:第八期字节跳动面试已offer

字节一面(50min) 1.自我介绍(面试官在看简历);2.问我的项目(让我挑一个最相熟的我的项目)3.问用到的技术栈4.问mysql有哪些存储引擎,你用到什么存储引擎,区别是什么?5.sql优化策略6.汇集索引的底层7.mvcc机制理解嘛8.mysql的表锁有哪些?9.给了一段sql语句,问会上什么锁?具体解读一下10.聊计网:输出url会产生什么?(一顿bala)11.tcp/ip三次握手,udp tcp区别12.场景题:要是握手第三次断了我怎么去设计?13.怎么保障tcp连贯稳定性?14.流量管制,拥塞管制。滑动窗口。15.做题:链表相加16.反诘:技术栈。 面完20分钟后收到hr电话约第2轮面试,约了第二天。 二面(1h)1.自我介绍(问能实习多久)2.过程和线程还有协程3.线程和过程的通信形式以及两者区别4.说出单例模式几种实现形式以及区别5.redis为什么快?6.redis晓得多少说多少?7.redis的sorted set8 sorted set底层,越细越好。9.TCP/IP三次握手四次挥手10.Mysql索引,联结索引,生效,左连贯(八股文)11.做题:给一个表并做一道sql题 写三个语句12.做题:最长的括号子串13.聊最善于的我的项目(根本我在说)14.反诘波及到的业务,说不会波及到一些高并发外围的货色,反诘能不能过?都有可能,会评估,过了会告诉你。 三面等了2个工作日,两头有个端午节,hr是节后第一天告诉我二面过了,约第三面的工夫,我就约了周日。 字节三面面经(1h)三面面试官一看发量就是大佬,特地有亲和力,大略不到40岁,有说有笑的,两头还给我一次性点了4个题,我吓呆了,而后他说就做两个,齐全不是按我简历问的,三面面试官是发散着问。 1.自我介绍一下2.介绍一下实习经验和我的项目3.连接池,一些参数的含意(具体探讨了一下 removeAbandonedTimeout细节)4.虚拟内存和物理内存的区别和关系?5.策略模式说一下,应用场景?6.单例模式的几种写法以及为啥双重校验锁。7.说下volatile底层,保障了什么?8.指令重排是什么?9.数据库怎么保障acid的,底层策略,说下undolog和redolog,next-key locks,那oracle呢?10.异样的一些开放性题目,没有固定答案,重来没见过的题(这一段消耗了很多工夫,我没听明确啥意思,都是凋谢的题目)11.一个1x2的矩形放2xn的矩形里有多少种放法?写出表达式12.做题:a.股票买卖(两种写法,优化) b.二叉树的公共先人 面试官夸了一下我写正文的习惯,还让我代码里尽量功能块跟其余性能用一行空格辨别一下,特地谨严 13.发问,而后还问到了go协程是怎么实现的。 第二天说三面通过了,而后约了hr面,hr小姐姐特地棒 字节hr面(30min)1.自我介绍2.实验室的状况说一下,还问了导师姓名3.怎么学习新技术的,用在了哪个中央能够说一下嘛?4.有哪些offer?5.为什么抉择字节?6.我的项目介绍7.对后面几位面试官有什么印象?8.找的职位都是后端开发嘛?9.说下性格特点?10.沟通了一下入职工夫,我说两周内,问能够实习多久,转正否?反诘:什么时候出后果?说将来一周内会有hr分割你而后下午五点间接发了实习offer,约了入职工夫,效率特高,速度很快,我都诧异了! 总结:其实之前投的是飞书的岗位而后转到其余部门这边来了,过后一面之前有些事件,还想着跟hr勾销面试,但hr给我立即换了工夫(面试前一小时),最初四面居然一路磕磕绊绊走下来了,所以千万不要放弃,打工人,一起加油!!

February 3, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode初级算法数学罗马数字转整数

题目:罗马数字蕴含以下七种字符: I, V, X, L,C,D 和 M。 字符 数值I 1V 5X 10L 50C 100D 500M 1000例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。 通常状况下,罗马数字中小的数字在大的数字的左边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的右边,所示意的数等于大数 5 减小数 1 失去的数值 4 。同样地,数字 9 示意为 IX。这个非凡的规定只实用于以下六种状况: I 能够放在 V (5) 和 X (10) 的右边,来示意 4 和 9。X 能够放在 L (50) 和 C (100) 的右边,来示意 40 和 90。 C 能够放在 D (500) 和 M (1000) 的右边,来示意 400 和 900。给定一个罗马数字,将其转换成整数。 ...

February 3, 2022 · 2 min · jiezi

关于golang:bgo-具备扩展性的-go-程序构建工具

bgo v0.3.0+前言咱们曾经在 bgo: 让构建 go 程序更容易 中介绍了 bgo 的根本能力。 通过几天的迭代,初步感觉到比较稳定了,因而发了 0.3.0 版本,作为是春节前的划断。 新版本有了节后嘛,得益于 cmdr 原有的 Aliases 性能的降级(元旦时遇到很多意外,都是忙乱惹的祸),bgo 向着不仅只是个 main 包批量构建器迈出了一小步: 咱们通过 Aliases 的形式提供了预建的 check-code-quanlities 性能。 这是 v0.3.1+ 之后提供的新性能。 check-code-qualities 性能这个性能是须要第三方工具的。以后须要 golint 和 gocyclo 在场,此外也须要 gofmt 工具。前两者须要提前装置: go install golang.org/x/lint/golintgo install github.com/fzipp/gocyclo当上述工具无效时,bgo 能够代为行使上述工具提供的质量检查性能: bgo check-code-quanlitiesbgo chk# Orbgo chk ./...这个命令顺次执行 gofmt, golint 以及 gocyclo 工具,对你的以后文件夹以及上级进行代码品质检测。 你能够附带参数如 ./... 或者其它指定的文件夹偏移。 Homebrewbrew 版本预建了装置脚本,你须要更新 hedzr/brew Tap 而后 reinstall bgo。 因为 brew 通过 update 命令来更新它本人以及所有的taps,因而其效率可能太低下。我感觉,一个变通的办法是: brew untap hedzr/brewbrew tap hedzr/brewbrew 当初会装置预置配置文件到 /usr/local/etc/bgo/。 ...

February 2, 2022 · 5 min · jiezi

关于golang:golangleetcode初级打乱数组最小栈

第一题 打乱数组题目信息 解题思路 代码package mainimport "math/rand"//leetcode submit region begin(Prohibit modification and deletion)type Solution struct { nums,original []int}func Constructor(nums []int) Solution { return Solution{nums,append([]int(nil),nums...)}}func (this *Solution) Reset() []int { copy(this.nums,this.original) return this.nums}func (this *Solution) Shuffle() []int { n:=len(this.nums) for i:=range this.nums{ j:=i+rand.Intn(n-i) this.nums[i], this.nums[j] = this.nums[j], this.nums[i] } return this.nums}/** * Your Solution object will be instantiated and called as such: * obj := Constructor(nums); * param_1 := obj.Reset(); * param_2 := obj.Shuffle(); *///leetcode submit region end(Prohibit modification and deletion)第二题题目信息 ...

February 1, 2022 · 1 min · jiezi

关于golang:第七期深信服go实习一面二面HR面

一面面试时长:1h自我介绍channel知识点协程goroutinemysql 的两种存储引擎InnoDB索引redis应用单线程还是多线程?有多少个库?redis长久化有哪些?各自劣势?谁更罕用?Python 一行代码去重讲一下set的原理,Java 的HashMap和 go 的map底层原理GMP模型go 的GC(标记清理 -> 三色标记发 -> 混合写屏障)RabbitMQ的音讯模型都有哪些?RabbitMQ都有哪些参数docker的一些根本命令(删除、进入容器等等)docker volume讲一下微服务有几个雷同的服务 A、B、C,挂了一个 A,REST API 怎么晓得 A 挂了并调用 B?go 中用 for 遍历屡次执行 goroutine会存在什么问题?怎么改良?如果要在每个goroutine中都获取返回值(捕捉参数),有哪些计划?(全局参数、channel,闭包)gRPC用的什么协定?TCP三次握手?四次挥手?FIN-WAIT-2是什么时候的?RPC有哪几种?这里还问了一个流式 RPC怎么巴拉巴拉什么解决之类的,我想不起来了问的具体是啥了,只记得过后我就蚌埠住了。分布式 ID 讲一下(九种计划 + 具体讲了号段、雪花算法的原理)ES理解多少(只会倒排索引、高亮)MongoDB讲一下?与MySQL的区别?为什么快?反诘面试体验:面试官真的好好哇~ 有什么想不起来的他会疏导我想起来 二面面试时长:45 min日常套路自我介绍怎么学习的?学习过程中遇到什么问题?怎么解决?具体是什么问题?有没有遇到过一些 BUG,而后解决完之后情绪感到十分难受的?具体是什么 BUG?你都是怎么写笔记的?(屏幕共享给面试官看我的笔记)看过什么书?是轻易翻翻还是看完了?(说了雨痕大佬的《Go语言学习笔记》和郑兆雄的《Go Web编程》,《Go语言学习笔记》在学校图书室我都借了三次看了三遍每次都有收益)go 手写二分查找还有就是一些巴拉巴拉的问题,反正都是一些集体状况学习状况之类的?想不太起来了?面试体验:面试官也是十分棒!点赞 HR面刚面试完二面没多久旧收到了 HR 面,电话面的有没有其它公司的 offer,我说有安全科技的实习 offer,是Java的,不太想去。(安全科技这公司我挺喜爱的,然而我投的上海只有北京了,也就是因为这样我才没第一工夫去)就和别的公司 HR 面差不多这里就不细说了秋招没找到,实习不能落下啊,这次深服气实习的面试是我从Java迈向Go的第一步,加油啊~心愿你肯定可能找到工作的,肯定会拿到offer的。

January 31, 2022 · 1 min · jiezi

关于golang:Go-Quiz-Google工程师的Go语言面试题

面试题Google工程师和Go语言布道者Valentin Deleplace会不定期分享一些Go语言的趣味题目。 我选取了最近的几道题目,给大家春节加加餐。 题目1:// quiz0.gopackage mainimport "fmt"func main() s := []string{"a", "b", "c"} copy(s[1:], s) fmt.Println(s)}A: [a a a]B: [a a b]C: [a a b c]D: [b c c]E: panic这道题次要考查Go语言里对切片slice应用copy函数的注意事项。 题目2:// quiz1.gopackage mainimport "fmt"func main() { a := make([]int, 20) b := a[18:] b = append(b, 2022) fmt.Println(len(b), cap(b))}A: 1 2B: 3 4C: 3 33D: 3 40这道题次要考查以下Go语言里对切片slice应用冒号:截取操作的底层机制以及slice的扩容原理。 题目3:// quiz2.gopackage mainimport "fmt"func main() { c := make(chan int, 1) c <- 1 close(c) close(c) fmt.Println("OK")}A: 死锁B: panicC: 打印"OK"D: 编译报错这道题次要考查以下Go语言里管道channel的注意事项。 ...

January 31, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode初级算法数学3的幂

题目:给定一个整数,写一个函数来判断它是否是 3 的幂次方。如果是,返回 true ;否则,返回 false 。整数 n 是 3 的幂次方需满足:存在整数 x 使得 n == 3x 链接: 力扣Leetcode—高级算法—数学—3的幂. 示例1 : 输出:n = 27输入:true示例2 : 输出:n = 0输入:false示例3 : 输出:n = 9输入:true示例4 : 输出:n = 45输入:false标签:递归、数学 思路:暴力求,一直判断n是否为2的倍数 次要Go代码如下: package mainimport ( "fmt")func isPowerOfThree(n int) bool { if n == 0 { return false } // 3 的 0 次方 if n == 1 { return true } for n != 1 { pop := n % 3 if pop != 0 { return false } n /= 3 } return true}func main() { var n int fmt.Scanf("%d", &n) fmt.Println(isPowerOfThree(n))}提交截图: ...

January 30, 2022 · 1 min · jiezi

关于golang:第六期技术中台golang开发实习生-滴滴

先说一下集体的总体状况,西电大三计科,没有实习和太多实践经验(只有本人写的博客什么的),数据结构和算法还行,在滴滴后面过很屡次字节,三次三面挂,好将来golang过了,还有许多中小厂就忘了,也没过。 总共兴许靠近二十次面试经验?滴滴的面试体验在我的个人经历里算是十分不错的,就是预先告诉太慢,还是我本人去问的二面.... 二面都是三天前的事件了,所以可能忘了很多问题,不过还是给大家一个参考吧 一面数据库索引(答了聚簇索引和非聚簇索引)非聚簇索引是如何查问的隔离级别RR是如何实现的(INNODB MVVC)在RR级别下可能读到事务ID靠后未提交的批改吗(不会,提醒说是锁,最初通知我加写锁,倡议我本人去试一试)网络UDP,TCPTCP差错控制、流量管制,拥塞管制HTTP(没答出3.0是啥)RESTfulgo切片和数组切片的问题go的通信实现channel的底层map的实现哈希过程是什么样子的桶的减少(这个具体还挺简单的)map线程平安吗?sync.mapgc过程算法反向输入层序遍历(简略) 反诘: 什么部门?二面网络get,post区别,post就不能在URL上附加参数吗(能够,http只是标准,服务端会解析你爱怎么样都行)三次握手如果改成发序列号x,回序列号x+1,再发x+2能够吗?(序列号预测攻打)数据库索引给了理论问题是并发问题(忘了是啥)如果有很多很多数据,分页显示,如何去做联结索引分布式环境如何加锁(不会)gosync.map实现map哈希过程(讲错了一点点,忘了可能插入雷同键不同值)锁的底层实现是什么(不会,给了集体的猜想) 聊天半小时: 你集体常写代码吗?你最次要的代码标准教训是什么?万一公司有很多不合理的标准怎么办?你想学到什么?不合乎你的预期怎么办?实习多久算法二叉树和为n的从上向下门路(简略) 反诘: 据说go有什么什么的缺点,你怎么看base地点能选杭州吗(只有北京,惋惜了,还是更想杭州离家近)追加一个问题,多线程解决问题你感觉开多少个线程(凋谢问题,情景本人思考)

January 30, 2022 · 1 min · jiezi

关于golang:Golang-实现-RabbitMQ-的死信队列

读本文之前,你应该曾经理解 RabbitMQ 的一些概念,如队列、交换机之类。死信概念艰深来讲,无奈被失常生产的音讯,咱们能够称之为死信。咱们将其放入死信队列,独自解决这部分“异样”音讯。 当音讯合乎以下的一个条件时,将会称为死信。 音讯被回绝,不从新放回队列(应用 basic.reject / basic.nack 办法回绝音讯,并且这两个办法的参数 requeue = false)音讯TTL过期队列达到最大长度利用利用场景:当消费者无奈失常生产音讯、音讯产生异样时,为了保证数据不失落,将异样的音讯置为死信,放入死信队列。在死信队列中的音讯,将启动独自的生产程序非凡解决。 架构图: 上面跟着架构图来实现代码。 生产者一个生产者一般来说只须要做两件事,一是创立链接,二是发送音讯。 RabbitMQ 中波及的队列、交换机、routing-key,这些都须要在代码中实现创立。这些操作既能够由生产者创立,也能够由消费者创立。对于谁来创立的探讨,见RabbitMq:谁来创立队列和交换机?此文。 本文中队列、交换机、routing-key 放到生产者一方来实现。所以生产者一共须要做这几件事。 创立连贯设置队列(队列、交换机、绑定)设置死信队列(队列、交换机、绑定)公布音讯创立连贯利用streadway/amqp包,与RabbitMQ 建设连贯。 func main() { mq := util.NewRabbitMQ() defer mq.Close() mqCh := mq.Channel ……}……// util.NewRabbitMQ()func NewRabbitMQ() *RabbitMQ { conn, err := amqp.Dial(constant.MqUrl) FailOnError(err, "Failed to connect to RabbitMQ") ch, err := conn.Channel() FailOnError(err, "Failed to open a channel") return &RabbitMQ{ Conn: conn, Channel: ch, }}设置队列(队列、交换机、绑定)外围操作就是设置队列阶段。 申明一般队列,并指定死信交换机、指定死信routing-key。后续死信队列创立后会与死信交换机、指定死信routing-key进行绑定。 var err error_, err = mqCh.QueueDeclare(constant.NormalQueue, true, false, false, false, amqp.Table{ "x-message-ttl": 5000, // 音讯过期工夫,毫秒 "x-dead-letter-exchange": constant.DeadExchange, // 指定死信交换机 "x-dead-letter-routing-key": constant.DeadRoutingKey, // 指定死信routing-key})util.FailOnError(err, "创立normal队列失败")申明交换机 ...

January 30, 2022 · 3 min · jiezi

关于golang:bgo-让构建-go-程序更容易

bgo一句话理解:bgo 管 exe 不论 lib前言前言之前: 这次的前言很长,能够间接跳过。 bgo 是一个构建辅助工具,它和已知的那些为 go 应用程序构建服务的工具没有多大的不同,都能反对在你的工作环境中穿插编译构建出 go 应用程序的执行文件。<!--MORE--> 只管这个能力原本是 go build 自带所有,但这样外包装一次后的辅助性的构建工具能够让你节俭大量的精力,无论是那些难以记忆的 go build 命令行参数也好,还是那些咱们不得不用到的前筹备,后处理步骤,例如 go generate,复制到某个公共地点,等等。 所以这就是 bgo 这样的工具的用处,省力。 缘起当然,为什么我要开发又一个辅助工具呢? 起因也不简单,有这么几个: 我当初经常在一个大目录中弄一大堆小我的项目,兴许只是试验一下某个性能,做某件事情,兴许是因为我须要列举一大堆 examples 给用户睇,总之很多就是了。但一个小的周期里,我通常聚焦在其中的某一个或者某两三个,为此,切换目录,构建就很疲乏了。Goland 倒是很贴心能让我省去这些命令行环境里的工作,但它的运行后果窗口不能反对全功能的键盘交互,所以有的行为我就只能开出一个终端来跑。当然还有很多别的是 Goland 肯定做不了的,就不列举了,总之这是一个具体的问题。对此,为什么不 vscode 呢?你用过吗?你要晓得 vscode 跑 goapp 只有调试跑某一个主程序的能力,想要不调试,或者想多个 apps,须要去它的嵌入终端里敲命令行的。另外,如果你不在 go.mod 那里关上工作区的话,vscode 会有很多问题——换句话说,vscode 顶多反对单个 go.mod 代表的模块。 另一个起因,是作为较为正式的公布,我可能频繁须要用到 -X 或者 go generate。对此,我本来有一个简单的 Makefile 能够主动解决这些问题。不过他们对于我在大规模我的项目中也不怎么好用,因为我可能会有很多不同的目录对应不同的子模块。 再一个起因是构建时的程序问题,我有时候须要有序地做一系列构建,而有时候我须要很快地构建单个 target 在 exeutable 模式下运行和检视后果。 当然还有其它起因,不过拉拉杂杂的就不说了。 你能够留神到次要的理由还是在于我在保护大型项目构造。为什么不切分成很多很多的 repos 呢?这又波及到另一个问题:go modules 不反对多个嵌套的 go.mod。也就是说,如果你的下级目录有 go.mod,那么上级就不能够再有,这是个很简单的状况,但终归对于你来说,这个限度是很硬的,所以这样的构造行不通: /complex-system go.mod /api /v1 go.mod /common go.mod /account go.mod /backends /order go.mod /ticket go.mod这里只列举了局部目录构造,而且仅仅是个示意。 ...

January 30, 2022 · 8 min · jiezi

关于golang:---新鲜出炉go-版本的-pipeline-发布啦你还在愁-go-没有好用的中间件吗

Goal-web/pipelinegoal-web/pipeline 这是一个管道库,实现了 和 laravel 一样的管道性能,如果你很相熟 laravel 的管道或者中间件,那你肯定对这个库很有亲切感。 装置 - installgo get github.com/goal-web/pipeline应用 - usage得益于 goal 弱小的容器,你能够在管道(pipe)和目的地(destination)任意注入容器中存在的实例 对管道不相熟的同学,能够把 pipe 了解为中间件,destination 就是控制器办法package testsimport ( "fmt" "github.com/goal-web/container" "github.com/goal-web/contracts" "github.com/goal-web/pipeline" "github.com/pkg/errors" "testing")type User struct { Id int Name string}func TestPipeline(t *testing.T) { pipe := pipeline.New(container.New()) pipe.Send(User{Id: 1, Name: "goal"}). Through( func(user User, next pipeline.Pipe) interface{} { fmt.Println("中间件1-start") result := next(user) fmt.Println("中间件1-end") return result }, func(user User, next pipeline.Pipe) interface{} { fmt.Println("中间件2-start") result := next(user) fmt.Println("中间件2-end") return result }, ). Then(func(user User) { fmt.Println("then", user) })}// TestPipelineException 测试异常情况func TestPipelineException(t *testing.T) { defer func() { recover() }() pipe := pipeline.New(container.New()) pipe.Send(User{Id: 1, Name: "goal"}). Through( func(user User, next pipeline.Pipe) interface{} { fmt.Println("中间件1-start") result := next(user) fmt.Println("中间件1-end", result) return result }, func(user User, next pipeline.Pipe) interface{} { fmt.Println("中间件2-start") result := next(user) fmt.Println("中间件2-end", result) return result }, ). Then(func(user User) { panic(errors.New("报个错")) })}// TestStaticPipeline 测试调用magical函数func TestStaticPipeline(t *testing.T) { // 利用启动时就筹备好的中间件和控制器函数,在大量并发时用 StaticPipeline 能够进步性能 middlewares := []contracts.MagicalFunc{ container.NewMagicalFunc(func(user User, next pipeline.Pipe) interface{} { fmt.Println("中间件1-start") result := next(user) fmt.Println("中间件1-end", result) return result }), container.NewMagicalFunc(func(user User, next pipeline.Pipe) interface{} { fmt.Println("中间件2-start") result := next(user) fmt.Println("中间件2-end", result) return result }), } controller := container.NewMagicalFunc(func(user User) int { fmt.Println("then", user) return user.Id }) pipe := pipeline.Static(container.New()) result := pipe.SendStatic(User{Id: 1, Name: "goal"}). ThroughStatic(middlewares...). ThenStatic(controller) fmt.Println("穿梭后果", result) /** 中间件1-start 中间件2-start then {1 goal} 中间件2-end [1] 中间件1-end [1] 穿梭后果 [1] */}在 goal 之外的框架应用 - use in frameworks other than goal这个库并不会限度你在哪个框架应用它,所以你能够在任意 go 环境应用这个管道库 ...

January 29, 2022 · 2 min · jiezi

关于golang:第五期游服务器一二三面-秋招-米哈游

一面下午2点,35分钟 golang内存模型golang并发模型golang gc原理 过程channel用处,原理redis数据结构,底层实现跳跃表查问插入复杂度过程,线程,协程kill原理除了kill -9还晓得什么信号父过程调用fork后,不调用waitpid会怎怎么僵尸过程线程间同步形式锁有哪些类型口述topk建堆过程 总体来说1面很惯例,感觉没啥难度,很快就约2面了 2面手撕。相似leetcode8。不过输出不是一个而是很多逗号宰割的字符串,还要本人思考各种异常情况。设计一个排行榜的数据结构,说思路3面手撕,相似ip前缀树。我间接傻了,以前没写过前缀树。sql建表。也很蛊惑,我说我曾经很久没写过建表的sql了,都是图形化工具建表的。而后硬着头皮写实习我的项目玩游戏吗,玩咱们公司的游戏嘛反诘。我问他游戏我的项目是否存在客户端相比服务端更加外围的景象,还有游戏后端相比web后端的不同点和难点。大佬真的很nice,尽管曾经判断要挂我了,还是很认真的给我解说了大略10分钟三面完半小时收到感谢信

January 29, 2022 · 1 min · jiezi

关于golang:golangleetcode初级二叉树的层序遍历将有序数组转化为二叉搜索树

第一题题目信息 解题思路层序遍历二叉树,显然广搜更为高效广搜的流程如图因而咱们须要领有一个队列记录搜寻的节点状况 我很道歉素朴的思路过于简单我并不能很好的把他展现进去让咱们学习优化一下解题思路 代码func levelOrder(root *TreeNode) [][]int { ret := [][]int{} if root == nil { return ret } q := []*TreeNode{root} for i := 0; len(q) > 0; i++ { ret = append(ret, []int{}) p := []*TreeNode{} for j := 0; j < len(q); j++ { node := q[j] ret[i] = append(ret[i], node.Val) if node.Left != nil { p = append(p, node.Left) } if node.Right != nil { p = append(p, node.Right) } } q = p } return ret}作者:LeetCode-Solution链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/solution/er-cha-shu-de-ceng-xu-bian-li-by-leetcode-solution/起源:力扣(LeetCode)著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。复杂度剖析工夫复杂度:每个点进队出队各一次,故渐进工夫复杂度为 O(n)。空间复杂度:队列中元素的个数不超过 n 个,故渐进空间复杂度为 O(n)。 ...

January 28, 2022 · 1 min · jiezi

关于golang:第四期字节跳动一面-golang

欢送退出GOLANG ROADMAP,一个年老的Go开发者社区。本篇面经中的面试题已收录到社区企业题库版块。一、golang1、什么是内存逃逸,在什么状况下产生,原理是什么?2、函数传指针和传值有什么区别?3、new和make有什么区别?4、理解golang的GC吗?5、理解GMP模型吗,介绍一下?6、channel理解吗,channel的工作原理是什么?二、计算机网络1、TCP三次握手、四次挥手,timewait,closewait状态2、理解socket编程吗,其中accept办法是什么3、get、post办法有什么区别三、操作系统1、过程和线程的区别是什么四、数据库1、mysql索引理解,原理是什么?2、hashmap原理3、redis有哪些数据类型五、算法1、爬梯子2、分苹果问题不止这些,大略记得这么些

January 28, 2022 · 1 min · jiezi

关于golang:第三期分享一篇B站后端面经-哔哩哔哩

欢送退出GOLANG ROADMAP,一个年老的Go开发者社区。本篇面经中的面试题已收录到社区企业题库版块。一面我的项目介绍go的gmpcpu特地高如何定位mysql引擎复合索引失效问题sql执行慢的起因?如何看是什么问题?rediszset实现一致性hashrpc理解吗?tcp,udp区别操作系统:线程与过程,死锁条件预防等?不要求写银行家算法,提下就行点到为止http的一些状态码含意?起初聊到服务器推送二面你怎么设计索引,不是优化是设计给你场景,你来抉择tcp还是udp我的项目中索引优化经验还有一些我的项目单干等非技术问题,就不提了三面我的项目经验加聊天 总结b站的面试感触很好,面试官都很nice,十分棒

January 27, 2022 · 1 min · jiezi

关于golang:第一期2022秋招区块链开发工程师技术面面经-欧科云链

欧科云链(OKEx) 区块链工程院(面后感触:OKEx问的区块链的底层不多,大多是Golang开发的底层) 一面过程、线程、Goroutine的比拟GMP模型Golang Map底层如何实现Map的有序查找(利用一个辅助slice)sync包理解吗Mutex与RWMutex怎么实现Map的并发平安(sync.Map,底层实际上用了一个Map缓存)Golang的channel底层defer函数的应用场景(提早Close、recover panic)简介所知的区块链的共识算法(PoW,PoS,DPoS,PBFT,Raft)PBFT与Raft的区别(拜占庭容错与解体容错)场景题:实现一个接口C在指定工夫内最大次数并发调用接口A与接口BMySQL的B+树简略问了下Solidity、我的项目反诘部门业务二面简略聊了下我的项目与毕设PBFT算法底层(外围三阶段,preprepare、prepare、commit)Raft算法底层(领导者选举、日志复制)Golang GC(三色标记法,插入屏障、删除屏障、混合写屏障)Map能够用数组作为Key吗(数组能够,切片不能够)Channel的阻塞和非阻塞(顺带问了select用法)介绍除了单例与工厂模式外的设计模式(消费者模式)Redis为什么快(内存数据库,单线程IO多路复用)介绍Bloom filter特点区块链里的MT与MPT以太坊智能合约如何执行,介绍EVM底层算法:手撕快排聊区块链行业反诘本篇面经中波及的面试题已收录进GOLANG ROADMAP企业题库(搜寻关注wx-gzh:GOLANG ROADMAP),可查看面试题解析和参加探讨。

January 27, 2022 · 1 min · jiezi

关于golang:golangleetcode初级验证二叉搜索树对称二叉树

第一题 验证二叉搜寻树题目信息 解题思路所有左子树和右子树本身必须也是二叉搜寻树。 显然这能够用递归的形式解决咱们只需验证根节点的值大于所有左子树的值,小于所有右子树的值即可即 将根节点别离与左子树的最大节点,根节点与右子树的最小节点比拟 代码如下 func isValidBST(root *TreeNode) bool { if root.Left==nil && root.Right==nil{ return true } if root.Val<max(root.Left) { return false }else if root.Val>min(root){ return false }else{ return isValidBST(root.Right)&&isValidBST(root.Left) }}func max(root *TreeNode) int { }func min(root *TreeNode) int { }max与min函数未实现因为咱们并不能保障子树是规范的二叉搜寻树想要在子树中找到最大与最小的值并不是件容易的事遍历搜寻树显然更简单 故咱们须要扭转递归的函数 同时思考遍历子树的时候也给了咱们启发树的三种遍历程序 先序遍历中序遍历后续遍历别离是指遍历的时候树的根节点排在左右子树的后面,两头,前面而按中序遍历的程序,二叉搜寻树失去的值的序列为升序序列这就失去了更为简洁的解法 递归代码func isValidBST(root *TreeNode) bool { return helper(root, math.MinInt64, math.MaxInt64)}func helper(root *TreeNode, lower, upper int) bool { if root == nil { return true } if root.Val <= lower || root.Val >= upper { return false } return helper(root.Left, lower, root.Val) && helper(root.Right, root.Val, upper)}作者:LeetCode-Solution链接:https://leetcode-cn.com/problems/validate-binary-search-tree/solution/yan-zheng-er-cha-sou-suo-shu-by-leetcode-solution/起源:力扣(LeetCode)著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。复杂度剖析工夫复杂度 : O(n),其中 n 为二叉树的节点个数。在递归调用的时候二叉树的每个节点最多被拜访一次,因而工夫复杂度为 O(n)。 ...

January 27, 2022 · 2 min · jiezi

关于golang:Go118-新特性新增好用的-Cut-方法

大家好,我是煎鱼。 在各种写业务代码的时候,大家会经常要解决字符串的内容。常见的像是用邮箱登陆账号,如果是:eddycjy@gmail.com,那就得依据 @ 来切割,别离取出前和后,来辨认用户名和邮箱地址。 这种需要,在 Go 里写起来不便吗?明天就由煎鱼带大家理解。 背景反复代码独一无二,Ainar Garipov 在许多我的项目中遇到了后面咱们所提的切割需要。 例如: idx = strings.Index(username, "@")if idx != -1 { name = username[:idx]} else { name = username} 又或是: idx = strings.LastIndex(address, "@")if idx != -1 { host = address[idx+1:]} else { host = address}常常要重复写一些繁琐的代码,提案提出者示意不欢快。 新提案施行内容倡议新增 Cut 办法到 strings 规范库: func Cut(s, sep string) (before, after string, found bool) { if i := Index(s, sep); i >= 0 { return s[:i], s[i+len(sep):], true } return s, "", false}同步也要在 bytes 规范库: ...

January 26, 2022 · 1 min · jiezi

关于golang:golangleetcode初级环形链表

第一题 环形链表题目信息 解题思路首先还是思考最暴力的解法由示例1可知,有两个节点同时指向第二个节点,从而在单链表的根底上造成了闭环。即pos0和pos3领有着雷同的next指针由示例2可知,对于指向头节点的状况,有必要退出哑节点辅助比拟pos1的next指针所以咱们只有比对一遍所有节点的next指针,找到指向雷同的节点即可然而很显著,该思路的复杂度为O(n^2),个别状况下没有写进去的必要。 工夫复杂度高的起因次要是因为比照的过程过于麻烦,有太多重复性的操作。对此再退出哈希表的概念优化一下,应用哈希表来存储所有曾经拜访过的节点 代码func hasCycle(head *ListNode) bool { seen := map[*ListNode]struct{}{} for head != nil { if _, ok := seen[head]; ok { return true } seen[head] = struct{}{} head = head.Next } return false}作者:LeetCode-Solution链接:https://leetcode-cn.com/problems/linked-list-cycle/solution/huan-xing-lian-biao-by-leetcode-solution/起源:力扣(LeetCode)著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。对于代码的map定义 复杂度剖析工夫复杂度:O(N),其中 N 是链表中的节点数。最坏状况下咱们须要遍历每个节点一次。 空间复杂度:O(N),其中 N 是链表中的节点数。次要为哈希表的开销,最坏状况下咱们须要将每个节点插入到哈希表中一次。 另一种思路快慢指针,永远滴神 func hasCycle(head *ListNode) bool { if head == nil || head.Next == nil { return false } slow, fast := head, head.Next for fast != slow { if fast == nil || fast.Next == nil { return false } slow = slow.Next fast = fast.Next.Next } return true}作者:LeetCode-Solution链接:https://leetcode-cn.com/problems/linked-list-cycle/solution/huan-xing-lian-biao-by-leetcode-solution/起源:力扣(LeetCode)著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。工夫复杂度:O(N),其中 N 是链表中的节点数。 ...

January 26, 2022 · 1 min · jiezi

关于golang:golangleetcode初级合并两个有序链表回文链表

第一题 合并两个有序链表题目信息将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 解题思路这是数据结构中对于链表一道很经典的例题因为两个链表都为升序链表,比拟两个链表的头部元素,并将小的数字退出到返回链表,遍历完一个链表后,再将另一链表的残余元素退出即可。 代码func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { head := &ListNode{} cur := head for l1 != nil || l2 != nil { if l1 != nil && l2 != nil { if l1.Val < l2.Val { cur.Next = l1 l1 = l1.Next } else { cur.Next = l2 l2 = l2.Next } cur = cur.Next } else if l1 != nil { cur.Next = l1 break } else { cur.Next = l2 break } } return head.Next}复杂度剖析工夫复杂度:O(n+m),其中 n 和 m 别离为两个链表的长度。空间复杂度:O(1)。咱们只须要常数的空间寄存head和cur两个指针 ...

January 25, 2022 · 2 min · jiezi

关于golang:golanggo语言中的静态和动态

动态和动静的概念动态动态绑定是指在程序运行前就曾经晓得办法是属于那个类的,在编译的时候就能够连贯到类的中,定位到这个办法。. 动态绑定产生于数据结构和数据结构间,程序执行之前。. 动态绑定产生于编译期,因而不能利用任何运行期的信息。. 它针对函数调用与函数的主体,或变量与内存中的区块。. 动静动静绑定(前期绑定)是指在程序运行过程中,依据具体的实例对象能力具体确定是哪个办法。. 动静绑定则针对运行期产生的拜访申请,只用到运行期的可用信息。. 在面向对象的代码中,动静绑定意味着决定哪个办法被调用或哪个属性被拜访,将基于这个类自身而不基于拜访范畴。 动态和动静的例子 动态类型语言和动静类型语言对于动态语言和动静语言Go语言是一门动态编译型语言,是一门强类型语言。但在go语言中也提供了相似于动静语言的性能。 和其它语言相比,Go语言是惟一联合了接口值,动态类型查看(是否该类型实现了某个接口),运行时动静转换的语言,并且不须要显式地申明类型是否满足某个接口。该个性容许咱们在不扭转已有的代码的状况下定义和应用新接口。接管一个(或多个)接口类型作为参数的函数,能够被实现了该接口的类型实例调用。实现了某个接口的类型能够被传给任何以此接口为参数的函数。相似于 Python 和 Ruby 这类动静语言中的动静类型(duck typing);这意味着对象能够依据提供的办法被解决(例如,作为参数传递给函数),而疏忽它们的理论类型:它们能做什么比它们是什么更重要。 像 Python,Ruby 这类语言,动静类型是提早绑定的(在运行时进行):办法只是用参数和变量简略地调用,而后在运行时才解析(它们很可能有像 responds_to 这样的办法来查看对象是否能够响应某个办法,然而这也意味着更大的编码量和更多的测试工作)。 Go语言的实现与此相反,通常须要编译器动态查看的反对:当变量被赋值给一个接口类型的变量时,编译器会查看其是否实现了该接口的所有函数。如果办法调用作用于像 interface{} 这样的“泛型”上,能够通过类型断言来查看变量是否实现了相应接口。 go语言中的动态函数和动静函数动静函数go中的接口类型实现了动静的成果: Go语言试图让程序员能在平安和灵便的编程之间获得一个均衡。它在提供严格的类型查看的同时,通过接口类型实现了对鸭子类型的反对,使得平安动静的编程变得绝对容易。并且在go1.17中引入了泛型的概念动态函数因为go语言属于动态类型语言,每个变量在定义时都会被赋予固定的值。go中也没有类的概念,每个办法与对应的变量绑定所以在go中个别的函数和办法都是属于动态的函数 参考https://www.cnblogs.com/wongb...http://c.biancheng.net/view/8...http://c.biancheng.net/view/5...

January 25, 2022 · 1 min · jiezi

关于golang:Golang可视化工具gocallvis

一、go-callvis介绍Go-callvis是一种golang代码可视化工具,用于帮忙应用交互式视图可视化 Go 程序的调用图。此工具的目标是为开发人员提供一个可视化的 Go 程序概览,应用来自调用图的数据及其与包和类型的关系。这在大型项目中特地有用,因为这些我的项目的代码复杂度要高得多,或者只是简略地试图了解其他人的代码。 二、运行依赖Go 1.13+Graphviz (optional, required only with -graphviz flag)三、装置go get -u github.com/ofabry/go-callvis或者是 git clone https://github.com/ofabry/go-callvis.gitcd go-callvismake install装置好的 go-callvis 可执行文件会在$GOPATH/bin目录下 四、应用办法运行go-callvis -h能够列出所有受反对的选项,如下Usage of go-callvis: -debug Enable verbose log. 输入具体日志 -file string output filename - omit to use server mode 以文件旧式输入后果,并将疏忽server交互模式 -cacheDir string Enable caching to avoid unnecessary re-rendering. 启用缓存以防止不必要的从新渲染。 -focus string Focus specific package using name or import path. (default "main") 关注特定的程序包,默认为“main”包 -format string output file format [svg | png | jpg | ...] (default "svg") 输入文件的格局,[svg | png | jpg | ...],默认为svg -graphviz Use Graphviz's dot program to render images. 应用Graphviz渲染图像 -group string Grouping functions by packages and/or types [pkg, type] (separated by comma) (default "pkg") 分组性能,依据包 与/或 类型分组 [pkg, type] (用逗号离开) (默认 "pkg"),例如 -group pkg,type -http string HTTP service address. (default ":7878") HTTP 服务地址 (默认 ":7878") -ignore string Ignore package paths containing given prefixes (separated by comma) 疏忽蕴含给定前缀的包门路(用逗号离开) -include string Include package paths with given prefixes (separated by comma) 蕴含具备给定前缀的包门路 (用逗号离开) -limit string Limit package paths to given prefixes (separated by comma) 将包门路限度为给定的前缀(以逗号分隔) -minlen uint Minimum edge length (for wider output). (default 2) 最小边长(用于更宽的输入)。 (默认2) -nodesep float Minimum space between two adjacent nodes in the same rank (for taller output). (default 0.35) 同一等级中两个相邻节点之间的最小间距(用于更高的输入)。 (默认0.35) -nointer Omit calls to unexported functions. 疏忽对未导出函数的调用。(疏忽首字母小写的函数) -nostd Omit calls to/from packages in standard library. 疏忽规范库的调用 -skipbrowser Skip opening browser. 跳过关上浏览器 -tags build tags a list of build tags to consider satisfied during the build. For more information about build tags, see the description of build constraints in the documentation for the go/build package 在构建期间更适宜的构建标记 无关构建标记的更多信息,请参阅go / build软件包的文档中的构建束缚阐明。 -tests Include test code. 蕴含测试代码 -version Show version and exit. 显示版本号命令行格局:go-callvis [可选参数] <包门路>默认状况下,输入的图在 http://localhost:7878/,可应用选项-http="ADDR:PORT"更改HTTP服务器地址。动态输入: ...

January 25, 2022 · 2 min · jiezi

关于golang:golang-defer详细讲解

Golang开发文档 https://www.topgoer.com/%E5%8... defer个性: 关键字 defer 用于注册提早调用。这些调用直到 return 前才被执。因而,能够用来做资源清理。多个defer语句,按先进后出的形式执行。defer语句中的变量,在defer申明时就决定了。defer用处: 敞开文件句柄锁资源开释数据库连贯开释依据开发文档形容,上面来做一一验证。 1.defer用于注册提早调用。 package mainimport "fmt"func main() { fmt.Println("测试defer start") defer func() { fmt.Println("defer func") }() fmt.Println("测试defer end")}执行后果为: 证实defer函数用来提早调用,在函数完结的时候被调用。函数完结包含:被调用办法失常return,或者达到办法体结尾,也或者蕴含defer函数的办法在执行panic的时候都会执行defer函数。 值得注意是,当蕴含defer函数的办法在执行panic操作的时候,会先执行defer函数,再执行panic办法,panic之后的语句是不可达的。上面我用实例来再次证实一下。 package mainimport "fmt"func main() { fmt.Println("测试defer start") defer func() { fmt.Println("defer func") }() fmt.Println("测试defer end") panic("panic 异样")}执行后果为: 由此看出,defer产生在panic执行之前,因而,能够在defer办法外面做资源清理,开释操作。 2.多个defer语句,按先进后出的形式执行。 package mainimport "fmt"func main() { deferFunc1()}func deferFunc1() { val := "1111" defer fmt.Println("val1",val) defer func() { fmt.Println("val2",val) }() defer fmt.Println("val3",val) defer func(val string) { fmt.Println("val4",val) }(val) defer fmt.Println("val5",val) fmt.Println("val",val)}执行后果为: ...

January 25, 2022 · 1 min · jiezi

关于golang:golang编译参数ldflags子路径不生效

golang 在编译时,通过退出- ldflags 的参数能够替换编译的二进制包中的文件内容。例如替换版本号,构建日期,Git commit等信息时很不便。 例如替换main包中的变量如下: package mainvar version="N/A"func main() { fmt.Println(version)}编译时加上参数:go build -a -ldflags "-X main.version=1.2" -o bin/demo main.go 运行测试如下: ~ ./bin/demo1.2然而测试到笼罩子包下的变量时,发现始终替换不胜利。 ~ mkdir pkg~ touch pkg/vars.go~ cat pkg.vars.gopackage pkgimport "fmt"var version="N/A"func Init() { fmt.Printf("pkg.version: %s\n",version)}在main函数中调用Init func main() { fmt.Println(version) pkg.Init()}编译测试: go build -a -ldflags "-X main.version=1.2 -X pkg/pkg.version=1.3" -o bin/demo main.go./bin/demo1.2pkg.version: N/A如上发现测试并不失效,网上有些说法是要绝对GOPATH上来写,要强制带上工程名,例如:demo/pkg/pkg.version,这种是能够失效的,然而如果工程门路不止一级,例如github.com/csi/demo,这样的全门路加上去也是不行的。 到底这个门路到底是什么,依据网上的材料检索,发现有一个工具能够间接列出编译的二进制文件中的变量门路: go tool nm ./bin/demo | grep version 162f6e0 D demo/pkg.version 162f870 D main.version 1404b10 R main.version.str通过这个工具,能够直观失去子包中的变量全门路到底是什么。如果是多级子目录的话,测试如下: ...

January 25, 2022 · 1 min · jiezi

关于golang:Go-Quiz-从Go面试题看channel在select场景下的注意事项

面试题这是Go Quiz系列中对于channel的第2篇,波及channel被close后的个性,以及在select和channel一起应用时的注意事项。 这道题目来源于Google的工程师Valentin Deleplace。 package mainimport "fmt"func main() { data := make(chan int) shutdown := make(chan int) close(shutdown) close(data) select { case <-shutdown: fmt.Print("CLOSED, ") case data <- 1: fmt.Print("HAS WRITTEN, ") default: fmt.Print("DEFAULT, ") }}A: 进入default分支,打印"DEFAULT, "B: 进入shutdown分支,打印"CLOSED, "C: 进入data分支,打印"HAS WRITTEN, "D: 程序会panicE: 程序可能panic,也可能打印"CLOSED, "这道题次要考查以下知识点: channel被敞开后,从channel接收数据和往channel发送数据会有什么后果?select的运行机制是怎么的?解析对于无缓冲区的channel,往channel发送数据和从channel接收数据都会阻塞。对于nil channel和有缓冲区的channel,收发数据的机制如下表所示: channelnil空的非空非满满了往channel发送数据阻塞发送胜利发送胜利阻塞从channel接收数据阻塞阻塞接管胜利接管胜利敞开channelpanic敞开胜利敞开胜利敞开胜利channel被敞开后: 往被敞开的channel发送数据会触发panic。从被敞开的channel接收数据,会先读完channel里的数据。如果数据读完了,持续从channel读数据会拿到channel里存储的元素类型的零值。 data, ok := <- c 对于下面的代码,如果channel c敞开了,持续从c里读数据,当c里还有数据时,data就是对应读到的值,ok的值是true。如果c的数据曾经读完了,那data就是零值,ok的值是false。 channel被敞开后,如果再次敞开,会引发panic。select的运行机制如下: 选取一个可执行不阻塞的case分支,如果多个case分支都不阻塞,会随机选一个case分支执行,和case分支在代码里写的程序没关系。如果所有case分支都阻塞,会进入default分支执行。如果没有default分支,那select会阻塞,直到有一个case分支不阻塞。依据以上规定,本文最开始的题目,在运行的时候 data和shutdown这2个channel都被敞开了。对于敞开的channel,从channel里接收数据,拿到的是channel的存储的元素类型的零值,因而case <-shutdown这个case分支不会阻塞。对于敞开的channel,向其发送数据会引发panic,因而case data <- 1这个case分支不会阻塞,会引发panic。因而这个select语句执行的时候,2个case分支都不会阻塞,都可能执行到。如果执行的是case <-shutdown这个case分支,会打印"CLOSED, "。如果执行的是case data <- 1这个case分支,会导致程序panic。因而本题的答案是E。 ...

January 24, 2022 · 1 min · jiezi

关于golang:为数据库组件铺路超好用的-go-集合collection库来了

Goal-web/collection这是一个神奇的仓库goal-web/collection 装置 - installgo get github.com/goal-web/collection应用package testsimport ( "errors" "fmt" "github.com/goal-web/collection" "github.com/goal-web/contracts" "github.com/shopspring/decimal" "github.com/stretchr/testify/assert" "testing")func TestNew(t *testing.T) { collect, err := collection.New(1) assert.Nil(t, collect) assert.Error(t, err, err) // 应用 MustNew 的时候,如果参数不是 array 或者 slice 的话,将会 panic collect, err = collection.New([]int{1}) assert.NotNil(t, collect) assert.Nil(t, err)}func TestArray(t *testing.T) { intCollection := collection.MustNew([]interface{}{ 1, 2, 3, true, "字符串", "true", }) fmt.Println(intCollection.ToFloat64Array()) assert.True(t, intCollection.Len() == 6) // 第二个参数是数据索引 intCollection.Map(func(data, index int) { fmt.Println(fmt.Sprintf("第 %d 个,值:%d", index, data)) }) // 第三个参数是所有数据汇合 intCollection.Map(func(data, index int, allData []interface{}) { if index == 0 { fmt.Println("allData", allData) } fmt.Println(fmt.Sprintf("第 %d 个,值:%d", index, data)) }) // 甚至能够间接转换成你想要的类型 intCollection.Map(func(data string, index int) { fmt.Println(fmt.Sprintf("第 %d 个,值:%s", index, data)) }) intCollection.Map(func(data bool, index int) { fmt.Println(fmt.Sprintf("第 %d 个,值:%v", index, data)) }) // 不返回任何值示意只遍历 intCollection.Map(func(data int) { fmt.Println("只遍历: ", data) }) fmt.Println(intCollection.ToIntArray()) // 返回一个值会生成一个新的 collection fmt.Println(intCollection.Map(func(data int) int { if data > 0 { return 1 } return 0 }).ToIntArray())}type User struct { id int Name string Money float64}func TestStructArray(t *testing.T) { users := collection.MustNew([]User{ {id: 1, Name: "qbhy"}, {id: 2, Name: "goal"}, }) users.Map(func(user User) { fmt.Printf("user: id:%d Name:%s \n", user.id, user.Name) }) // 应用 fields 接管的时候,未导出字段默认是 nil users.Map(func(user contracts.Fields) { fmt.Printf("user: id:%v Name:%s \n", user["id"], user["name"]) }) // 应用 map 批改数据后在用 where 筛选 assert.True(t, users.Map(func(user User) User { if user.id == 1 { user.Money = 100 } return user }).Where("money", 100).Len() == 1)}func TestFilterArray(t *testing.T) { users := collection.MustNew([]User{ {id: 1, Name: "qbhy", Money: 10000000}, {id: 2, Name: "goal", Money: 10}, }) fmt.Println("第一个数据", users.ToInterfaceArray()[0]) richUsers := users.Filter(func(user User) bool { return user.Money > 100 }) assert.True(t, richUsers.Len() == 1) fmt.Println(richUsers.ToInterfaceArray()) poorUsers := users.Skip(func(user User) bool { return user.Money > 100 }) assert.True(t, poorUsers.Len() == 1) fmt.Println(poorUsers.ToInterfaceArray()) qbhyUsers := users.Where("name", "qbhy") assert.True(t, qbhyUsers.Len() == 1) fmt.Println(qbhyUsers.ToInterfaceArray()) assert.True(t, users.WhereLte("money", 50).Len() == 1) assert.True(t, users.Where("money", "<=", 50).Len() == 1)}// TestAggregateArray 聚合函数测试func TestAggregateArray(t *testing.T) { users := collection.MustNew([]User{ {id: 1, Name: "qbhy", Money: 10000000000000000}, {id: 2, Name: "goal", Money: 10000000000000000}, {id: 3, Name: "collection", Money: 0.645624123}, }).(*collection.Collection) // SafeSum、SafeAvg、SafeMax、SafeMin 等办法须要 *collection.Collection 类型 fmt.Println("Sum", users.SafeSum("money")) fmt.Println("Avg", users.SafeAvg("money")) fmt.Println("Max", users.SafeMax("money")) fmt.Println("Min", users.SafeMin("money")) sum, _ := decimal.NewFromString("20000000000000000.645624123") avg, _ := decimal.NewFromString("6666666666666666.8818747076666667") max, _ := decimal.NewFromString("10000000000000000") min, _ := decimal.NewFromString("0.645624123") assert.True(t, users.SafeSum("money").Equal(sum)) assert.True(t, users.SafeAvg("money").Equal(avg)) assert.True(t, users.SafeMax("money").Equal(max)) assert.True(t, users.SafeMin("money").Equal(min)) users = collection.MustNew([]User{ {id: 1, Name: "qbhy", Money: 1}, {id: 2, Name: "goal", Money: 2}, {id: 3, Name: "collection", Money: 0}, }).(*collection.Collection) assert.True(t, users.Sum("money") == 3) assert.True(t, users.Avg("money") == 1) assert.True(t, users.Max("money") == 2) assert.True(t, users.Min("money") == 0) assert.True(t, users.Count() == 3)}// TestSortArray 测试排序功能func TestSortArray(t *testing.T) { users := collection.MustNew([]User{ {id: 1, Name: "qbhy", Money: 12}, {id: 2, Name: "goal", Money: 1}, {id: 2, Name: "goal", Money: 15}, {id: 2, Name: "goal99", Money: 99}, {id: 3, Name: "collection", Money: -5}, {id: 3, Name: "挪动", Money: 10086}, }) fmt.Println(users.ToInterfaceArray()) // 暂不反对转成 contracts.Fields usersOrderByMoneyDesc := users.Sort(func(user User, next User) bool { return user.Money > next.Money }) fmt.Println(usersOrderByMoneyDesc.ToInterfaceArray()) assert.True(t, usersOrderByMoneyDesc.ToInterfaceArray()[0].(User).Money == 10086) usersOrderByMoneyAsc := users.Sort(func(user User, next User) bool { return user.Money < next.Money }) fmt.Println(usersOrderByMoneyAsc.ToInterfaceArray()) assert.True(t, usersOrderByMoneyAsc.ToInterfaceArray()[0].(User).Money == -5) numbers := collection.MustNew([]interface{}{ 8, 0, 1, 2, 0.6, 4, 5, 6, -0.2, 7, 9, 3, "10086", }) sortedNumbers := numbers.Sort(func(i, j float64) bool { return i > j }).ToFloat64Array() fmt.Println(sortedNumbers) assert.True(t, sortedNumbers[0] == 10086)}// TestCombine 测试组合汇合性能func TestCombine(t *testing.T) { users := collection.MustNew([]User{ {id: 1, Name: "qbhy", Money: 12}, }) users = users.Push(User{id: 2, Name: "goal", Money: 1000}) //users = users.Prepend(User{id: 2, Name: "goal", Money: 1000}) // 插入到结尾 assert.True(t, users.Len() == 2) fmt.Println(users.ToInterfaceArray()) others := collection.MustNew([]User{ {id: 3, Name: "马云", Money: 100000000}, }) all := others.Merge(users).Sort(func(pre User, next User) bool { return pre.Money > next.Money }) assert.True(t, all.Len() == 3) fmt.Println(all.ToInterfaceArray()) fmt.Println(all.Only("money", "name").ToArrayFields()) assert.True(t, all.First("name") == "马云") // 最有钱还是马云 normalUsers := all.Where("money", ">", 100) assert.True(t, normalUsers.Len() == 2) // 两个普通人 assert.True(t, normalUsers.Last("name") == "goal") // 筛选不影响排序,跟马云比还差了点 assert.False(t, normalUsers.IsEmpty()) // 有普通人 assert.True(t, normalUsers.Where("money", "<", 0).IsEmpty()) // 普通人都没有负债 randomUsers := all.Random(2) // 随机获取两个数据 assert.True(t, randomUsers.Len() == 2) fmt.Println(randomUsers.ToInterfaceArray()) assert.True(t, all.Pull().(User).Name == "qbhy") // 从开端取走一个 assert.True(t, all.Len() == 2) // 判断取走后的长度 assert.True(t, all.Shift().(User).Name == "马云") // 从结尾取走一个 assert.True(t, all.Len() == 1) // 判断取走后的长度}func TestChunk(t *testing.T) { collect := collection.MustNew([]int{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, }) err := collect.Chunk(5, func(collection contracts.Collection, page int) error { fmt.Printf("页码:%d,数量:%d %v\n", page, collection.Len(), collection.ToInterfaceArray()) switch page { case 4: assert.True(t, collection.Len() == 4) default: assert.True(t, collection.Len() == 5) } return nil }) assert.Nil(t, err) err = collection.MustNew([]User{ {id: 1, Name: "qbhy", Money: 12}, {id: 2, Name: "goal", Money: 1}, {id: 2, Name: "goal", Money: 15}, {id: 2, Name: "goal99", Money: 99}, {id: 3, Name: "collection", Money: -5}, {id: 3, Name: "挪动", Money: 10086}, }).Chunk(3, func(collection contracts.Collection, page int) error { assert.True(t, page == 1) assert.True(t, collection.First("name") == "qbhy") assert.True(t, collection.Last("name") == "goal") return errors.New("第一页退出") }) assert.Error(t, err)}goal-web goal-web/collection qbhy0715@qq.com ...

January 24, 2022 · 4 min · jiezi

关于golang:利用-gitkit-实现支持-http-和-grpc-的微服务

利用 git-kit 微服务框架实现一个同时反对 http 和 grpc 服务的利用。以一个最常见的文章服务为例,开始教程!我的项目架子go-kit 三层模型简介go-kit 是一套开源的 golang 微服务工具汇合。go-kit 自上而下提供了三层模型,别离是 Transport 层、Endpoint 层、Service 层。 Transport 层:解决 HTTP、gRPC、Thrift 等协定相干的逻辑,次要对申请进行解码、对响应进行编码操作;Endpoint 层:在Service的下层作为业务的中间件,可应用限流、熔断、监控等能力;Service 层:用来解决业务逻辑;我的项目初始化感激FengGeSe/demo 我的项目提供了一个很好工程 demo,本教程基于此仓库进行革新,教程代码于此git-kit-demo。 FengGeSe/demo我的项目在 go-kit 三层模型中,又减少了 Server 和 Router 层,前者作为服务启动,后者作为路由转发。 利用数据模型 Model 作为“中立”数据格式,同时兼容多协定的申请。 eg: 一个 http 申请到来,json 数据会转为 model,响应时 model 会转为 json。 一个 grpc 申请到来,protobuf 数据会转为 model,当响应时,model 会转为 protobuf。 我的项目目录构造.├── README.md ├── cmd // 提供client和server的入口│   ├── client│   └── server├── conf // 配置相干├── endpoint // endpoint层│   └── article├── errors // 错误处理├── go.mod├── go.sum├── params // model层(在代码中应用params示意)│   └── article├── pb // pb层│   └── article├── router // 路由层。grpc和http注册路由的中央│   ├── grpc│   └── http├── server // server层,启动服务的中央│   ├── grpc│   └── http├── service // service层,解决业务逻辑的中央│   └── article├── static // 文档,文档图片相干│   └── img├── transport // transport, 数据转换的中央│   ├── grpc│   └── http├── util // 工具办法└── vendor // 三方依赖上面进入开发! ...

January 24, 2022 · 7 min · jiezi

关于golang:Go118-新特性编译后的二进制文件将包含更多信息

大家好,我是煎鱼。 我有一个敌人,,开开心心入职,想着施展拳脚,第一个工作就是对老旧的二进制文件进行钻研。 他一看,这文件,不晓得是编译器用什么参数怎么打进去的,环境不晓得是什么,更不晓得来自什么代码分支? 这除了是我的项目流程上的问题外,Go 在这块也有相似的小问题,解决起来比拟麻烦。 背景日常中很难从 Go 二进制文件中检索元信息,要么是信息齐全缺失,要么提取须要对二进制文件进行大量解析。 蕴含的元信息如下: 元信息提取处Go 构建版本符号表,通过全局变量 runtime.buildVersion 来获取构建信息,例如:模块和版本符号表,通过全局变量 runtime/debug.modinfo 来获取编译器选项,例如:构建模式、编译器、gcflags、ldflags 等无奈获取用户定义的自定义数据,例如:应用程序版本等需在编译时设置全局字符串变量,才能够获取关注到编译器选项,也就是参数等都是无奈得悉的,也就是会进步获取如何编译进去的难度。 新提案Michael Obermüller 提出了一个新的提案《cmd/go: add compiler flags, relevant env vars to 'go version -m' output》用于解决上述问题。 在提案中想要的是 JSON 格局的构造输入: { "version": "go1.13.4", "compileropts": { "compiler": "gc", "mode": "pie", "os": "linux", ... }, "buildinfo": { "path": "脑子进煎鱼了", "main": { "path": "HelloWorld", "version": "(devel)", }, "deps": [] }, "user": { "customkey": "customval", ... }}Russ Cox 示意因为编译信息已有既有格局,并且默认应用 JSON 只会让二进制文件变得更大。益处少,没必要,改为了选项化的反对。 ...

January 24, 2022 · 1 min · jiezi

关于golang:Golang-wails2-跨端桌面解决方案

wails2 Golanggithub: https://github.com/wailsapp/w... 文档: https://wails.io/zh-Hans/docs... 环境要求Go 1.16npm需是 Windows,MacOS, Linux 操作系统之一gcc装置# Go 1.17 下 装置go install github.com/wailsapp/wails/cmd/wails@latest# Go 1.16 $ go get -u github.com/wailsapp/wails/cmd/wails输出命令,有如下后果就是装置胜利了 $ wails updateWails v1.16.9 - Checking for updates...> Checking for updates... Current Version : v1.16.9 Latest Release : v1.16.9Looks like you're up to date!初始化 个人信息$ wails setup _ __ _ __| | / /___ _(_) /____| | /| / / __ `/ / / ___/| |/ |/ / /_/ / / (__ ) v1.16.9|__/|__/\__,_/_/_/____/ https://wails.appThe lightweight framework for web-like appsWelcome to Wails!## 输出开发者姓名 以及 邮箱What is your name (xiaobaiyaoshengfa):What is your email address (xiaobaiyaoshengfa@sifou): xiaobaiyaoshengfa@sifouWails config saved to: C:\Users\xxx\.wails\wails.jsonFeel free to customise these settings.## 查看以后运行的零碎环境,以及依赖的命令行工具是否可用。Detected Platform: WindowsChecking for prerequisites...Program 'gcc' found: C:\Program Files\mingw-w64\x86_64-7.3.0-release-posix-seh-rt_v5-rev0\mingw64\bin\gcc.exeProgram 'npm' found: C:\nodejs\npm.cmdReady for take off!Create your first project by running 'wails init'.Hello World初始化我的项目$ wails initWails v1.16.9 - Initialising projectThe name of the project (My Project): HelloProject Name: HelloThe output binary name (hello): helloOutput binary Name: helloProject directory name (hello):Project Directory: helloPlease select a template (* means unsupported on current platform): 1: Angular - Angular 8 template (Requires node 10.8+) 2: React JS - Create React App v4 template 3: Svelte - A basic Svelte template 4: Vanilla - A Vanilla HTML/JS template 5: * Vue3 Full - Vue 3, Vuex, Vue-router, and Webpack4 6: * Vue3 JS - A template based on Vue 3, Vue-router, Vuex, and Webpack5 7: Vue2/Webpack Basic - A basic Vue2/WebPack4 template 8: Vuetify1.5/Webpack Basic - A basic Vuetify1.5/Webpack4 template 9: Vuetify2/Webpack Basic - A basic Vuetify2/Webpack4 template## 这里提供了9个前端模板,比方常见的有 Angular, React,Vue 等,这里我抉择了相熟的 ReactPlease choose an option [1]: 2Template: React JS> Generating project...## 当前目录下生成一个 hello 文件夹,理论的wails 我的项目将就在外面。 Project 'Hello' initialised. Run `wails build` to build it.我的项目 目录构造$ tree -L 2 ./hello/./hello/├── appicon.png├── build│   └── hello.exe├── frontend│   ├── build│   ├── node_modules│   ├── package.json│   ├── package.json.md5│   ├── package-lock.json│   ├── public│   ├── README.md│   └── src├── go.mod├── go.sum├── hello.exe.manifest├── hello.ico├── hello.rc├── hello-res.syso├── main.go└── project.json6 directories, 14 files这里 frontend 就是前端我的项目的目录, ./frontend/build 文件夹保留了 npm 编译后的成绩。而 wails 是怎么将其引入到代码中的呢? ...

January 23, 2022 · 3 min · jiezi

关于golang:彻底理解Golang-Map

本文目录如下,浏览本文后,将一网打尽上面Golang Map相干面试题 面试题map的底层实现原理为什么遍历map是无序的?如何实现有序遍历map?为什么Go map是非线程平安的?线程平安的map如何实现?Go sync.map 和原生 map 谁的性能好,为什么?为什么 Go map 的负载因子是 6.5?map扩容策略是什么?实现原理Go中的map是一个指针,占用8个字节,指向hmap构造体; 源码src/runtime/map.go中能够看到map的底层构造 每个map的底层构造是hmap,hmap蕴含若干个构造为bmap的bucket数组。每个bucket底层都采纳链表构造。接下来,咱们来具体看下map的构造 hmap构造体// A header for a Go map.type hmap struct { count int // 代表哈希表中的元素个数,调用len(map)时,返回的就是该字段值。 flags uint8 // 状态标记,下文常量中会解释四种状态位含意。 B uint8 // buckets(桶)的对数log_2 // 如果B=5,则buckets数组的长度 = 2^5=32,意味着有32个桶 noverflow uint16 // 溢出桶的大略数量 hash0 uint32 // 哈希种子 buckets unsafe.Pointer // 指向buckets数组的指针,数组大小为2^B,如果元素个数为0,它为nil。 oldbuckets unsafe.Pointer // 如果产生扩容,oldbuckets是指向老的buckets数组的指针,老的buckets数组大小是新的buckets的1/2;非扩容状态下,它为nil。 nevacuate uintptr // 示意扩容进度,小于此地址的buckets代表已搬迁实现。 extra *mapextra // 这个字段是为了优化GC扫描而设计的。当key和value均不蕴含指针,并且都能够inline时应用。extra是指向mapextra类型的指针。 }bmap构造体bmap 就是咱们常说的“桶”,一个桶外面会最多装 8 个 key,这些 key 之所以会落入同一个桶,是因为它们通过哈希计算后,哈希后果是“一类”的,对于key的定位咱们在map的查问和插入中具体阐明。在桶内,又会依据 key 计算出来的 hash 值的高 8 位来决定 key 到底落入桶内的哪个地位(一个桶内最多有8个地位)。 ...

January 23, 2022 · 8 min · jiezi

关于golang:golangleetcode初级最长公共前缀删除链表中的节点

第一题 最长公共前缀题目信息编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 ""。   示例 1: 输出:strs = ["flower","flow","flight"]输入:"fl"示例 2: 输出:strs = ["dog","racecar","car"]输入:""解释:输出不存在公共前缀。  提醒: 1 <= strs.length <= 2000 <= strs[i].length <= 200strs[i] 仅由小写英文字母组成 解题思路按程序对字符串切片进行一次遍历,对每个字符串的首个字符进行查找若字符都雷同,则将该字符退出返回的字符串变量,并查找下一字符若字符不同,则间接返回 代码func getch(str string,n int)rune{ for i, r := range str { if i==n{ return r } } return 0}func longestCommonPrefix(strs []string) string { var res string var n int var c rune for { c=getch(strs[0],n) for _, str := range strs { if getch(str,n)==0{return res} if getch(str,n)!=c{ return res } } res=res+string(c) n++ }}复杂度剖析工夫复杂度:O(len(res)*len(strs)) 返回的字符串长度每加一,就要多做一边循环;每做一遍循环,就要遍历一次字符串切片的所有字符串;空间复杂度:O(1) 常数级空间 ...

January 23, 2022 · 1 min · jiezi

关于golang:Go-Quiz-从Go面试题搞懂slice-range遍历的坑

面试题最近Go 101的作者公布了11道Go面试题,十分乏味,打算写一个系列对每道题做具体解析,欢送大家关注。 本题是Go quiz slice系列的第2道题目,这道题十分有迷惑性。 通过这道题咱们能够通晓对slice做range遍历的坑,防止在理论我的项目中踩坑。 package mainfunc main() { var x = []string{"A", "B", "C"} for i, s := range x { print(i, s, ",") x[i+1] = "M" x = append(x, "Z") x[i+1] = "Z" }}0A,1B,2C,0A,1Z,2Z,0A,1M,2M,0A,1M,2C,0A,1Z,2M,0A,1M,2Z,(infinite loop)大家能够在评论区留下你们的答案。这道题次要有以下几个考点: slice做range遍历,Go编译器背地会做哪些事件?slice什么时候扩容,扩容后的行为是怎么样的?解析咱们先一一解答下面的问题。 range遍历机制range对slice做遍历的时候,实际上是先结构一个原slice的拷贝,再对这个拷贝做遍历。 在for循环外面的逻辑执行之前,这个拷贝的值就确定下来了。因而这个拷贝的长度和容量是不会在for循环的时候产生扭转的。 以下面的题目为例:range x 实际上是会先结构一个原切片x的拷贝,咱们假如为y,而后对y做遍历。 for i, s := range x { print(i, s, ",") x[i+1] = "M" x = append(x, "Z") x[i+1] = "Z"}下面这段代码能够等价为: y := xfor i := 0; i < len(y); i++ { print(i, y[i], ",") x[i+1] = "M" x = append(x, "Z") x[i+1] = "Z"}slice扩容机制通过append函数给slice增加元素的时候,有2种状况: ...

January 23, 2022 · 1 min · jiezi

关于golang:golangleetcode初级实现-strStr外观数列

第一题 实现 strStr()题目信息实现 strStr() 函数。 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串呈现的第一个地位(下标从 0 开始)。如果不存在,则返回  -1 。   阐明: 当 needle 是空字符串时,咱们该当返回什么值呢?这是一个在面试中很好的问题。 对于本题而言,当 needle 是空字符串时咱们该当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。   示例 1: 输出:haystack = "hello", needle = "ll"输入:2示例 2: 输出:haystack = "aaaaa", needle = "bba"输入:-1示例 3: 输出:haystack = "", needle = ""输入:0  提醒: 0 <= haystack.length, needle.length <= 5 * 104haystack 和 needle 仅由小写英文字符组成相干标签双指针字符串字符串匹配 解题思路首先想到的当然是最暴力的解法,遍历haystack字符串,每当读到字符与needle首字符雷同的则将其后续与needle进行一次比拟,直到haystack的残余长度小于needle为止。然而,该算法工夫复杂度较高,还有很多可优化的空间这里咱们引入KPM算法 代码暴力解法 func strStr(haystack, needle string) int { n, m := len(haystack), len(needle)outer: for i := 0; i+m <= n; i++ { for j := range needle { if haystack[i+j] != needle[j] { continue outer } } return i } return -1}作者:LeetCode-Solution链接:https://leetcode-cn.com/problems/implement-strstr/solution/shi-xian-strstr-by-leetcode-solution-ds6y/起源:力扣(LeetCode)著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。kmp算法 ...

January 22, 2022 · 2 min · jiezi

关于golang:是的没错我就是抄的一个像-Laravel-那样好用的-go-语言的-SQL-查询构造器

Goal/QueryBuilderGoal 的数据库查问结构器为创立和运行数据库查问提供了一个不便的接口。它能够用于反对大部分数据库操作,并与 Goal 反对的所有数据库系统完满运行。并且大量参考了 Laravel 的查问结构器设计,你简直能够在这个库找到所有与 Laravel 对应的办法。 Goal 的查问结构器实现了相似 PDO 参数绑定的模式,来爱护您的应用程序免受 SQL 注入攻打。因而不用清理因参数绑定而传入的字符串。查问结构器会返回你想要的 SQL 语句以及绑定参数。 装置go get github.com/goal-web/querybuilder运行数据库查问依据条件从表中检索出数据你能够应用 NewQuery 办法来开始查问。该办法为给定的表返回一个查问结构器实例,容许你在查问上链式调用更多的束缚,最初应用 get 办法获取后果: package querybuilderimport ( "fmt")func TestSimpleQueryBuilder() { query := NewQuery("users"). Where("name", "qbhy"). Where("age", ">", 18). Where("gender", "!=", 0). OrWhere("amount", ">=", 100). WhereIsNull("avatar") fmt.Println(query.ToSql()) fmt.Println(query.GetBindings()) // select * from users where name = ? and age > ? and gender != ? and avatar is null or amount >= ? // [qbhy 18 0 100]}你也能够通过 SelectSql 办法一次性获取你想要的参数。例如:sql, bindings := NewQuery("users").Where("gender", 1).SelectSql()插入语句你能够通过 InsertSql 或者 CreateSql 很不便的生成插入语句。 ...

January 22, 2022 · 2 min · jiezi