参考资料地址1:https://pan.baidu.com/s/1RvSbqB1eiop4FjYFo8nAPw 提取码:gqlo 参考资料地址2:https://share.weiyun.com/Oh3g6KRc 密码:kiyx7m
一、什么是低代码? 低代码(Low Code)是一种可视化的应用开发方法,用较少的代码、以较快的速度来交付应用程序,将程序员不想开发的代码做到自动化,称之为低代码。
二、低代码所带来的核心价值 低代码开发平台能够实现业务应用的快速交付。也就是说,不只是像传统开发平台一样“能”开发应用而已,低代码开发平台的重点是开发应用更“快”。 低代码开发平台能够降低业务应用的开发成本。
三、低代码产品形态是什么样的? 一般来说,按搭建应用时是否需要代码可以将广义低代码产品分为狭义低代码和零代码两种,二者均可通过可视化界面,对封装好的代码模块进行拖拉拽来完成应用搭建。 低代码:主要服务关注业务逻辑的开发部门,需要少量代码进行模块衔接或功能拓展;零代码:更强调低代码的低门槛,仅需理顺业务逻辑即可快速搭建流程管理、表单等轻量级应用。
四、低代码的特点 1、不能仅用于或主要应用构建特定行业的应用,不能仅限于在依赖其他解决方案或平台上运行。 2、需要能提供给IT技术人员使用,不能只给平民开发者使用。 3、全生命周期:覆盖应用和相关资源的开发、版本管理、测试、部署、执行、管制、监控和管理的全生命周期。 4、内建数据存储:内建数据存储机制,不能依赖其他的数据库等存储服务。 5、数据与逻辑设计:支持用来设计数据结构和应用逻辑。 6、完整的界面设计:支持创建完整的应用界面,不能仅支持创建表单或管理界面。
变长参数的使用需要注意下面几个问题: 函数只能有一个变长参数,并且只能是函数参数列表中最后一个形参; 变长参数在函数体内是切片类型,也就是说…T等同于[]T 形参的类型和实参必须一致,包括接口类型 比如下面这个例子是初学者很容易犯的错误: func main() { f1("imooc") }
func f1(name string, params ...interface{}) { if len(params) == 0 { fmt.Println(name) return } for i, param := range params { fmt.Println("i:", i, ";param:", param) } } 我们先看源码中DeepEqual函数的定义$GOROO/src/reflect/deepequal.go func DeepEqual(x, y any) bool { if x == nil || y == nil { return x == y } v1 := ValueOf(x) v2 := ValueOf(y) if v1.Type() != v2.Type() { return false } return deepValueEqual(v1, v2, make(map[visit]bool)) }
首先第一种是直接通过类型转化的结果来判断,具体方式如下: package main
import ( "fmt" "reflect" )
type person struct { Name string }
func (p *person) Say(str string) string { return p.Name + str }
func main() { //方法1:通过类型转化判断 p := &person{} fmt.Println(HasMethodSay(p)) //true
}
func HasMethodSay(v interface{}) (has bool) { _, has = v.(interface{ Say(str string) string }) return }
第二种方式是借助标准库中的reflect包来实现,具体实现方式如下: func main() { //方法2;通过反射实现 fmt.Println(HasMethod(p, "Say")) //true }
func HasMethod(obj interface{}, methodName string) bool { if methodName == "" { return false } object := reflect.ValueOf(obj) // 获取到方法 method := object.MethodByName(methodName) if !method.IsValid() { return false } return true } 我们可以通过下面的代码进行验证: func Sprintf(format string, a ...any) string { p := newPrinter() p.doPrintf(format, a) s := string(p.buf) p.free() return s }
// newPrinter allocates a new pp struct or grabs a cached one. func newPrinter() pp { p := ppFree.Get().(pp) p.panicking = false p.erroring = false p.wrapErrs = false p.fmt.init(&p.buf) return p } 低代码平台提供了预先构建好的组件和模板,这使得开发人员可以更快地构建应用程序,而无需从头开始编写代码。例如简道云平台中有大量的场景套件,如人事行政OA、客户关系管理、进销存模板、仓库管理等等,这种方法可以大大减少开发时间,从而加快了产品上市时间。 package main
import ( "fmt" "reflect" "strings" "unsafe" )
var s = strings.Repeat("1", 1<<20)
func main() { ptr := (*reflect.StringHeader)(unsafe.Pointer(&s)) //字符串字节数组的的地址 fmt.Println("s pointer:", unsafe.Pointer(ptr.Data))
Assign()
AssignPointer()
StringSlice()
Repeat()
StringSlice1(s)
StringSlice2(s)
StringSliceUseBuilder(s)
f1(s)
f2(&s)
}
func Assign() { s2 := s ptr := (*reflect.StringHeader)(unsafe.Pointer(&s2)) //字符串字节数组的的地址 fmt.Println("Assign:", unsafe.Pointer(ptr.Data)) _ = s2 }
func AssignPointer() {
s2 := &s
ptr := (*reflect.StringHeader)(unsafe.Pointer(s2))
//字符串字节数组的的地址
fmt.Println("AssignPointer", unsafe.Pointer(ptr.Data))
_ = s2
}
func StringSlice() { s2 := s[:20] ptr := (*reflect.StringHeader)(unsafe.Pointer(&s2)) //字符串字节数组的的地址 fmt.Println("StringSlice", unsafe.Pointer(ptr.Data)) _ = s2
}
func Repeat() {
s2 := strings.Repeat(s, 1)
//s2 := strings.Repeat(s, 2)
ptr := (*reflect.StringHeader)(unsafe.Pointer(&s2))
//字符串字节数组的的地址
fmt.Println("Repeat", unsafe.Pointer(ptr.Data))
_ = s2
}
func f1(s string) string { ptr := (*reflect.StringHeader)(unsafe.Pointer(&s)) //字符串字节数组的的地址 fmt.Println("f1:", unsafe.Pointer(ptr.Data)) return s }
func f2(s string) *string { ptr := (reflect.StringHeader)(unsafe.Pointer(s)) //字符串字节数组的的地址 fmt.Println("f2:", unsafe.Pointer(ptr.Data)) return s }
func StringSlice1(s string) string { s1 := []byte(s[:20]) ptr := (reflect.StringHeader)(unsafe.Pointer(&s1)) //字符串字节数组的的地址 fmt.Println("StringSlice1:", unsafe.Pointer(ptr.Data)) s2 := string(s1) ptr = (reflect.StringHeader)(unsafe.Pointer(&s2)) //字符串字节数组的的地址 fmt.Println("StringSlice1:", unsafe.Pointer(ptr.Data)) return s2 }
func StringSlice2(s string) string { s1 := string([]byte(s[:20])) ptr := (*reflect.StringHeader)(unsafe.Pointer(&s1)) //字符串字节数组的的地址 fmt.Println("StringSlice2:", unsafe.Pointer(ptr.Data))
return s1
}
func StringSlice3(s string) string { s1 := (" " + s[:20])[1:]
ptr := (*reflect.StringHeader)(unsafe.Pointer(&s1))
//字符串字节数组的的地址
fmt.Println("StringSlice3:", unsafe.Pointer(ptr.Data))
return s1
}
func StringSliceUseBuilder(s string) string { var b strings.Builder b.Grow(20) b.WriteString(s[:20]) s1 := b.String()
ptr := (*reflect.StringHeader)(unsafe.Pointer(&s1))
//字符串字节数组的的地址
fmt.Println("StringSliceUseBuilder:", unsafe.Pointer(ptr.Data))
return s1
}