I want to implement a trait for a generic-type struct. A method inside the trait block must return a non-generic type. I'm having problems while trying to cast:
struct Rectangle<T> {
x: T,
y: T,
width: T,
height: T,
}
trait Area {
fn area(&self) -> f64;
}
impl<T> Area for Rectangle<T>
where T: std::ops::Mul<Output=T>
{
fn area(&self) -> f64 {
let t_area = self.height * self.width;
let f_area = t_area as f64;
f_area
}
}
fn main() {
let sq = Rectangle { x: 0, y: 0, height: 1, width: 1 };
println!("{}", sq.area());
}
And the compiler output is:
error: non-scalar cast: `T` as `f64`
--> src/main.rs:22:22
|
22 | let f_area = t_area as f64;
| ^^^^^^^^^^^^^
Can I cast T to f64 without using unsafe blocks?
Can I, not using unsafe blocks, cast T to f64?
What's T? The code to convert u8 to f64 is certainly not the same as the code to convert u64 to f64 (the latter can fail, after all).
As I see it, you have two paths ahead of you:
make Area generic over T, and thus return a T
constrain T to types that can be converted into a f64
I'll demonstrate the latter:
impl<T> Area for Rectangle<T>
where T: std::ops::Mul<Output=T> + Clone + std::convert::Into<f64>
{
fn area(&self) -> f64 {
self.height.clone().into() * self.width.clone().into()
}
}
Can I, not using unsafe blocks, cast T to f64?
No, and there are many good reasons for that. T could be any type, so it doesn't need to be compatible with or similar to f64 at all. The only thing you know about your T is, that it implements std::ops::Mul<Output=T>. But that doesn't help, because that trait doesn't say anything about f64 either.
So what you could do, is to bound T to be std::ops::Mul<Output=f64>. This means that multiplying two Ts will result in an f64. Your function then works (even without the as f64 cast), but you make your impl way less generic.
The proper way to solve this problem, is to abstract over multiple kinds of numbers. Thankfully, the num-traits crate has already done that. In particular, you are probably interested in the ToPrimitive trait. Your impl should then probably look somewhat like:
use num_traits::ToPrimitive;
impl<T> Area for Rectangle<T>
where T: std::ops::Mul
<T as std::ops::Mul>::Output: ToPrimitive
{
fn area(&self) -> f64 {
let t_area = self.height * self.width;
t_area.to_f64().unwrap()
}
}
Minor problem: we have this unwrap() here which panics when the multiplication result can't be converted into an f64. I'm not quite sure why this can happen, but we need to be aware of that. Maybe there is a better solution without such an unwrap().
You can of course also create your own trait. Something like:
trait AsF64 {
fn cast(self) -> f64;
}
impl AsF64 for i32 {
fn cast(self) -> f64 { self as f64 }
}
// more impls for u32, u16, i16, ...
And then impl for <T as std::ops::Mul>::Output: AsF64.
Related
I'm trying to make a function that can take a lambda that takes a reference and a lambda that takes a value.
An example will probably help since its difficult to describe.
fn derivative<F, R>(f: &F, x: f64) -> R
where F: Fn(f64) -> R,
R: Div<f64, Output=R> + Sub<Output=R>
{
let epsilon = 1e-7;
(f(x + epsilon / 2.0) - f(x - epsilon / 2.0)) / epsilon
}
fn derivative<F, R>(f: &F, x: f64) -> R
where F: Fn(&f64) -> R,
R: Div<f64, Output=R> + Sub<Output=R>
{
let epsilon: f64 = 1e-7;
(f(&(x + epsilon / 2.0)) - f(&(x - epsilon / 2.0))) / epsilon
}
This function approximates the derivative of f and I'd like to support both Fn<f64> and Fn<&f64>. In C++ I would do partial template specialization (just a fancy term for pattern matching template arguments) is there some thing similar to this in rust?
I thought that the syntax would look like the example code, but apparently the compiler tells me that derivative has been redefined [E4028].
Or is there an even easier way to implement this behavior?
I ran into a similar problem recently, where I wanted to specialize a method based on type parameters. Here is a standalone example that seems to work:
// trait is specialized for each specialization
pub trait SomeTraitSpecification<T> {
fn someFunctionImpl(&self, value: T);
}
// base trait
struct SomeStructure;
impl SomeStructure {
// function entry
// where clause restricts function options down to specific specialization function
pub fn someFunction<T>(&self, value: T) where Self: SomeTraitSpecification<T> {
// does nothing but call the specialized function
self.someFunctionImpl(value);
}
}
// implement SomeTraitSpecification for each type you want to call SomeStructure on
// declared in different impl blocks to avoid redefinitions
// f32 specialization
impl SomeTraitSpecification<f32> for SomeStructure {
fn someFunctionImpl(&self, value: f32) {
println!("float!");
}
}
// i32 specialization
impl SomeTraitSpecification<i32> for SomeStructure {
fn someFunctionImpl(&self, value: i32) {
println!("integer!")
}
}
fn main() {
let structure = SomeStructure {};
structure.someFunction(4); // calls i32 specialization
structure.someFunction(5.0); // calls f32 specialization
}
It's a little verbose, but it does work. The SomeTraitSpecialization trait is used to provide specializations. The "where" clause on the someFunction<T> is where the magic happens -- I've provided some comments that add some clarification.
Hopefully you can modify this to be useful.
I've got a vector of mutable references:
struct T;
let mut mut_vec: Vec<&mut T> = vec![];
How can I pass (a copy of) it into a function that takes a vector of immutable references?
fn cool_func(mut immut_vec: Vec<&T>) {}
You can dereference and reborrow the mutable references, then add them to a new Vec:
fn main() {
let mut st = String::new();
let mut_vec = vec![&mut st];
let immut_vec = mut_vec.into_iter().map(|x| &*x).collect();
cool_func(immut_vec);
}
fn cool_func(_: Vec<&String>) {}
Note however, that this consumes the original Vec - you can't really get around this, as if the original Vec still existed, you'd have both mutable and immutable references to the same piece of data, which the compiler will not allow.
If you need to actually convert, see Joe Clay's answer. However, you might not need to convert in the first place!
Instead of changing the argument, change the function so that it accepts both mutable and immutable references. Here we use Borrow to abstract over both:
use std::borrow::Borrow;
fn main() {
let mut st = String::new();
let mut_vec = vec![&mut st];
cool_func(mut_vec);
let immut_vec = vec![&st];
cool_func(immut_vec);
}
fn cool_func<S>(_: Vec<S>)
where
S: Borrow<String>,
{
}
See also:
How to pass Iterator<String> as Iterator<&str>?
Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?
I would like to express a static_assert with the form:
static_assert(expression should not compile);
Let me add a complete example:
template <bool Big>
struct A{};
template <>
struct A<true>
{
void a() {}
};
A<false> b;
static_assert(!compile(b.a()));
or
static_assert(!compile(A<false>::a()));
So, the idea is to be able to ensure that an expression (with valid syntax) will not compile.
It will be better if the solution only uses C++11 if possible.
OK, given the context of your question is somewhat vague, this answer might not be appropriate for your case. However, I found this a very interesting challenge.
Clearly, as stated in the comments, the solution will have to exploit some kind of (expression) SFINAE. Basically, what we need is a more generic variant of the detection idiom. Hovewer, there are mainly two problems here:
1) To make SFINAE kick in, we need some kind of templates.
2) To provide the compile(XXX) syntax, we need to create these templates "on the fly" inside a macro. Otherwise we would have to define a test function for each test in advance.
The second constraint makes things rather difficult. We can define structs and functions locally inside lambdas. Unfortunately, templates are not allowed there.
So here is, how far I was able to get (not 100% what you want, but relatively close).
Usually, the expression-SFINAE-detectors leverage either (template) function overloading or class template specialisation. As both are not allowed inside a lambda, we need an additional layer: a functor that takes a bunch of lambdas and calls the one that fits the call arguments best. This is often used in combination with std::variant.
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
Now we can create a detector like this:
auto detector = overloaded{
[](auto, auto) -> std::false_type {return {};}
,
[](auto x, int)-> decltype(decltype(x)::a(), std::true_type{}){ return {};}
};
static_assert(!detector(A<false>{}, int{}));
static_assert(detector(A<true>{}, int{}));
Now, we can define a macro, that defines and calls a dector for the desired expression:
#define compile(obj, xpr) \
[]() { \
auto check = \
overloaded{[](auto&&, auto) -> std::false_type { return {}; }, \
[](auto&& x, int) -> decltype(x xpr, std::true_type{}) { \
return {}; \
}}; \
return decltype(check(obj, int{})){}; \
}()
This macro creates a lambda, substitutes the xpr into the detector, and performs type deduction on decltype(x) to make SFINAE kick in. It can be used as follows:
static_assert(!compile(b, .a()));
static_assert(compile(a, .a()));
int x = 0;
static_assert(compile(x, *= 5));
static_assert(!compile(x, *= "blah"));
Unfortunately, it won't work with a typename as first argument. Therefore we need a second macro for those kinds af tests:
#define compile_static(clazz, xpr) \
[]() { \
auto check = overloaded{ \
[](auto, auto) -> std::false_type { return {}; }, \
[](auto x, int) -> decltype(decltype(x) xpr, std::true_type{}) { \
return {}; \
}}; \
return decltype(check(std::declval<clazz>(), int{})){}; \
}()
static_assert(!compile_static(A<false>, ::a()));
static_assert(compile_static(A<true>, ::a()));
As stated above, this is not 100% what you requested, as we'll always need an additional , to separate the macro arguments. Also, it needs two separate macros. Maybe this is something that can be impoved using the preprocessor to detect whether the xpr argument starts with ::. And, of course, there might be cases, where it doesn't work. but perhaps it is a starting point.
It requires c++17, but seems to work with gcc >= 7, clang >= 5 and even msvc 19.
Here is a full example.
I am trying to cast Stdout to Write:
use std::io::{self, Write};
pub struct A<Output: Write> {
output: Output,
}
impl<Output: Write> A<Output> {
pub fn new() -> A<Output> {
A {
output: io::stdout() as Write,
}
}
}
The compiler is complaining:
error[E0620]: cast to unsized type: `std::io::Stdout` as `std::io::Write`
--> src/main.rs:10:21
|
10 | output: io::stdout() as Write,
| ^^^^^^^^^^^^^^^^^^^^^
|
help: consider using a box or reference as appropriate
--> src/main.rs:10:21
|
10 | output: io::stdout() as Write,
| ^^^^^^^^^^^^
I want to cast this and tried to do what the compiler suggested but then it is saying that the as keyword could only be used for primitives and that I should implement the From trait.
How could I cast the Stdout as a Write trait?
cast Stdout to Write
This does not make sense because Write isn't a type that you cast to. Write is a trait. There are trait objects that are types though, such as Box<Write> or &Write. Re-read the trait objects chapter of The Rust Programming Language to refresh your memory on this topic. Rust 1.27 is going to improve the syntax here to make it more obvious as Box<dyn Write> / &dyn Write.
You could use Box::new(io::stdout()) as Box<Write>, but you'll quickly run into "Expected type parameter" error in the constructor of a generic struct.
impl A<Box<Write>> {
pub fn new() -> Self {
A {
output: Box::new(io::stdout()) as Box<Write>,
}
}
}
See also:
What makes something a "trait object"?
Why is `let ref a: Trait = Struct` forbidden
"Expected type parameter" error in the constructor of a generic struct
I am new to golang, so appologize if this question is too naive. Looked around, but could not find answer to my basic question.
Lets say I have a concrete struct and methods as shown below.
type MyData struct{
field1 string
field2 int
}
func(a MyData) OperatorOnString() string{
return a.field1.(string)
}
func(a MyData) OperatorOnInt() int{
return a.field2.(int)
}
My question is, can I type cast and return rather than performing assertion? From what I have learned so far is that, assertion is used on data of type interface. But in this case I have concrete type. Should I still use assertion or I can do something like return int(a.field2). I know this example is trivial, but the point that I am confused is when to use between the two conversion types. Or is there some golang idiomaticity involved here?
Thanks
First of all, type assertion can be used only on interfaces:
For an expression x of interface type and a type T, the primary expression
x.(T)
asserts that x is not nil and that the value stored in x is of type T. The notation x.(T) is called a type assertion.
But you're applying it to non interface typed fields (int and string). That makes compiler unhappy.
Secondly, if you want to return type T from a method/function, it's always enough to return an expression of type T, which your fields already happen to be. The correct code is then easy:
package main
import "fmt"
type MyData struct {
field1 string
field2 int
}
func (a MyData) OperatorOnString() string {
return a.field1
}
func (a MyData) OperatorOnInt() int {
return a.field2
}
func main() {
a := MyData{"foo", 42}
fmt.Println(a.OperatorOnString(), a.OperatorOnInt())
}
Playground
Output:
foo 42