Question about how to think about Enum data type and just struct: Let’s assume that there is a piece of code in language which has traditional OOP. There is a need to have an array of some objects which have to be processed in a bulk. So let’s assume that all items in array have to be the same type. So there could be base class which is abstract (or might be a trait) and other child classes which extends base abstract class and contains specific for child classes’ fields. Taking an example in Scala it would look like this:
trait Fruit
case object Apple extends Fruit
case object Orange extends Fruit
case object Plum extends Fruit
case class GlassOfJuice(fruits: Set[Fruit])
// ...
val fruits = Seq(Apple, Orange, Plum)
def squeezer(fruits: Seq[Fruit]): GlassOfJuice =
fruits.foldLeft(GlassOfJuice(Set.empty))((glass, fruit) => glass.copy(fruits = glass.fruits + fruit))
How similar code might look like in rust? Should Fruit
and all child be a enum
data type? Or in case of usage struct
data type for it. How squeezer
function would look like since struct
s can’t extends other struct
s.
squeezer
return GlassOfJuice
with a set of fruits, while the class only contains a set of fruits?GlassOfJuice
could take the fruits and set it as itselfs only property.
GlassOfJuice
could be simle initiated like this: GlassOfJiuce(fruits.toSet)
Fruit
s) and a bulk of commands are translated into a sequence of events. So I started implementation just with struct
s but later on I understand if I want to have separated handler of commands and I want to process them in bulk - it need to have base type for all of them or imlement trait for them (but the idea with trait doesn’t look nice since it’s only tagging / putting a label on command in order to sutisfy compiler’s requirements and there is no any method on a command which is required for now). And I re-checked docs again and found an enum data type and was in doubts which way to go :-) and yes, I agree in software there is “it depends” :-)
extern crate
in the main.rs file.
use
in every file/module that needs it. extern exposes the top-level symbol though.
extern crate chrono;
doesn't require use chrono;
in the same mod/file, but you will need use chrono;
in other files. (You may also want to do something like use chrono::*;
to bring symbols into scope unqualified.
fn start_kafka(tx: Sender<Message>) {
let mut consumer = Consumer::from_hosts(vec!["example.com".to_owned()]); //... some other config omitted
loop {
for ms in consumer.poll().unwrap().iter() {
for m in ms.messages() {
tx.send(m);
}
consumer.consume_messageset(ms);
}
consumer.commit_consumed().unwrap();
}
}
consumer.poll().unwrap()
doesn't live long enough. But the actual problem is that I'm passing m
(the Message) into tx
a Sender<Message>
type from the std::mpsc lib
The Message type itself looks like this: (from https://spicavigo.github.io/kafka-rust/kafka/consumer/struct.Message.html)
pub struct Message<'a> {
pub offset: i64,
pub key: &'a [u8],
pub value: &'a [u8],
}
It's not marked as Clone
so I can't copy the message directly. I've tried copying the values off of it but my own external clone method inherits the 'a
lifetime from it, so the copy is still bound to the same lifespan.
<'a>
lifetime from the Message propogates all the way up to the poll
method
kafka = "0.5"
in my dependencies
cargo add
(from cargo-edit) and it added 0.5.0, so that seems to be the latest.
let mut consumer = Consumer::from_hosts(vec!["example.com:9092".to_owned()])
.with_topic_partitions("test".to_owned(), &[0])
.with_fallback_offset(FetchOffset::Earliest)
.with_group("mygroup".to_owned())
.with_offset_storage(GroupOffsetStorage::Kafka)
.create()
.unwrap();
error: no method named `poll` found for type `kafka::consumer::Builder` in the current scope
--> src/main.rs:10:28
|
10 | for ms in consumer.poll().unwrap().iter() {
| ^^^^
error: no method named `consume_messageset` found for type `kafka::consumer::Builder` in the current scope
--> src/main.rs:14:22
|
14 | consumer.consume_messageset(ms);
| ^^^^^^^^^^^^^^^^^^
error: no method named `commit_consumed` found for type `kafka::consumer::Builder` in the current scope
--> src/main.rs:16:18
|
16 | consumer.commit_consumed().unwrap();
| ^^^^^^^^^^^^^^^
extern crate kafka;
use std::sync::mpsc::Sender;
use kafka::consumer::{Consumer, Message};
use kafka::consumer::{Consumer, FetchOffset, GroupOffsetStorage};
use kafka::client::fetch::Message;
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
error[E0308]: mismatched types
--> src/main.rs:19:25
|
19 | tx.send(m);
| ^ expected struct `kafka::consumer::Message`, found reference
|
= note: expected type `kafka::consumer::Message<'_>`
= note: found type `&kafka::consumer::Message<'_>`
fn start_kafka(tx: Sender<Message>) {
fn start_kafka(tx: Sender<&Message>) {
poll
line but if you comment out the tx.send(m)
it will compile so the source of the problem is trying to hold onto that m
value which is then just propagating back up.