Enum
This section describes the enum
type in Cangjie. The enum
type provides a way to define a type by enumerating all possible values of the type.
Many programming languages feature an enum
type (sometimes referred to as an enumerated type), but the usage and expressive capabilities of the enum
type vary across languages. In Cangjie, the enum
type may be understood as an algebraic data type in a functional programming language.
The following describes how to define and use enum
types, how to use pattern matching to perform different operations when an enum
is set to different values, and how to use a common enum
type named Option
to indicate that an instance of a type may or may not contain a value.
Defining an Enum
An enum
type is defined by listing all possible values. These values are called the constructors
of the enum
type.
enum RGBColor {
| Red | Green | Blue
}
An enum
definition starts with the keyword enum
, followed by a type name, and then an enum
body in braces. The enum
body contains several constructors which are separated by |
(the |
before the first constructor is optional). In the preceding example, an enum
type named RGBColor
is defined. It has three constructors: Red
, Green
, and Blue
, representing the colors in the RGB color model.
The constructors in the above enum
can also carry one or more parameters, making them parameterized constructors. For example, you can set a parameter of the UInt8
type for Red
, Green
, and Blue
to represent the brightness level of each color.
enum RGBColor {
| Red(UInt8) | Green(UInt8) | Blue(UInt8)
}
Cangjie allows multiple constructors with the same name within the same enum
, provided the number of parameters is different (considering that a constructor with no parameters has a parameter count of 0
). For example:
enum RGBColor {
| Red | Green | Blue
| Red(UInt8) | Green(UInt8) | Blue(UInt8)
}
enum
definitions can be recursive. In the following example, enum
is used to define a type of expressions (Expr
). An expression can take only three forms: a single number Num
(with a parameter of the Int64
type), an addition expression Add
(with two parameters of the Expr
type), or a subtraction expression Sub
(with two parameters of the Expr
type). The Add
and Sub
constructors recursively use Expr
itself in their parameters.
enum Expr {
| Num(Int64)
| Add(Expr, Expr)
| Sub(Expr, Expr)
}
In addition, a series of member functions, operator functions (for details, see Operator Overloading), and member properties (for details, see Properties) can be defined in the enum
body. However, the names of constructors, member functions, and member properties must be unique. For example, the following example defines a function named printType
in RGBColor
, which outputs the string RGBColor
:
enum RGBColor {
| Red | Green | Blue
public static func printType() {
print("RGBColor")
}
}
Note:
enum
definitions can only appear at the top level of a source file.- When there is a mutually recursive relationship between
enum
andstruct
types, and theenum
type is used as a type parameter ofOption
, compilation errors may occur.
Using an Enum
After defining an enum
type, instances of it can be created through one of its constructors, either directly or qualifying it with the type name as TypeName.Constructor
. Unlike struct
and class
types, an enum
type name cannot be used as a constructor. For parameterized constructors, all the parameters must be provided.
In the following example, RGBColor
defines three constructors: two without parameters (Red
and Green
) and one with a parameter (Blue(UInt8)
). main
defines three variables r
, g
, and b
of the RGBColor
type. The value of r
is initialized using RGBColor.Red
, the value of g
is initialized using Green
, and the value of b
is initialized using Blue(100)
.
enum RGBColor {
| Red | Green | Blue(UInt8)
}
main() {
let r = RGBColor.Red
let g = Green
let b = Blue(100)
}
When the type name is omitted, the names of enum
constructors may conflict with type names, variable names, or function names. In this case, you must add the enum
type name to specify the enum
constructor. Otherwise, only type, variable, and function definitions with the same name are used.
In the following example, only the constructor Blue(UInt8)
can be used without the type name. Red
and Green(UInt8)
cannot be directly used due to name conflict and must be prefixed with the type name RGBColor
.
let Red = 1
func Green(g: UInt8) {
return g
}
enum RGBColor {
| Red | Green(UInt8) | Blue(UInt8)
}
let r1 = Red // Will choose 'let Red'
let r2 = RGBColor.Red // Ok: constructed by enum type name
let g1 = Green(100) // Will choose 'func Green'
let g2 = RGBColor.Green(100) // Ok: constructed by enum type name
let b = Blue(100) // Ok: can be uniquely identified as an enum constructor
In the following example, only the constructor Blue
cannot be directly used due to name conflicts and must be prefixed with the type name RGBColor
.
class Blue {}
enum RGBColor {
| Red | Green(UInt8) | Blue(UInt8)
}
let r = Red // Ok: constructed by enum type name
let g = Green(100) // Ok: constructed by enum type name
let b = Blue(100) // Will choose constructor of 'class Blue' and report an error