Functions
Declaring functions
Functions are declared with fn, parameters are name: Type, and the return type follows ->:
fn add(a: i64, b: i64) -> i64 {
a + b
}
fn greet(name: String) {
println(f"Hello, {name}!");
}
- The last expression in the body is the return value. No
returnkeyword needed. - If a function doesn't return a value, omit the
-> Type. - Use
returnfor early exits:
fn first_positive(numbers: Vec[i64]) -> Option[i64] {
for n in numbers {
if n > 0 {
return Some(n);
}
}
None
}
Expressions, not statements
Almost everything in Kāra is an expression that produces a value. if/else is an expression:
fn abs(x: i64) -> i64 {
if x >= 0 { x } else { -x }
}
match is an expression:
fn describe(n: i64) -> String {
match n {
0 => "zero",
1..=9 => "single digit",
_ => "big number",
}
}
This means you rarely need temporary variables — you can use control flow inline wherever a value is expected.
Parameter modes: the compiler helps
Here's a function that reads a string but doesn't consume it:
fn count_words(text: String) -> u64 {
text.split(' ').len()
}
You wrote text: String, but the compiler notices that text is only read, never moved or mutated. It automatically infers that text should be passed by reference. The caller doesn't make a copy; count_words borrows the string.
You can also be explicit:
fn count_words(text: ref String) -> u64 {
text.split(' ').len()
}
Both versions behave identically. The inference just saves you the annotation. We'll cover ownership in depth in Chapter 12.
Methods
Functions can be attached to types using impl blocks:
struct Circle {
radius: f64,
}
impl Circle {
fn area(ref self) -> f64 {
3.14159 * self.radius * self.radius
}
fn scale(mut ref self, factor: f64) {
self.radius = self.radius * factor;
}
fn new(radius: f64) -> Circle {
Circle { radius }
}
}
ref self— the method borrows the value (reads only).mut ref self— the method borrows mutably (can modify fields).- No
selfparameter — it's an associated function (like a static method). Call it asCircle.new(5.0).
Methods use Universal Function Call Syntax (UFCS). These two calls are the same:
let c = Circle.new(5.0);
c.area() // method syntax
Circle.area(c) // function syntax — same thing