Using Options
Option Types describes the definition of the Option
type. The Option
type can be used for error handling instead of exceptions, or in conjunction with them.
For example, if the value of the argument of the getOrThrow
function is Some(v)
in the following code, the value of v
is returned. If the value of the argument is None
, an exception is thrown.
func getOrThrow(a: ?Int64) {
match (a) {
case Some(v) => v
case None => throw NoneValueException()
}
}
Because Option
is a very common type, Cangjie provides multiple deconstruction methods to facilitate its use, including pattern matching, getOrThrow
functions, coalescing
operators (??
), and question mark operators (?
). The following describes these methods one by one.
-
Pattern matching: Because the
Option
type is an enum type, enum pattern matching can be used to deconstruct anOption
value, as the sample code above has already shown. In the following example, thegetString
function receives a parameter of the?Int64
type, which is a shorthand forOption<Int64>
. When the value of the argument isSome(x)
, the function returns the string representation of the value ofx
. When the value of the parameter isNone
, the function returns the string"none"
.func getString(p: ?Int64): String{ match (p) { case Some(x) => "${x}" case None => "none" } } main() { let a = Some(1) let b: ?Int64 = None let r1 = getString(a) let r2 = getString(b) println(r1) println(r2) }
The execution result of the above code is as follows:
1 none
-
The coalescing operator
??
: For an expressione1
of the type?T
, if you want to substitute the valuee2
of the typeT
when the value ofe1
isNone
, you can use the??
operator. If the value ofe1
is equal to that ofSome(v)
, the expressione1 ?? e2
evaluates tov
, ande2
is not evaluated at all. Otherwise,e2
is evaluated and the result is used as the value of the entire coalescing expression. The following is an example:main() { let a = Some(1) let b: ?Int64 = None let r1: Int64 = a ?? 0 let r2: Int64 = b ?? 0 println(r1) println(r2) }
The execution result of the preceding code is as follows:
1 0
-
Question mark operators (
?
):?
must be used with.
,()
,[]
, or{}
(in the scenario where the trailing lambda is called) to enable theOption
type to support.
,()
,[]
, and{}
. Take.
as an example (the same applies to()
,[]
, and{}
). For an expressione
of the?T1
type, when the value ofe
isSome(v)
, the value ofe?.b
isOption<T2>.Some(v.b)
. Otherwise, the value ofe?.b
isOption<T2>.None
. In both cases,T2
is the type ofv.b
. The following is an example:struct R { public var a: Int64 public init(a: Int64) { this.a = a } } let r = R(100) let x = Some(r) let y = Option<R>.None let r1 = x?.a // r1 = Option<Int64>.Some(100) let r2 = y?.a // r2 = Option<Int64>.None
Question mark operators (
?
) support multi-layer access. The following usesa?.b.c?.d
as an example (the same applies to()
,[]
, and{}
). The type of the expressiona
must beOption<T1>
, andT1
contains the instance memberb
. The type ofb
contains the instance member variablec
, and the type ofc
isOption<T2>
.T2
contains the instance memberd
. The type of the expressiona?.b.c?.d
isOption<T3>
, whereT3
is the type of the instance memberd
ofT2
. Whena
is equal toSome(va)
andva.b.c
is equal toSome(vc)
,a?.b.c?.d
is equal toOption<T3>.Some(vc.d)
. Whena
is equal toSome(va)
andva.b.c
is equal toNone
,a?.b.c?.d
is equal toOption<T3>.None
(d
is not evaluated). When the value ofa
is equal toNone
, the value ofa?.b.c?.d
is equal toOption<T3>.None
(b
,c
, andd
are not evaluated).struct A { let b: B = B() } struct B { let c: Option<C> = C() let c1: Option<C> = Option<C>.None } struct C { let d: Int64 = 100 } let a = Some(A()) let a1 = a?.b.c?.d // a1 = Option<Int64>.Some(100) let a2 = a?.b.c1?.d // a2 = Option<Int64>.None
-
getOrThrow
functions: The expressione
of the?T
type can be deconstructed by calling thegetOrThrow
function. If the value ofe
is equal toSome(v)
,e.getOrThrow()
returns the value ofv
. Otherwise, it throws an exception. The following is an example:main() { let a = Some(1) let b: ?Int64 = None let r1 = a.getOrThrow() println(r1) try { let r2 = b.getOrThrow() } catch (e: NoneValueException) { println("b is None") } }
The execution result of the preceding code is as follows:
1 b is None