This page contains usage information that is common to both the Evcxr REPL and the Evcxr Jupyter kernel.
- If your code segfaults (e.g. due to buggy unsafe code), aborts, exits etc, the process in which the code runs will be restarted. All variables will be lost.
Define functions, structs, enums, and other data types:
>> pub struct User {
username: String
}
>> let user = User { username: String::from("John Doe") };
Assign values to variables then make use of them later:
>> let x = "hello";
>> // do other things
>> println!("{}", x)
Load crates from crates.io:
>> :dep rand = { version = "0.7.3" }
>> let x: u8 = rand::random();
Note that loading large crates with many dependencies may take a while.
If you'd like to use a crate with a different name than what it's know as on crates.io, you can use
:dep any_name = { package = "crates_io_name" }
. For example, if you wanted to load the crates.io
package unicode-xid
, but refer to it locally as unicode_xid
, you could do that as follow.
:dep unicode_xid = { package = "unicode-xid", version = "*" }
use unicode_xid;
You can use the local work-in-progress crate like this:
>> :dep my_crate = { path = "." }
>> use my_crate::*;
Alternatively you can use a shorter form:
>> :dep .
>> :dep ../another_crate
>> :dep /path/to/crate
It will even automatically update when you save your files!
There are many other options that can be specified. See Cargo's official dependency documentation for details.
Nice error reporting:
>> let x = unknown();
^^^^^^ not found in this scope
cannot find function `unknown` in this scope
help: consider importing this function
Support for the ?
operator
Evcxr will automatically propagate errors caught with the ?
operator to the formatter set with :efmt
. For example:
>> let var = std::env::var("UNKNOWN")?;
NotPresent
If :efmt
is set to Debug
, this will also work for Option
:
>> [1, 2, 3].get(4)?
NoneError
Support for async-await
If you use await
in your code, evcxr will automatically build and start a Tokio runtime. You can
test this out with a trival example as follows:
>> async fn foo() -> u32 { 42 }
>> foo().await
Compiling libc v0.2.150
Compiling num_cpus v1.16.0
Compiling tokio v1.34.0
42
If you'd like to use more non-default features of tokio, then you need to add the dependency on tokio before you first try to use the await keywork. For example:
:dep tokio = {version = "1.34.0", features = ["full"]}
You can then write code that uses await and can optionally use the ?
operator as well.
The following code will attempt to connect to localhost on port 1234.
let mut stream = tokio::net::TcpStream::connect("127.0.0.1:1234").await?;
Unless you happen to have a program listening on this port, this should report the error:
Connection refused (os error 111)
If you're on Linux, you can use netcat (you may need to install it) to listen on an arbitrary port. For example:
nc -t -l 1234
Leave that running in one shell, then back in evcxr, run the following:
use tokio::io::AsyncWriteExt;
stream.write(b"Hello, world!\n").await?;
You should hopefully see the "Hello, world!" message appear in the shell where netcat (nc) is running. You can stop nc by pressing control-c.
- There is currently no way to import macros from external crates.
You can create an init.evcxr
file in the evcxr
config directory. The location of this directory varies depending on your operating system:
Linux | OSX | Windows |
---|---|---|
~/.config/evcxr |
/Users/Alice/Library/Preferences/evcxr |
C:\Users\Alice\AppData\Roaming\evcxr |
You can check the location of the config directory by running the following in the REPL:
:dep dirs
dirs::config_dir().unwrap().join("evcxr").join("init.evcxr")
Any options set in this file will be automatically loaded at startup. For example:
:timing
:dep { rand = "0.7.3" }
:dep { log = "0.4.11" }
You can also create an prelude.rs
file which will be evaluated on startup. For example:
// prelude.rs
const msg: &str = "hello";
$ evcxr
Welcome to evcxr. For help, type :help
Executing prelude from "~/.config/evcxr/prelude.rs"
>> msg
"hello"
You can optionally cache compilation outputs. To do so, add :cache {size in MB}
to your
init.evcxr
. e.g. to have a 500 MB cache, add the following:
:cache 500
To disable the cache, use :cache 0
. Running with the cache disabled doesn't clear the cache. To
clear the cache, run :clear_cache
.
The :vars
command will list all the variables defined in the current context:
>> let x = 0;
>> let y = 1;
>> :vars
y: i32
x: i32
Variables that persist cannot reference other variables. For example, you can't do this:
let all_values = vec![10, 20, 30, 40, 50];
let some_values = &all_values[2..3];
There are a few ways to mitigate this limitation. Firstly, if you don't need some_values
to
persist, you can limit its scope:
let all_values = vec![10, 20, 30, 40, 50];
{
let some_values = &all_values[2..3];
// Use some_value here
}
If you really need some_values
to persist, you can make all_values
into a static reference by
leaking it:
let all_values: &'static Vec<i32> = Box::leak(Box::new(vec![10, 20, 30, 40, 50]));
let some_values = &all_values[2..3];
Note that we need to give all_values
a type here because otherwise the type ends up being a
mutable reference, which would result in us still having borrow checker problems.
Installing the lld
linker it is recommended as it is generally faster than the default system linker. On Debian-based systems you might be able to install it with:
$ sudo apt install lld
lld
will be used automatically if detected on all systems with the exception of Mac OS. You can check which linker is being used by running :linker
.
If you'd like to try using cranelift rather than llvm to do codegen, you can do so using recent rust nightly releases.
First update your nightly toolchain with rustup update nightly
or, if you don't already have it
installed, rustup install nightly
.
Install the cranelift preview component:
rustup component add rustc-codegen-cranelift-preview --toolchain nightly
Then use the following commands from evcxr or in your init.evcxr.
:toolchain nightly
:codegen_backend cranelift
Here is a complete list of the configuration options you can set to customize your Evcxr experience:
:efmt [format]
Set the formatter for errors returned by?
:fmt [format]
Set output formatter (default:{:?}
):internal_debug
Toggle internal code debugging output:linker [linker]
Set/print linker. Supported:system
,lld
,mold
:offline [0|1]
Set offline mode when invoking cargo:opt [level]
Toggle/set optimization level:preserve_vars_on_panic [0|1]
Try to keep vars on panic:sccache [0|1]
Set whether to use sccache:time_passes
Toggle printing of rustc pass times (requires nightly):timing
Toggle printing of how long evaluations take:toolchain
Set which toolchain to use (e.g. nightly):types
Toggle printing of the type of the output
And here are the supported Evcxr commands:
:clear
Clear all state, keeping compilation cache:dep
Add an external dependency. e.g.:dep regex = "1.0"
:explain
Print the explanation of last error:help
View the help message:last_compile_dir
Print the directory in which we last compiled:last_error_json
Print the last compilation error as JSON (for debugging):load_config
Reloads startup configuration files. Accepts optional flag--quiet
to suppress logging.:quit
Quit evaluation and exit:type
|:t
Show variable type:vars
List bound variables and their types:version
Print Evcxr version