四种方法:1,传播错误.

import net.http

fn f(url string) ?string {
	resp:=http.get(url)?//返回<?http.Response>
	return resp.text
}

?会传播给调用者(f).内部有个?外部也得有?.如果传播,则恐慌了.其为下面的缩写版本:

resp := http.get(url) or { return err }//返回
    return resp.text

2,打断执行:

user := repo.find_user_by_id(7) or { return }

或块中用panic()或exit()来终止程序.或用控制语句(中,断,下)该域退出.断/下只能用于for块.
V不能解包.如rustunwrap()swift!.用or { panic(err.msg) }.
3,或块中提供默认值.要求必须类型一致.

fn do_something(s string) ?string {
	if s == "foo" {
		return "foo"
	}
	return error("无效串") 
// 也可为`return none`
}

a := do_something("foo") or { "default" } 
// a 将为"foo"
b := do_something("bar") or { "default" } 
// b 将为"default"
println(a)
println(b)

4,用if来解包.

import net.http

if resp := http.get("https://google.com") {
	println(resp.text) //非可选
//响应仅出现在`如块`
} else {
	println(err)//打印错误,
//而错误仅出现在异块.
}
泛型
struct Repo<T> {
    db DB
}

struct User {
	id   int
	name string
}

struct Post {
	id   int
	user_id int
	title string
	body string
}

fn new_repo<T>(db DB) Repo<T> {
    return Repo<T>{db: db}
}

//这是泛型函数,对每个用的类型生成相应函数
fn (r Repo<T>) find_by_id(id int) ?T {
    table_name := T.name //取表名.
    return r.db.query_one<T>("select * from $table_name where id = ?", id)
}

db := new_db()
users_repo:=new_repo<User>(db)//中Repo<User>
posts_repo:=new_repo<Post>(db)//中Repo<Post>
//这里用了泛型
user := users_repo.find_by_id(1)? // find_by_id<User>
post := posts_repo.find_by_id(1)? // find_by_id<Post>

当前,泛型定义必须用类型参数,未来能从单字母推导泛型.

fn compare<T>(a T, b T) int {
	if a < b {
		return -1
	}
	if a > b {
		return 1
	}
	return 0
}

// compare<int>
println(compare(1, 0)) // 输出: 1
println(compare(1, 1)) //          0
println(compare(1, 2)) //         -1
// compare<string>
println(compare("1", "0")) // 输出: 1
println(compare("1", "1")) //          0
println(compare("1", "2")) //         -1
// compare<f64>
println(compare(1.1, 1.0)) // 输出: 1
println(compare(1.1, 1.1)) //          0
println(compare(1.1, 1.2)) //         -1
并行

与Go类似.go 函数.

import math

fn p(a f64, b f64) { //无返回类型普通函数
	c := math.sqrt(a * a + b * b)
	println(c)
}

fn main() {
	go p(3, 4)
	//在其他线程运行p函数
}

有时要等待完成.

import math

fn p(a f64, b f64) { 
	c := math.sqrt(a * a + b * b)
	println(c) // 打印`5`
}

fn main() {
	h := go p(3, 4)
	h.wait()//等待完成
	// p()已完成
}

可取返回值:

import math { sqrt }

fn get_hypot(a f64, b f64) f64 { //返回值
	c := sqrt(a * a + b * b)
	return c
}//普通函数

fn main() {
	g := go get_hypot(54.06, 2.08) //产生线程并处理
	h1 := get_hypot(2.32, 16.74) //本地执行
	h2 := g.wait() //新线程等待结果
//自己完成后,等待别人完成
	println("结果: $h1, $h2") //打印`Results: 16.9, 54.1`
}//就像两个人完成任务一样.

用线程数组管理大量任务:

import time

fn task(id int, duration int) {
	println("开始 $id ")
	time.sleep(duration * time.millisecond)
	println("结束 $id ")
}

fn main() {
	mut threads := []thread{}
	threads << go task(1, 500)
	threads << go task(2, 900)
	threads << go task(3, 100)
//大概是先压下去,再执行.
	threads.wait()//等待他们完成
	println("done")
}

返回相同类型线程,在线程数组上调用wait,等待完成计算.

fn expensive_computing(i int) int {
	return i * i
}

fn main() {
	mut threads := []thread int{}
	for i in 1 .. 10 {
		threads << go expensive_computing(i)
	}
	//合并 
	r := threads.wait()
	println("都完成: $r")//得到的是已完成的数组值.
//[1, 4, 9, 16, 25, 36, 49, 64, 81]
}

通道是协程通信的首选,与go一样,你可把对象压至通道一端,并从另一端取出来.可/不必缓冲通道,也能从多通道选择1个.
用法:
chan objtype,

ch := chan int{} // 未缓冲的同步
ch2 := chan f64{cap: 100} //100长缓冲通道.
//cap,声明通道长度.

不必声明通道为,缓冲长不是通道类型,而是独立通道对象的属性.可像普通变量一样传递通道协程.

fn f(ch chan int) {
	// ...
}

fn main() {
	ch := chan int{}
	go f(ch)
	// ...
}

可用<-压对象至通道,同样用<-来弹出.

//造缓冲通道,这样压时,通道有空间时不阻塞.
ch := chan int{cap: 1}
ch2 := chan f64{cap: 1}
n := 5
// 压
ch <- n
ch2 <- 7.3
mut y := f64(0.0)
m := <-ch // 弹至新变量
y = <-ch2 // 弹至旧变量

可关闭通道来禁止推.推对象恐慌.已关闭通道且为空,弹时则立即返回.可用或分支来处理.

ch := chan int{}
ch2 := chan f64{}
// ...
ch.close()
// ...
m := <-ch or {
    println("已关闭")
}

// 传播错误.
y := <-ch2 ?

选择命令可低成本监控多通道.其类似匹配,由传输和语句关联分支列表构成.

import time

fn main() {
	ch := chan f64{}
	ch2 := chan f64{}
	ch3 := chan f64{}
	mut b := 0.0
	c := 1.0
	// ... 安装将在ch/ch2上发送的go线程.
	go fn (the_channel chan f64) {
		time.sleep(5 * time.millisecond)
		the_channel <- 1.0
	}(ch)
	go fn (the_channel chan f64) {
		time.sleep(1 * time.millisecond)
		the_channel <- 1.0
	}(ch2)
	go fn (the_channel chan f64) {
		_ := <-the_channel
	}(ch3)
	//
	select {
		a := <-ch {
			// 用`a`干活
			eprintln("> a: $a")
		}
		b = <-ch2 {
			//用预声明b干活
			eprintln("> b: $b")
		}
		ch3 <- c {
			//发送`c`时干活
			time.sleep(5 * time.millisecond)
			eprintln("在3声道发送> c: $c ")
		}
		> 500 * time.millisecond {
			//半秒内通道都没准备好,则
			eprintln("啊啊")
		}
	}
	eprintln("> 完成")
}

超时分支可选.不存在,则一直等待.也可用异分支来处理未准备好通道的情况.超时排外的.
选择命令可按所有通道关闭时变为极类型的表达式用.

if select {
    ch <- a {
        // ...
    }
} {
    //打开通道 
} else {
    // 关闭通道
}
特殊通道

特殊通道有些内置属性和方法,

struct Abc {
	x int
}

a := 2.13
ch := chan f64{}
res := ch.try_push(a) // try to perform `ch <- a`
println(res)
l := ch.len //队列中元素数
c := ch.cap //最大队列长
is_closed := ch.closed // 极标志,是否关闭
println(l)
println(c)
mut b := Abc{}
ch2 := chan Abc{}
res2 := ch2.try_pop(mut b) // 试着`b = <-ch2`

试压/弹.success,.not_ready或.closed时立即返回.由是否转移对象或原因决定.
生产中不推荐使用他们,可能有竞争.特别是不要用.len/.closed来做决定,应用或分支/错误传播/选择来替代.