Golang基础(变量[普通变量、数组、切片、map、list、ring]声明及赋值)
Go语言和其他语言一样都有基本存储容器.可以存储一个或多个值在程序中,方便程序中多次使用容器中内容,这个容器称为:变量
Go语言虽然是静态类型语言,但是支持动态类型语言语法,因为Go语言希望程序员少声明变量,增加GC效率
一、变量命名规则
以字母或下划线开头(Go语言中多不以_开头)
后面可以是任意数量的字符、数字和下划线
区分大小写
不能是关键字(关键字具备特定含义),下面是Go语言的关键字
关键字如下 | ||||
---|---|---|---|---|
break | default | func | interface | select |
case | defer | go | map | struct |
chan | else | goto | package | switch |
const | fallthrough | if | range | type |
continue | for | import | return | var |
在同一范围内不允许出现同名变量
Go语言要求变量声明后至少使用一次(赋值不属于使用)
二、单个变量声明及赋值
先声明后赋值(声明后开辟内存,不同类型变量都有不同初值)
//语法:
//1. 声明
var 变量名 类型
//2. 赋值
变量名=值//示例:
var smallming string
smallming = "英文名"
声明并赋值(省略类型,变量类型取决于值的类型)
//语法:
var 变量名 = 值//示例:
var smallming = "英文名"
短变量(只能在函数内使用)
//语法:
变量名 := 值//示例:
smallming := "英文名"
三、声明多个变量和赋值
先声明后赋值
func main() {var a, b, c inta, b, c = 1, 2, 3fmt.Println(a, b, c)
}
声明时赋值
func main() {var a, b, c, d = 1, 2, 3, falsefmt.Println(a, b, c, d)
}
声明并赋值,推荐方式
func main() {var (a = 1b = truec = "测试")fmt.Println(a, b, c)
}
使用短变量给多个变量赋值时,必须要保证至少有个变量是没有声明的
func main() {var (a = 1b = truec = "测试")//短变量操作多个值时只要保证里面至少有一个新变量b, c, d := false, "smallming", 3fmt.Println(a, b, c, d)
}
① 变量作用域
变量声明位置决定了变量的可访问范围(哪里能调用到变量)
Go语言中变量的有效范围如下
函数级别:变量声明在函数内部,只有在函数内部才能访问,称变量为局部变量
package 包级别,在当前包下都可以访问.称变量为全局变量.变量声明在函数外面
应用级别,在整个应用下任何包内都可以访问.通过首字母大小写控制
② 局部变量
局部变量一定是在函数内部
在哪个{}内部声明,只能在哪个{}内部访问
func test1() {i := 2 //从此处开始到test1结束}任何位置都能调用iif i>=2{j:=3fmt.Println(i+j)//此处可以访问i}fmt.Println(i)//fmt.Println(j)//此处不能调用j,超出声明j时{}外
}
func test2() {fmt.Println(i) //此处无法调用test1()中的i
}
③ 全局变量
全局变量声明到函数外部,整个包都可以访问
如果全局变量首字母大写,跨包也可以访问.
声明全局变量时规范是
var (变量名变量名=值 )
全局变量代码示例
var (name = "smallming"age = 17
)
func demo1() {fmt.Println("名字:",name)
}
func demo2() {fmt.Println("年龄:",age)
}
四.数组的创建和赋值
可以在声明数组时可以同时给数组赋值,赋值时要求长度必须大于等于初始值个数
//方式一:完整写法var arr [3]int = [3]int{1, 2, 3}//方式二:短变量方式arr2 := [3]int{1, 2, 3}//方式三:长度大于初始值个数.长度为4,只给前三个元素赋值,其余元素为默认值arr3 := [4]int{1, 2, 3}//方式四:赋值时不写长度,数组长度根据元素个数确定arr4 := [...]int{1, 2, 3}
可以通过:数组名[脚标]对数组中元素进行操作
arr := [3]int{1, 2, 3}
fmt.Println(arr)//通过脚标对数组中元素进行重新赋值arr[0] = 5arr[1] = 6arr[2] = 7fmt.Println(arr[0], arr[1], arr[2])
通过len(数组变量)获取数组长度,数组脚标最大值为长度减一,如果超出这个范围将会报错
arr := [3]int{1, 2, 3}fmt.Println(len(arr))//输出:3arr[3]=5//错误信息:invalid array index 3 (out of bounds for 3-element array)
4.1、数组是值类型
在Go语言中数组是值类型,和之前学习的int或float64等类型相同,把一个数组变量赋值给另一个数组变量时为复制副本,重新开辟一块空间
使用==比较数组中值是否相等
arr := [3]int{1, 2, 3}arr2:=arrfmt.Println(arr,arr2)fmt.Printf("%p %p",&arr,&arr2)//地址不同fmt.Println(arr==arr2)
4.2、切片
切片的英文名称slice
切片:具有可变长度相同类型元素序列.
由于长度是可变,可以解决数组长度在数据个数不确定情况下浪费内存的问题.
切片和数组声明时语法最主要的区别就是长度
var slice []string //切片var array [3]string //数组
切片只声明时为nil,没有开辟内存空间,不能直接操作切片,需要先初始化
注意:切片只能和nil进行判断是否相等
var slice []string //切片fmt.Println(slice==nil)//输出:truefmt.Printf("%p",slice)//输出:0x0
4.3、定义切片
通过直接指定初始值定初始化一个切片变量
names := []string{"smallming", "佳明哥"}fmt.Println(names)
定义完切片后就可以通过
切片对象[脚标]
取出或修改切片中元素内容.语法和数组相同
4.4、切片是引用类型
引用类型在变量之间赋值时传递的是地址.引用类型变量就是这个类型的指针.切片就是引用类型
值类型在变量之间赋值时传递的是值的副本
names := []string{"smallming", "佳明哥"}names1 := namesnames1[0] = "张"fmt.Println(names, names1)//输出:[张 佳明哥] [张 佳明哥]fmt.Printf("%p %p",names,names1)//地址相同
4.5、数组的遍历
关键字 range 会返回两个值,第一个值是当前迭代到的索引位置,第二个值是该位置对应元素值的一份副本
array:=[]string{"hello","hi","heihei"}//使用for循环遍历for a:=0;a<len(array);a++ {fmt.Println(a,array[a])}//使用range循环遍历for key,value:=range array{fmt.Println(key,value)}
1、make函数
Go语言中可以使用make函数创建slice 、 map、 channel、 interface
使用make函数定义无内容,但是不是nil的切片,意味着切片已经申请了内存空间
make(类型,初始长度[,初始容量])
初始容量可以省略,默认和长度相等
slice := make([]string, 0) //长度为0的切片,没有第三个参数表示容量和长度相等slice1 := make([]string, 0, 2) //长度为0,容量为2fmt.Println(slice, slice1)
长度表示切片中元素的实际个数,容量表示切片占用空间大小,且切片容量成倍增加.当增加到1024后按照一定百分比增加.
len(slice) 查看切片的长度
cap(slice) 查看切片的容量
slice := make([]string, 0) //长度为0的切片,没有第三个参数表示容量和长度相等slice1 := make([]string, 0, 3) //长度为0,容量为2fmt.Println(len(slice), cap(slice))fmt.Println(len(slice1), cap(slice1))
2、append()函数
append()在Go语言标准库中源码如下
// The append built-in function appends elements to the end of a slice. If
// it has sufficient capacity, the destination is resliced to accommodate the
// new elements. If it does not, a new underlying array will be allocated.
// Append returns the updated slice. It is therefore necessary to store the
// result of append, often in the variable holding the slice itself:
// slice = append(slice, elem1, elem2)
// slice = append(slice, anotherSlice...)
// As a special case, it is legal to append a string to a byte slice, like this:
// slice = append([]byte("hello "), "world"...)
func append(slice []Type, elems ...Type) []Type
可以向切片中添加一个或多个值,添加后必须使用切片接收append()函数返回值
s := make([]string, 0)fmt.Println(len(s), cap(s))//输出:0 0s = append(s, "老张", "佳明哥")fmt.Println(len(s), cap(s))//输出:2 2s = append(s, "smallming")fmt.Println(len(s), cap(s))//输出:3 4
如果添加一次添加多个值,且添加后的长度大于扩容一次的大小,容量和长度相等.等到下次添加内容时如果不超出扩容大小,在现在的基础上进行翻倍
s := make([]string, 0)fmt.Println(len(s), cap(s)) //输出:0 0s = append(s, "老张", "佳明哥")fmt.Println(len(s), cap(s)) //输出:2 2s = append(s, "smallming")fmt.Println(len(s), cap(s)) //输出:3 4s = append(s, "4", "5", "6", "7", "8", "9")fmt.Println(len(s), cap(s)) //输出:9 9s = append(s,"10")fmt.Println(len(s), cap(s)) //输出:10 18
也可以把一个切片的内容直接添加到另一个切片中.需要注意语法中有三个点
s := make([]string, 0)s1 := []string{"smallming", "佳明哥"}s = append(s, s1...) //注意此处,必须有三个点fmt.Println(s)
4.5、通过数组产生切片
定义数组后,取出数组中一个片段,这个片段就是切片类型,(names[0:]->表示从脚标0开始到最后一个结束,当结束脚标为最后一个脚标时可省略最后一个脚标)
names := [3]string{"老张", "佳明哥", "smallming"}s := names[0:2] //包前不包后 注意此处数组内是0:n格式s1 := names[0:] fmt.Printf("%T", s) //输出:[]stringfmt.Println(s) //输出:[老张 佳明哥]fmt.Println(s1) //输出:[老张 佳明哥 smallming]
切片是指针,指向数组元素地址,修改切片的内容,数组的内容会跟随变化
names := [3]string{"老张", "佳明哥", "smallming"}s := names[0:2] //包前不包后fmt.Printf("%p %p",s,&names[0])//输出的地址是相同的s[0] = "Go语言"fmt.Println(s) //输出:[Go语言 佳明哥]fmt.Println(names) //输出:[Go语言 佳明哥 smallming]
当切片内容在增加时
如果增加后切片的长度没有超出数组,修改切片也是在修改数组
如果增加后切片的长度超出数组,会重新开辟一块空间放切片的内容
通过下面代码也正面了切片中内容存在一块连续空间(和数组一样)
names := [3]string{"老张", "佳明哥", "smallming"}s := names[0:2] //包前不包后fmt.Printf("%p %p\n",s,&names[0])s[0] = "Go语言"s=append(s,"区块链")fmt.Println(s) //输出:[Go语言 佳明哥 区块链]fmt.Println(names) //输出:[Go语言 佳明哥 区块链]fmt.Printf("%p %p\n",s,&names[0])//地址相同
s=append(s,"超出了数组长度")fmt.Println(s) //输出:[Go语言 佳明哥 区块链 超出了数组长度]fmt.Println(names) //输出:[Go语言 佳明哥 区块链]fmt.Printf("%p %p\n",s,&names[0])//切片地址改变
4.6、删除实现
Go语言标准库中没有提供删除的函数
切片也可以取其中的一段形成子切片,利用这个特性可以实现删除效果
num := []int {0,1,2,3,4,5,6}//要删除脚标为n的元素n:= 2num1 :=num[0:n]num1= append(num1,num[n+1:]...)fmt.Println(num1)
package mainimport ("fmt""strings"
)func main() {var s string="smallming";//创建切片,切片是引用类型,声明之后并未分配空间,var split []string;fmt.Printf("%p",split) //0x0 地址是空的fmt.Println(split1==nil) //truesplit= strings.Split(s, "m");fmt.Println(split)sprintf := fmt.Sprintf("%s", strings.Split(s, "m"));fmt.Println("接收到的数组为"+sprintf)fmt.Println(strings.Join(split, "m"))}
五. map
map以散列表方式存储键值对集合
map中每个元素都是键值对
map[key]Value
key是操作map的唯一标准.可以通过key对map中元素进行增加/删除/修改/查看
key是唯一的,添加重复的key会覆盖之前的元素.
map是值类型,只声明时为空指针(nil)
var m map[string]intfmt.Println(m == nil) //输出:truefmt.Printf("%p", m) //输出:0x0
map读写数据时并不是并发安全的,可以结合RWMutex保证并发安全(RWMutex在后面讲解)
5.1、实例化map的几种方式
使用make函数实例化一个没有初始值的map
m := make(map[string]string)fmt.Println(m==nil)//输出:falsefmt.Printf("%p", m)//输出:内存地址
可以在声明map时直接给map赋初始值.注意初始值在一行和在多行写时的语法区别
map中元素键值对语法满足: key:value
key和value的类型必须和map[key]value类型严格对应
m := map[string]string{"name": "smallming", "address": "北京海淀"}m1 := map[string]string{"name": "smallming","addresss": "北京海淀",}fmt.Println(m, m1)
5.2、操作map中的元素
使用key判断,如果key不存在向map中新增数据,如果key存在会覆盖map中元素
m := make(map[string]int)m["money"] = 5fmt.Println(m) //输出:map[money:5]m["money"] = 6fmt.Println(m) //map[money:6]
Go语言标准库中提供了对map元素删除的函数,使用顶层delete()即可完成删除
如果key存在执行删除元素
如果key不存在,map中内容不变,也不会有错误
m := make(map[string]int)m["money"] = 5delete(m, "没有的key")fmt.Println(m) //输出:map[money:5]delete(m, "money")fmt.Println(m) //输出:map[]
获取map中指定key对应的值
使用:map变量[key]获取key对应的值
如果key不存在返回map[key]Value中Value类型的默认值.例如:Value是string类型就返回""
返回值可以是一个,也可以是两个.
一个表示key对应的值
两个分别表示:key对应的值和这个key是否存在
m := map[string]string{"name": "smallming", "address": "北京海淀"}fmt.Println(m["name"]) //输出:smallmingfmt.Println(m["age"]) //输出:空字符串value, ok := m["age"]fmt.Println(value, ok) //输出:空字符串 false
如果希望把map中所有元素都遍历,可以使用for结合range实现
hello:=map[string]int{"hello1":1,"hello2":2};fmt.Println(hello["hello1"])fmt.Println(hello["hello2"])for key,value:=range hello{fmt.Println(key,value)}
六.双向链表概述
双向链表结构如下
双向链表结构中元素在内存中不是紧邻空间,而是每个元素中存放上一个元素和后一个元素的地址
第一个元素称为头(head)元素,前连接(前置指针域)为nil
最后一个元素称为尾(foot)元素,后连接(后置指针域)为nil
双向链表的优点:
在执行新增元素或删除元素时效率高,获取任意一个元素,可以方便的在这个元素前后插入元素
充分利用内存空间,实现内存灵活管理
可实现正序和逆序遍历
头元素和尾元素新增或删除时效率较高
双向链表的缺点
链表增加了元素的指针域,空间开销比较大
遍历时跳跃性查找内容,大量数据遍历性能低
6.1、 双向链表容器List
在Go语言标准库的container/list 包提供了双向链表List
List结构体定义如下
root表示根元素
len表示链表中有多少个元素
// List represents a doubly linked list.
// The zero value for List is an empty list ready to use.
type List struct {root Element // sentinel list element, only &root, root.prev, and root.next are usedlen int // current list length excluding (this) sentinel element
}
其中Element结构体定义如下
next表示下一个元素,使用Next()可以获取到
prev表示上一个元素,使用Prev()可以获取到
list表示元素属于哪个链表
Value表示元素的值,interface{}在Go语言中表示任意类型
// Element is an element of a linked list.type Element struct {// Next and previous pointers in the doubly-linked list of elements.// To simplify the implementation, internally a list l is implemented// as a ring, such that &l.root is both the next element of the last// list element (l.Back()) and the previous element of the first list// element (l.Front()).next, prev *Element
// The list to which this element belongs.list *List
// The value stored with this element.Value interface{}}
6.2、操作List
直接使用container/list包下的New()新建一个空的List, list与切片、Map不一样,没有具体元素类型的限制。
在java、c++等里面,list的成员必须是同一个数据类型,但是Go语言中却允许list里插入任意类型成员。
建议使用New()实现list。
mylist := list.New()fmt.Println(mylist) //输出list中内容fmt.Println(mylist.Len()) //查看链表中元素的个数fmt.Printf("%p", mylist) //输出地址
Go语言标准库中提供了很多向双向链表中添加元素的函数
//添加到最后,List["a"]mylist.PushBack("a")//添加到最前面,List["b","a"]mylist.PushFront("b") //向第一个元素后面添加元素,List["b","c","a"]mylist.InsertAfter("c", mylist.Front()) //向最后一个元素前面添加元素,List["b","c","d","a"]mylist.InsertBefore("d", mylist.Back())
取出链表中的元素
fmt.Println(mylist.Back().Value) //最后一个元素的值fmt.Println(mylist.Front().Value) //第一个元素的值
//只能从头向后找,或从后往前找,获取元素内容n := 5var curr *list.Elementif n > 0 && n <= mylist.Len() {if n == 1 {curr = mylist.Front()} else if n == mylist.Len() {curr = mylist.Back()} else {curr = mylist.Front()for i := 1; i < n; i++ {curr = curr.Next()}}} else {fmt.Println("n的数值不对")}//遍历所有值for e := mylist.Front(); e != nil; e = e.Next() {fmt.Println(e.Value)}
移动元素的顺序
mylist.MoveToBack(mylist.Front()) //把第一个移动到后面mylist.MoveToFront(mylist.Back()) //把最后一个移动到前面mylist.MoveAfter(mylist.Front(),mylist.Back())//把第一个参数元素,移动到第二个参数元素后面mylist.MoveBefore(mylist.Front(),mylist.Back())//把第一个参数元素,移动到第二个参数元素前面
删除元素
mylist.Remove(mylist.Front())
mylist := list.New()mylist.PushBack(1)mylist.PushBack("hello")mylist.PushBack(2.0)for e:=mylist.Front();e!=nil;e=e.Next() {fmt.Println(e.Value)}// 1// hello// 2.0 *go语言中list中可以存放不同类型的数据
一.双向循环链表
循环链表特点是没有节点的指针域为nil,通过任何一个元素都可以找到其他元素
环形链表结构如下
双向循环链表和双向链表区别
双向循环链表没有严格意义上的头元素和尾元素
没有元素的前连接和后连接为nil
一个长度为n的双向循环链表,通过某个元素向某个方向移动,在查找最多n-1次后一定会找到另一个元素
双向循环链表,默认第一元素为头元素,头元素即代表链表中的一个元素有代表整个双向循环链表,并且头元素是不可以被删除和覆盖的,因为它既是元素又代表链表。
二.Go语言中的双向循环链表
在container/ring包下结构体Ring源码如下
官方明确说明了Ring是循环链表的元素,又是环形链表.
实际使用时Ring遍历就是环形链表第一个元素
// A Ring is an element of a circular list, or ring.
// Rings do not have a beginning or end; a pointer to any ring element
// serves as reference to the entire ring. Empty rings are represented
// as nil Ring pointers. The zero value for a Ring is a one-element
// ring with a nil Value.
//
type Ring struct {next, prev *RingValue interface{} // for use by client; untouched by this library
}
Go语言标准库中对container/ring包提供的API如下
type Ring//实例化长度为n的环形链表func New(n int) *Ring//长度func (r *Ring) Len() int//下一个元素func (r *Ring) Next() *Ring//上一个元素func (r *Ring) Prev() *Ring//移动n次,支持负数func (r *Ring) Move(n int) *Ring//合并s和rfunc (r *Ring) Link(s *Ring) *Ring//删除r后面n%r.Len()元素,删除多个,当前元素前面的不删除func (r *Ring) Unlink(n int) *Ring//循环遍历,i是当前元素的值func (r *Ring) Do(f func(interface{}))
三.代码演示
实例化、赋值、遍历
package mainimport ("container/ring""fmt"
)func main() {//代表整个循环链表,又代码第一个元素r:=ring.New(5)r.Value = 0 //0即是头元素又代表整个链表,通过r.Value为链表元素进行赋值。r.Next().Value =1 //向后赋值r.Next().Next().Value= 2//r.Next().Next().Next().Value=3//r.Next().Next().Next().Next().Value=4r.Prev().Value=4 //向前赋值,由于循环链表是一个环状结构,所以重复的链表脚标即覆盖 r.Prev().Prev().Value=3//fmt.Println(r.Move(-2).Value) //Move源码中调用的就是根据Move(参数a)中a是否大于0而调 //用r.Next()和r.Prev()//增加//r1:=ring.New(1)//r1.Value=5//r.Next().Link(r1) //通过Link向原链表中添加新的元素,默认天加到头元素即第 //一个创建的元素后,r.Next().Link即添加到首元素下一个 //元素后//删除//参数n取值为n%r.len() r.Unlink(1) //通过Unlink方法,将链表中头元素后边的n个元素删除。此处是 //删除了头元素后边的第一个元素即元素值为1的元素。//虽然是循环链表但是不允许删除头元素和头元素之前的元素。//循环链表有几个元素,func执行几次,i代表当前执行元素的内容,遍历链表所有元素r.Do(func(i interface{}) {fmt.Println(i)})
}
实例化后的r就是链表中第一个创建的元素.可以找到元素的前后元素
fmt.Println(r.Next().Value)//输出:1fmt.Println(r.Next().Next().Value)//输出:2fmt.Println(r.Next().Next().Next().Value)//输出:0fmt.Println(r.Move(-1).Value)//输出:2fmt.Println(r.Prev().Value)//输出:2
可以向环形链表添加或删除链表
s := ring.New(1)s.Value = 13//r是哪个元素,就把新的链表添加到哪个元素后面r.Link(s)r.Do(func(i interface{}) {fmt.Print(i, " ")})fmt.Println("")//从r元素向后,n/r.Len()个元素被删除,当前元素和前面的保留r.Unlink(1)r.Do(func(i interface{}) {fmt.Print(i, " ")})
Golang基础(变量[普通变量、数组、切片、map、list、ring]声明及赋值)相关推荐
- 02 Java基础语法(变量+数据类型+运算符)
Java基础语法 2 基础语法 2.1 二进制(复习总结) 进制转换(二进制 八进制 十进制 十六进制) 2.2 变量 2.2.1 变量定义 2.2.2 使用变量 2.2.3 声明变量的3种方式 2. ...
- golang基础教程
目录 golang基础教程(一).环境搭建 golang基础教程(二).开发规范及API golang基础教程(三).变量与数据类型概述 golang基础教程(四).基本数据类型 golang基础教程 ...
- Golang基础笔记
Go笔记 一.注释 单行注释 //单行注释 多行注释 /*这是多行注释这是一个main函数,这个是go语言启动的入口 */ 二.变量 声明变量使用var关键字: var name type var 变 ...
- Java基础+流程控制+方法+数组【笔记含代码】
文章目录 什么是计算机 计算机硬件 计算机软件 DOS命令 计算机语言发展史 第一代语言 第二代语言 第三代语言 Java帝国的诞生 C & C++ 反抗 Java初生 Java发展 Java ...
- 努力前端【LeetCode-10】448. 找到所有数组中消失的数字 442. 数组中重复的数据(中等) 41. 缺失的第一个正数(困难) [鸽笼原理,数组,Map,类似No.645]
文章目录 题目描述-448 一.哈希Map 二.空间复杂度的优化--鸽笼原理 三.总结 题目描述-442 一.还是hashMap 二.继续鸽笼原理 题目描述-41 一.基础方案 二.数组模拟Map 题 ...
- 【Java基础】--第1~6章:基础知识、变量和数据类型、运算符、程序控制结构、数组
文章目录 Java基础 一.Java概述 Java技术体系平台 Java重要特点 Java运行机制及运行过程 Java核心机制--Java虚拟机(JVM) 编译和运行过程 JDK和JRE 二.基础知识 ...
- Java基础语法之变量、运算符、流程控制、数组和方法等基础语法
变量.运算符.流程控制.数组和方法等基础语法.Java程序的执行流程,符合Java语法规则的程序. 1.1.1 Java初识 对Java进行简单介绍,Java程序如何执行,以及Java程序的结构. J ...
- day02--java基础编程:变量,数据类型,类型转换,运算规则,运算符,分支结构,循环(随机数),方法,重载,可变参数,递归,数组,冒泡排序
1 Day02–变量+数据类型+类型转换 1.1 前言 1.1.1 标识符 可以简单的理解为一个名字.在Java中,我们需要标识代码的很多元素,包括包名.类名.方法.字段.变量等.我们选择的名称就称为 ...
- day02--java基础编程:变量,数据类型,类型转换,运算规则,Scanner,运算符,分支结构,循环(随机数),方法,重载,可变参数,递归,数组,冒泡排序
1 Day02–变量+数据类型+类型转换 1.1 前言 1.1.1 标识符 可以简单的理解为一个名字.在Java中,我们需要标识代码的很多元素,包括包名.类名.方法.字段.变量等.我们选择的名称就称为 ...
最新文章
- Linux内核分析--理解进程调度时机、跟踪分析进程调度和进程切换的过程
- GIT:本地有更改,但强制作远程仓库里作更新
- 信息化建设工程的有效成本及定价分析(1)
- java企业网站源码,模版,有前后台,springmvcSSM,生成静态化
- unity3d做会减少的血条_Unity3d中NGUI加强版血条(Healthbar)的制作
- ie传递给系统调用的数据区域太小_【Linux系列】系统调用
- Java并发编程—常见面试题
- 金融数据分析与挖掘实战1.4.4-1.5.1
- php查看当前运行使用的是哪个php.ini
- Linux Semaphore
- 中南大学-大学生心理健康教育-MOOC/雨课堂-图片版答案(期末测试)
- 不只是整体OTA,原生全宅智能颠覆了我的想象!
- 底部任务栏桌面计算机怎么删除,桌面下方的任务栏总是隐藏怎么办
- aspcms cookies欺骗和后台无验证注入
- UVM-TLM通信机制(四)
- 2021-2027全球与中国可待因止疼药市场现状及未来发展趋势
- 共享wifi流量主小程序项目
- python报错TypeError: must be str, not int
- Arduino+MAX4080S制作小量程电流表
- week7 PyCharm和Flask初应用