// 082: Type Aliases
// Shortening complex types with type aliases
// Approach 1: Simple aliases
type Point = (f64, f64);
type Name = String;
fn distance(p1: Point, p2: Point) -> f64 {
((p2.0 - p1.0).powi(2) + (p2.1 - p1.1).powi(2)).sqrt()
}
// Approach 2: Result alias (common pattern)
#[derive(Debug, PartialEq)]
enum AppError {
ParseError(String),
DivByZero,
}
type AppResult<T> = Result<T, AppError>;
fn parse_int(s: &str) -> AppResult<i32> {
s.parse().map_err(|_| AppError::ParseError(format!("Not a number: {}", s)))
}
fn safe_div(a: i32, b: i32) -> AppResult<i32> {
if b == 0 { Err(AppError::DivByZero) } else { Ok(a / b) }
}
// Approach 3: Complex type aliases
type Predicate<T> = Box<dyn Fn(&T) -> bool>;
type Transform<T> = Box<dyn Fn(T) -> T>;
fn filter_map_custom<T: Clone, U>(
items: &[T],
pred: &dyn Fn(&T) -> bool,
f: &dyn Fn(T) -> U,
) -> Vec<U> {
items.iter().filter(|x| pred(x)).map(|x| f(x.clone())).collect()
}
// io::Result pattern
type IoResult<T> = std::io::Result<T>;
fn main() {
println!("distance: {}", distance((0.0, 0.0), (3.0, 4.0)));
println!("parse: {:?}", parse_int("42"));
println!("div: {:?}", safe_div(10, 3));
let evens = filter_map_custom(
&[1, 2, 3, 4, 5, 6],
&|x: &i32| x % 2 == 0,
&|x: i32| x * 2,
);
println!("doubled evens: {:?}", evens);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_distance() {
assert!((distance((0.0, 0.0), (3.0, 4.0)) - 5.0).abs() < 0.001);
}
#[test]
fn test_parse_int() {
assert_eq!(parse_int("42"), Ok(42));
assert!(parse_int("abc").is_err());
}
#[test]
fn test_safe_div() {
assert_eq!(safe_div(10, 3), Ok(3));
assert_eq!(safe_div(10, 0), Err(AppError::DivByZero));
}
#[test]
fn test_filter_map() {
let result = filter_map_custom(
&[1, 2, 3, 4, 5, 6],
&|x: &i32| x % 2 == 0,
&|x: i32| x * 2,
);
assert_eq!(result, vec![4, 8, 12]);
}
}
(* 082: Type Aliases *)
(* Approach 1: Simple aliases *)
type point = float * float
type name = string
type age = int
let distance ((x1, y1) : point) ((x2, y2) : point) : float =
sqrt ((x2 -. x1) ** 2.0 +. (y2 -. y1) ** 2.0)
(* Approach 2: Result alias *)
type error = string
type 'a result_t = ('a, error) result
let parse_int (s : string) : int result_t =
match int_of_string_opt s with
| Some n -> Ok n
| None -> Error (Printf.sprintf "Not a number: %s" s)
let safe_div (a : int) (b : int) : int result_t =
if b = 0 then Error "Division by zero" else Ok (a / b)
(* Approach 3: Complex type alias *)
type 'a predicate = 'a -> bool
type 'a transform = 'a -> 'a
type ('a, 'b) mapper = 'a -> 'b
let filter_map (pred : 'a predicate) (f : ('a, 'b) mapper) lst =
lst |> List.filter pred |> List.map f
(* Tests *)
let () =
let p1 : point = (0.0, 0.0) in
let p2 : point = (3.0, 4.0) in
assert (abs_float (distance p1 p2 -. 5.0) < 0.001);
assert (parse_int "42" = Ok 42);
assert (parse_int "abc" = Error "Not a number: abc");
assert (safe_div 10 3 = Ok 3);
let is_even : int predicate = fun x -> x mod 2 = 0 in
let double : (int, int) mapper = fun x -> x * 2 in
assert (filter_map is_even double [1; 2; 3; 4; 5; 6] = [4; 8; 12]);
Printf.printf "โ All tests passed\n"