Structs
Structs in Cyrus are user-defined composite types that allow grouping related data together. They are similar to struct in C/C++ but follow Cyrus' type system rules.
Defining a Struct
Use the struct keyword, followed by the name and fields:
struct User {
name: char*;
age: uint;
king: bool;
}
Initializing a Struct
Structs can be initialized using struct literals:
var user = User {
name: "Cyrus",
age: 2500,
king: true
};
Accessing Struct Fields
You can access struct fields using the dot (.) operator:
user.name; // Output: Cyrus
user.age; // Output: 2500
user.king; // Output: true
Methods
Structs can define functions inside their body, called methods.
pub struct Logger {
pub group: char*;
pub fn new(group: char*) Logger {
Logger.logger_initialized();
return Logger { group: group };
}
inline fn logger_initialized() {
libc::fprintf(libc::stdout, "Logger init.\n");
}
pub fn logf(&self, format: char*) {
libc::printf("[info][%s] %s\n", self->group, format);
}
pub inline fn errorf(self, format: char*) {
libc::fprintf(libc::stderr, "[error][%s] %s\n", self->group, format);
}
}
Static Methods
Static methods do not require a struct instance. Called on the struct type itself. It often used as constructor or helper functions.
pub fn new(group: char*) Logger {
return Logger { group: group };
}
Instance Methods
Instance methods operate on a struct instance and can access its fields.
pub fn logf(&self, format: char*) {
libc::printf("[info][%s] %s\n", self->group, format);
}
pub fn errorf(self, format: char*) {
libc::fprintf(libc::stderr, "[error][%s] %s\n", self->group, format);
}
Reference vs Copy
Cyrus allows controlling how instance methods receive the struct:
&self→ passes a reference to the instance (does not copy)self→ passes a copy of the instance (moves it)
pub fn logf(&self, format: char*) { ... } // reference
pub fn errorf(self, format: char*) { ... } // copy
Note: Attempting to get a reference (&self) from a const-lvalue is not allowed. The compiler will issue an error to prevent modifying or referencing immutable data.
Fat Arrows
In Cyrus, you can have pointers to structs. When accessing fields or calling methods through a pointer, you can use fat pointers (fat arrows) which automatically dereference the pointer.
var user = User { name: "Cyrus", age: 2500 };
var ptr = &user;
ptr->name; // Output: Cyrus
ptr->age; // Output: 2500
Note: Using ptr->name or ptr->age is equivalent to (*ptr).name and (*ptr).age.
Local Structs
In Cyrus, structs can also be declared locally inside functions. This is useful when the type is only relevant to that function and should not pollute the global scope.
fn main() {
struct User {
name: char*;
age: uint;
}
var user = User { name: "Cyrus", age: 2500 };
libc::printf("%s is %d years old.\n", user.name, user.age);
}
Unnamed Structs
Unnamed structs are struct values declared inline without defining a named type. They are useful for quick, one-off configurations or temporary data holders.
fn main() {
var state = struct {
name = "Cyrus",
counter = 0,
};
config.name;
state.counter += 1;
}
Field types are inferred automatically.
Typed Unnamed Struct
You can also specify field types explicitly:
var state = struct {
name: char* = "Cyrus",
counter: int = 0,
};
Note: Unnamed structs cannot define methods.
Global Unnamed Structs
Unnamed structs are not limited to local scope. They can also be declared globally and accessed across functions (if marked public).
pub const CONFIG = struct {
host = "127.0.0.1",
port = 8080
};
fn main() {
printf("host: %s\n", CONFIG.host);
printf("port: %d\n", CONFIG.port);
}

