Skip to content

Instantly share code, notes, and snippets.

@bmcorser
Created May 29, 2015 12:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bmcorser/b7bb08466799acddf317 to your computer and use it in GitHub Desktop.
Save bmcorser/b7bb08466799acddf317 to your computer and use it in GitHub Desktop.

I found understanding Rust types really confusing, so I wrote up a small tutorial for myself in an attempt to understand some of them. This is by no means exhaustive. There is a types section in the manual, but it has nowhere near enough examples.

I'm not talking about managed pointers (@) at all. A lot of the difficulty with Rust types is that the language is constantly changing, so this will likely be out of date soon.

First, a few preliminaries: it's easier to play with types if you have a REPL and can interactively check the types of objects. This isn't really possible in Rust, but there are workarounds.

To start out: some help

How to get a Rust REPL

There is no working Rust REPL. However, you can use this script to approximate one -- it compiles what you put into it and prints the result. You can't use the results of what you did previously, though. Save as rustci.

How to find the type of a variable

If you want to find the type of a variable y, run:

let x: () = y;

This will generate a compiler error with the type of y. This is a hack, but as I understand it it's the best workaround for now.

For example, to find the type of a function in our fake REPL, you can do

fn f() {}; let x: () = f;

This will give us the error:

error: mismatched types: expected `()` but found `fn()` (expected () but found extern fn)

which tells us that the type of f is fn(). Yay!

The types!

Primitive types

This is an incomplete list.

Integers (signed and unsigned): int, uint, i8, i16, i32, i64, u8, u16, u32, u64

Floats: f32, f64

Booleans: bool

Primitive type examples

let x: uint = 2;
let y: u8 = 40;
let z: f32 = abc;

Vectors

There are 3 possible types for a vector of u8: [u8, ..N], &[u8], ~[u8].

[u8] by itself is not a type.

[u8, ..5] is a fixed-size vector of u8 of length 5.

Vector Examples

// Fixed size vector
let x : [uint, ..10] = [5, ..10]; // [5,5,5,5,5,5,5,5,5,5]

// Create a variable size owned vector
let mut numbers1 : ~[uint]= ~[0, 1, 2, 3, 4, 5];

// Create a variable size borrowed vector. This is also called a "vector slice".
let mut numbers2 : &[uint]= &[0, 1, 2];
let mut slice: &[uint] = numbers1.slice(0, 3);

Strings and characters

Some string types include: &str, ~str, and &'static str.

A string is represented internally as a vector of bytes. However, str by itself is not a type, and there are no fixed-size strings. You can convert any of the string types to a byte vector &[u8].

char is a 32-bit Unicode character.

String Examples

use std::option::Option;
// Static string
let hello: &'static str = "Hello!";
let hello2: &str = "Hello!";

// Owned string
let owned_hello: ~str = ~"Hello!";

// Borrowed string
let borrowed_hello = &owned_hello;

// Character
let c: char = 'a';

// Indexing into a string gives you a byte, not a character.
let byte: u8 = owned_hello[1];

// You need to create an iterator to get a character from a string.
let c: Option<char> = owned_hello.chars().nth(2);

// Switch to the string's representation as bytes
let bytes: &[u8] = owned_hello.as_bytes();

Functions

For a function fn(a: A) -> B

fn(A)->B is a type, So are &(fn(A)->B), ~(fn(A)->B), but you need to add parens right now.

You probably only want to use fn(A)->B, though.

Function type examples

fn foo(a: int) -> f32 {
    return 0.0;
}
let bar: fn(int) -> f32 = foo; 
let baz: &(fn(int) -> f32) = &foo;

Closures

The type of a closure mapping something of type A to type B is |A| -> B. A closure with no arguments or return values has type ||.

Closure type examples

let captured_var = 10; 
let closure_no_args = || println!("captured_var={}", captured_var); 
let closure_args = |arg: int| -> int {
  println!("captured_var={}, arg={}", captured_var, arg); 
  arg
};

// closure_no_args has type ||
// closure_args has type |int| -> int

fn call_closure(c1: ||, c2: |int| -> int) {
  c1();
  c2(2);
}

call_closure(closure_no_args, closure_args);

Raw pointers

For any type T, *T is a type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment