基础类型内存宽度以及表示范围

bool

1Byte true/false

uint8

1Byte 0-255

uint16

2Byte 0-65535

uint32

4Byte 0-4294967295

uint64

8Byte 0-18446744073709551615

int8

1Byte -128-127

int16

2Byte -32768-32767

int32

4Byte -2147483648-2147483647

int64

6Byte -9223372036854775808-9223372036854775807

byte

1Byte 类似 uint8

rune

4Byte 类似 int32

uint

4Byte / 8Byte 32 或 64 位

int

4Byte / 8Byte 与 uint 一样大小

float32

4Byte

float64

8Byte

string

1Byte (英文) / 2Byte-4Byte(中文,取决于字符编码类型)
切片拼接
slice1 := []int{0, 1, 2, 3}
slice2 := []int{3, 4, 5}

slice1 = append(slice1, slice2...)
fmt.Println(slice1)

//[0 1 2 3 3 4 5]
bit Byte

bit:计算机记忆的最小单位,一个bit可以代表0或1

Byte:一个Byte8bits所组成

1Byte=8Bits

1KB=1024Bytes

时间转换

字符串转时间

time.Parse()

时间转字符串

time.Format()

时间转时间戳

Time.Unix()

时间戳转时间

time.Unix()
计时

朴素方法

	startTime := time.Now()
	//do something
	time.Sleep(time.Second)
	duration := time.Since(startTime)
	fmt.Printf("经过时间:%v\n", duration)
	
//经过时间:1.005046959s

简洁方法

// TimeCost 耗时统计函数
func TimeCost(start time.Time) {
	duration := time.Since(start)
	fmt.Printf("经过时间:%v\n", duration)
}

	defer TimeCost(time.Now())
	//do something
	time.Sleep(time.Second)
	
//经过时间:1.005054375s

优雅方法

// TimeCost 耗时统计函数
func TimeCost() func() {
	start := time.Now()
	return func() {
		duration := time.Since(start)
		fmt.Printf("经过时间:%v\n", duration)
	}
}

	defer TimeCost()()
	//do something
	time.Sleep(time.Second)
	
//经过时间:1.005033916s
时间的加减法
	// Add 时间相加
	now := time.Now()
	// ParseDuration parses a duration string.
	// A duration string is a possibly signed sequence of decimal numbers,
	// each with optional fraction and a unit suffix,
	// such as "300ms", "-1.5h" or "2h45m".
	//  Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
	// 10分钟前
	m, _ := time.ParseDuration("-1m")
	m1 := now.Add(m)
	fmt.Println(m1)

	// 8个小时前
	h, _ := time.ParseDuration("-1h")
	h1 := now.Add(8 * h)
	fmt.Println(h1)

	// 一天前
	d, _ := time.ParseDuration("-24h")
	d1 := now.Add(d)
	fmt.Println(d1)

	// 10分钟后
	mm, _ := time.ParseDuration("1m")
	mm1 := now.Add(mm)
	fmt.Println(mm1)

	// 8小时后
	hh, _ := time.ParseDuration("1h")
	hh1 := now.Add(hh)
	fmt.Println(hh1)

	// 一天后
	dd, _ := time.ParseDuration("24h")
	dd1 := now.Add(dd)
	fmt.Println(dd1)

	// Sub 计算两个时间差
	subM := now.Sub(m1)
	fmt.Println(subM.Minutes(), "分钟")

	sumH := now.Sub(h1)
	fmt.Println(sumH.Hours(), "小时")

	sumD := now.Sub(d1)
	fmt.Printf("%v 天\n", sumD.Hours()/24)
go get 下载指定版本
go get github.com/ormissia/go-opv@v0.0.2
go chan close

gochan中,chan被关闭后,消费者会继续读取channel中的消息。直到消息被全部读取之后使用i, ok := <-ch得到的ok才会变为false

下面是测试代码以及运行时控制台打印结果:

func main() {
	ch := make(chan int, 3)

	go producer(ch)

	for {
		i, ok := <-ch
		fmt.Printf("consume msg: %d\tok: %v\n", i, ok)
		time.Sleep(time.Second * 3)
	}

}

func producer(ch chan int) {
	for i := 0; i < 10; i++ {
		ch <- i
		fmt.Printf("produce msg: %d\n", i)
		time.Sleep(time.Second)
	}
	close(ch)
	fmt.Println("chan closed")
}

输出结果

produce msg: 0
consume msg: 0	ok: true
produce msg: 1
produce msg: 2
consume msg: 1	ok: true
produce msg: 3
produce msg: 4
consume msg: 2	ok: true
produce msg: 5
consume msg: 3	ok: true
produce msg: 6
consume msg: 4	ok: true
produce msg: 7
consume msg: 5	ok: true
produce msg: 8
consume msg: 6	ok: true
produce msg: 9
chan closed
consume msg: 7	ok: true
consume msg: 8	ok: true
consume msg: 9	ok: true
consume msg: 0	ok: false
consume msg: 0	ok: false
异或
  • 异或运算法则:无进位相加
  • 异或运算性质:
    • 0 ^ N = N
    • N ^ N = 0
    • 满足交换律和结合律
a := 0b1100
b := 0b1001
fmt.Printf("%b",a^b)
//101

简单应用:不申请额外内存交换两个变量的值

a := 0b1100
b := 0b1001

a = a ^ b
b = a ^ b //b = (a ^ b) ^ b = a
a = a ^ b //a = (a ^ b) ^ a = b
fmt.Printf("a:%b,b:%b", a, b)
//a:1001,b:1100

堆的实质是一棵完全二叉树

堆可分为两种类型:

  • 大根堆:所有子树的根节点均为最大值
  • 小根堆:所有子树的根节点均为最小值

一般情况下堆可以用一个有序数组来存储
[0…i…n] i节点的左孩子index2*i+1,右孩子为2i+2,父节点为(i-1)/2

也有一种特例是从1开始(位运算比加减法快)
[01…i…n] i节点的左孩子index2*ii<<1,右孩子为2i+1i<<1|1,父节点为i/2

  • 堆的基本操作:
    • 上浮
    • 下沉
  • 堆的插入弹出
    • 插入
      1. 在最后插入节点
      2. 依次上浮
    • 弹出
      1. 弹出根节点
      2. 将最后一个节点放入根节点
      3. 将根节点下沉
  • 堆排序
    • 依次弹出根节点
Strings

test

String str = "123";
函数

函数参数为val类型,且可以给出默认值

def test(a: Int, b: Int = 1, c: Int = 2): Unit = {
  println(s"$a $b $c")
}
  
test(1, 2)      //1 2 2
test(1, c = 4)  //1 1 4
匿名函数

函数是带有参数的表达式。

(x: Int) => x + 1
方法

方法的表现和行为和函数非常类似,但是它们之间有一些关键的差别。

方法由def关键字定义。def后面跟着一个名字、参数列表、返回类型和方法体。

def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier
println(addThenMultiply(1, 2)(3)) // 9
字符串拼接
val a = 1
val b = 2
val c = s"$a+$b=${a + b}"
对象

约等于static单例对象

object TestObj {
  def main(args: Array[String]): Unit = {
    val a = 1
    val b = 2
    val c = s"$a+$b=${a + b}"
    println(c)
  }
}

可以使用class关键字定义一个类,后面跟着它的名字和构造参数。

  • 类里裸露的代码是默认构造中的
  • 类名构造器中的参数就是类的成员属性,默认是val类型,且是private
  • 只有在类名构造器中的参数可以设置成var,其他方法函数中的参数都是val类型的,且不允许设置成var类型
class Greeter(prefix: String, var suffix: String) {
  var name = "name"

  def greet(name: String): Unit =
    println(prefix + name + suffix)
}
循环

scala中嵌套for循环可以写到一起,循环上可以加守卫(条件)。 循环结果可以通过yield收集到一个集合中

// val value = for (i <- 1 to 9; j <- 1 to i) yield {
val value = for (i <- 1 to 9; j <- 1 to 10 if (j <= i)) yield {
  i * j
}
for (i <- value) {
  println(i)
}
偏应用函数

类似于重新封装一下函数

def log(date: Date, logType: String, msg: String): Unit = {
  println(s"$date\t$logType\t$msg")
}

val info = log(_, "info", _)
info(new Date, "this is a info msg")  //Thu Jul 22 23:14:04 CST 2021	info	this is a info msg
可变长度参数以及foreach
def foreachTest(a: Int*): Unit = {
  //for (i <- a) {
  //  print(i)
  //}

  //a.foreach((x: Int) => {
  //  print(x)
  //})

  //a.foreach(print(_))
  a.foreach(print)
}

foreachTest(1, 2, 3, 4, 5)  //12345
高阶函数

函数作为参数

def computer(a: Int, b: Int, f: (Int, Int) => Int): Unit = {
  val res = f(a, b)
  println(res)
}

computer(1, 2, (x: Int, y: Int) => {x + y}) //3
computer(1, 2, _ + _)                       //3

函数作为返回值

def factory(i: String): (Int, Int) => Int = {
  def plus(x: Int, y: Int): Int = {
    x + y
  }

  if (i.equals("+")) {
    plus
  } else {
    _ * _
  }
}

val plus = factory("+")
computer(1,2,plus)  //3
柯里化

多个参数列表

def testFunc(a:Int*)(b:Int*)(c:String*): Unit ={
  a.foreach(print)
  b.foreach(print)
  c.foreach(print)
}

testFunc(1,2,3)(2,3,4)("3","4","5") //123234345
数组

数组 scala中泛型是[],数组用()

val约等于final,不可变描述的是val指定的引用(字面值、地址)

val arr1 = Array[Int](1, 2, 3)
arr1(1) = 99
println(arr1(1))  //99

遍历


for (elem <- arr1) {}
//foreach需要函数接收元素
arr1.foreach(println)
链表

scalacollections中有两个包:immutable,mutable,默认是不可变的immutable

val list1 = List(1, 2, 3, 4)

//++ += ++: :++
val list2 = new ListBuffer[Int]
list2.+=(1)
list2.+=(2)
list2.+=(3)
val list1 = List(1, 2, 3, 4)
val list2 = list1.map(_ * 2)
list2.foreach(print) //2468
Set

Set

不可变的

val set1 = Set(1, 2, 3, 4, 1, 2)  //1 2 3 4

可变的

val set2 = mutable.Set(1, 2, 3, 4, 1, 2)
set2.add(1)
set2.add(5) //1 2 3 4 5
Map

Map

val map1 = Map(("a", 1), "b" -> 2, ("c", 3), ("a", 4))

map1.foreach(print) //(a,4)(b,2)(c,3)
println(map1.get("a")) //Some(4)
println(map1.get("d")) //None
println(map1.getOrElse("a", "test")) //4
println(map1.getOrElse("d", "test")) //test

val keys = map1.keys
keys.foreach(println)

遍历

for (m <- map1) {
  print(s"$m")
}
for (k <- keys) {
  print(s"($k,${map1(k)})")
}

可变的

val map2 = mutable.Map(("a", 1), "b" -> 2, ("c", 3), ("a", 4))
map2.put("a", 5)
案例类
模式匹配
特质
偏函数
隐式转换
函数

在 python 中,类型属于对象,变量是没有类型的:

a=[1,2,3]
a="ormissia"

以上代码中,[1,2,3]List类型,"ormissia"String类型,而变量a是没有类型,他仅仅是一个对象的引用(一个指针),可以是指向List类型对象,也可以是指向String类型对象。

可更改(mutable)与不可更改(immutable)对象

在python中,stringstuplesnumbers是不可更改的对象,而listdict等则是可以修改的对象。

  • 不可变类型:变量赋值a=5后再赋值a=10,这里实际是新生成一个int值对象10,再让a指向它,而5被丢弃,不是改变a的值,相当于新生成了a

  • 可变类型:变量赋值la = [1,2,3,4]后再赋值la[2] = 5则是将list la的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。

python函数的参数传递:

  • 不可变类型:类似C++的值传递,如整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。如果在fun(a)内部修改a的值,则是新生成一个a的对象。

  • 可变类型:类似C++的引用传递,如列表,字典。如fun(la),则是将la真正的传过去,修改后fun外部的la也会受影响

python中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

函数
按年月日分组聚合
group by date_format(field_name, format);

根据format字符串格式化date值。下列修饰符可以被用在format字符串中:

%M 月名字(January……December) 
%W 星期名字(Sunday……Saturday) 
%D 有英语前缀的月份的日期(1st, 2nd, 3rd, 等等。) 
%Y 年, 数字, 4%y 年, 数字, 2%a 缩写的星期名字(Sun……Sat) 
%d 月份中的天数, 数字(00……31) 
%e 月份中的天数, 数字(0……31) 
%m 月, 数字(01……12) 
%c 月, 数字(1……12) 
%b 缩写的月份名字(Jan……Dec) 
%j 一年中的天数(001……366) 
%H 小时(00……23) 
%k 小时(0……23) 
%h 小时(01……12) 
%I 小时(01……12) 
%l 小时(1……12) 
%i 分钟, 数字(00……59) 
%r 时间,12 小时(hh:mm:ss [AP]M) 
%T 时间,24 小时(hh:mm:ss) 
%S 秒(00……59) 
%s 秒(00……59) 
%p AM或PM 
%w 一个星期中的天数(0=Sunday ……6=Saturday ) 
%U 星期(0……52), 这里星期天是星期的第一天 
%u 星期(0……52), 这里星期一是星期的第一天 
%% 一个文字“%”
count统计不重复个数
select count(distinct (field_name))
from table_name
sum结果为null时置为0

SQL中使用sum统计总数时:sum(col_name),如果某列不符合sum的条件(比如某列中含有NULL元素,或者不是数值类型,或者没有符合where条件的行),那么会返回NULL 有的时候不希望sum的结果为NULL,可以做如下的处理:

SELECT COALESCE(sum(col_name), 0) FROM Table

此外还有ISNULL(SQL Server)NVL(Oracle)以及IFNULL(MySQL)的用法,起到同样的效果