scalar_double(c(4.2, 1.3, 2.5))
#> Error in scalar_double(c(4.2, 1.3, 2.5)): Expected Scalar, got Doubles
Vector Type Mapping
Vector Type Mapping with Rust Types
What happens if we try to pass more than one value to scalar_double()
?
It errors because the function expects a scalar of the f64
type, not a vector of f64
.
In this section, we show you how to pass Rust vectors between R and Rust.
While using a Rust vector is possible in some cases, it is strongly not recommended. Instead, extendr types should be used as they provide access directly to R objectes. Whereas using Rust vectors requires additional allocations.
The syntax is basically the same as with scalars, with just some minor changes. We’ll use doubles again to demonstrate this.
For reference, below are the type of Rust vectors that can be utilized with extendr.
R type | extendr type | Rust type |
---|---|---|
integer() |
Integers |
Vec<i32> |
double() |
Doubles |
Vec<f64> |
complex() |
Complexes |
Vec<Complex<f64>> |
character() |
Strings |
Vec<String> |
raw() |
Raw |
&[u8] |
logical() |
Logicals |
|
list() |
List |
You might have anticipated Vec<bool>
to be a supported Rust vector type. This is not possible because in R, logical vectors do not contain only true
and false
like Rust’s bool type. They also can be an NA
value which has no corresponding representation in Rust.
Below defines Rust function which takes in a vector of f64
values and prints them out.
#[extendr]
fn vector_double(x: Vec<f64>) {
rprintln!("The values of x are {x:?}");
}
That function can be called from R which prints the Debug format of the vector.
Rust’s vector do not implement the Display trait so the debug format (:?
) is used.
vector_double(c(4.2, 1.3, 2.5))
#> The values of x are [4.2, 1.3, 2.5]
Returning values using Rust follows the same rules as R. You do not need to explicitly return a value as long as the last item in an expression is not followed by a ;
.
#[extendr]
fn vector_double(x: Vec<f64>) -> Vec<f64> {
x }
Calling the function returns the input as a double vector
<- vector_double(c(4.2, 1.3, 2.5))
x typeof(x)
#> [1] "double"
+ 1
x #> [1] 5.2 2.3 3.5
Additional examples
These same principles can be extended to other supported vector types such as Vec<i32>
and Vec<String>
.
#[extendr]
fn vector_integer(x: Vec<i32>) -> Vec<i32> {
x}
#[extendr]
fn vector_character(x: Vec<String>) -> Vec<String> {
x }
vector_integer(c(4L, 6L, 8L))
#> [1] 4 6 8
vector_character(c("Hello world!", "Hello extendr!", "Hello R!"))
#> [1] "Hello world!" "Hello extendr!" "Hello R!"