一句话先给结论
在仓颉里,?
是 Option 的"安全导航符";它能无缝插进任何"取值/调用/下标/代码块"场景,遇到 None 就立即短路返回 None,否则继续往后走。
下面带你一次看全所有花式用法。
基础规则速查表
符号 | 意义 | 是否可接 ? |
短路行为 |
---|---|---|---|
. |
成员访问 | ✅ | None 时跳过成员访问 |
() |
函数/方法调用 | ✅ | None 时跳过调用 |
[] |
下标取值 | ✅ | None 时跳过取下标 |
{} |
lambda/闭包 | ✅ | None 时跳过闭包执行 |
场景示例
方法返回Option类型
cangjie
func readFile(): ?String {
None<String>
}
let cache: Option<String> = readFile()
?.
访问成员变量
cangjie
import std.random.Random
let rand = Random()
struct User {
User(let name: String) {}
}
func getUser(): ?User {
if (rand.nextBool()) {
User("unravel")
} else {
None
}
}
let u: Option<User> = getUser() // 可能 None
let len = u?.name.size // Option<Int>
?()
调用函数
cangjie
func twice(x: Int64): Int64 {
x * 2
}
let f: Option<(Int64) -> Int64> = Some(twice)
let r = f?(10) // Some(20)
?[]
访问下标
cangjie
// 安全下标
let arr: Option<Array<Int64>> = Some([7, 8, 9])
// arr存在时才可以返回值,不能保证下标越界的崩溃
let second = arr?[1] // Some(8)
?{}
传入尾随闭包
cangjie
type IntCallFunc = ((Int64) -> Int64) -> Int64
func opFunc(action: (Int64) -> Int64): Int64 {
action(5)
}
let op: ?IntCallFunc = opFunc
let doubled = op? {
x => x * 2
} // Some(10)
链式混写------一次写完所有符号
cangjie
type IntCallFunc = ((Int64) -> Int64) -> Int64
func opFunc(action: (Int64) -> Int64): Int64 {
action(5)
}
class ContainerItem {
func compute(): ?IntCallFunc {
return opFunc
}
}
class Container {
Container(public let items: Array<?ContainerItem>) {}
}
// 链式混写------一次写完所有符号
let deep: Option<Container> = Container([ContainerItem()])
// 安全导航:取值→下标→调用→闭包
let result = deep?.items[0]?.compute()? {x => x + 1}
与 match 组合:把最终 None 转成默认值
当然,更建议使用coalescing操作符。coalescing操作符和下面的实现等价
cangjie
let final0 = result ?? -1
let final = match (result) {
case Some(v) => v
case _ => -1
}
配合标准库ifSome、ifNone使用
cangjie
ifSome(cache) {
c => println("拿到缓存 ${c}")
}
ifNone(cache) {
println("没有拿到缓存")
}
多层嵌套 struct 一路点下去
cangjie
struct A {
A(let b: Option<B>) {}
}
struct B {
B(let c: Option<C>) {}
}
struct C {
C(let value: Int64) {}
}
let a: Option<A> = A(B(C(64)))
let v = a?.b?.c?.value // Option<Int64>
数组元素本身是 Option
cangjie
let opts: Array<Option<Int64>> = [Some(1), None, Some(3)]
let heads = opts[1] // 先取下标 → 得到 None
ifSome(heads) {
v => println("heads的值是${v}")
}
高阶函数指针
cangjie
type Fn = (Int64) -> Option<Int64>
let maybeFn: Option<Fn> = Some({x => Some(x * 3)})
let out = maybeFn?(7) // Some(21)
自定义下标运算符
cangjie
extend<T> Array<T> {
public operator func [](idx: Int64, action: (T) -> T): T {
if (idx >= 0 && idx < size) {
let v = this[idx]
action(v)
} else {
throw Exception("下标越界")
}
}
} // Some(30)
let data = Some([10, 20])
let x = data?[1, {
v => v + 10
}]
一张图记住所有写法
text
Option<T> 变量 ──→ ? ──→ .member → Option<U>
│ │()
│ │[]
│ │{ ... }
│ │
└─→ 任意一环 None 就整体返回 None