struct Ipv4{
addres: String
}
struct Ipv6{
addres: String
}
#[derive(Debug)]
enum IPAddrKind{
V4(Ipv4),
V6(Ipv6)
}
fn main(){
let home = IPAddrKind::V4(String::from("127.0.0.1"));
println!("your ip : {:?}",home)
}
IPAddrKind::V4 holds a struct Ipv4. When you want to instantiate a IPAddrKind::V4, you also need to instantiate the struct.
let home = IPAddrKind::V4(Ipv4 {
addres: String::from("127.0.0.1"),
});
Also, don't forget to add the Debug trait to Ipv4 and Ipv6.
#[derive(Debug)]
struct Ipv4 {
addres: String,
}
#[derive(Debug)]
struct Ipv6 {
addres: String,
}
Related
#[derive(Serialize, Deserialize, Debug)]
struct Product {
id: usize,
name: String,
timestamp: i128
}
I deserialize this struct value from a JSON value.
Now I want to expose another property on my struct:
dt: OffsetDateTime
I want this property to be immutable, and set only once. So I don't want to expose a function that like below b/c it would re-calculate each time I call it:
impl Product {
fn dt(&self) -> OffsetDateTime {
OffsetDateTime::from_unix_timestamp_nanos(self.timestamp)
}
}
In java world or other languages I would do something like this:
private dt: OffsetDateTime = null;
public OffsetDateTime getDt() {
if(dt == null) {
dt = OffsetDateTime::from_unix_timestamp_nanos(self.timestamp)
}
return dt;
}
Does Rust have a similar pattern I can use?
You have three options:
Initialize it when initializing the struct, by providing a constructor. This is by far the easiest solution, if initialization isn't expensive or access is common enough that initializing always is not a problem. This is not equivalent to your Java code, however.
Store an Option<OffsetDateTime> and use Option::get_or_insert_with() to initialize it on access. This is cheapier than the third option, but requires a &mut access:
pub fn dt(&mut self) -> &OffsetDateTime {
self.dt.get_or_insert_with(|| { /* Initialization logic */ })
}
Use a library such as once_cell (or the unstable versions in std) to initialize under & access. You can use either Sync or not, depending on whether you need multiple threads to access the data):
pub fn dt(&self) -> &OffsetDateTime {
self.dt.get_or_init(|| { /* Initialization logic */ })
}
You could use an Option to simulate the Java behavior.
struct P {
pub thing: Option<i32>
}
impl P {
pub fn calc_thing( mut self ) -> i32 {
if let None = self.thing {
self.thing = Some(5);
}
self.thing.unwrap()
}
}
fn main(){
let p = P{ thing: None };
println!( "{}", p.calc_thing() );
}
I am trying to understand following enum from this repo
#[repr(C)]
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone)]
pub struct InitEscrowArgs {
pub data: EscrowReceive,
}
#[repr(C)]
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone)]
pub struct ExchangeArgs {
pub data: EscrowReceive,
}
#[derive(BorshSerialize, BorshDeserialize, Clone)]
pub enum EscrowInstruction {
InitEscrow(InitEscrowArgs),
Exchange(ExchangeArgs),
CancelEscrow(),
}
and it's use of it in this match from this repo.
pub fn process(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let instruction = EscrowInstruction::try_from_slice(instruction_data)?;
match instruction {
EscrowInstruction::InitEscrow(args) => {
msg!("Instruction: Init Escrow");
Self::process_init_escrow(program_id, accounts, args.data.amount)
}
EscrowInstruction::Exchange(args) => {
msg!("Instruction: Exchange Escrow");
Self::process_exchange(program_id, accounts, args.data.amount)
}
EscrowInstruction::CancelEscrow() => {
msg!("Instruction: Cancel Escrow");
Self::process_cancel(program_id, accounts)
}
}
}
I understand that this try_from_slice method gets some sort of byte array and deserialize it.
I do not understand how it determines which enum value to use.
The enum has 3 choices, InitEscrow / Exchange / CancelEscrow, but what determines the match to know which one it is suppose to select?
Seem to me the InitEscrowArgs and ExchangeArgs both takes in same struct. Both containing data that is EscrowReceive data type.
Method try_from_slice is part of the BorshDeserialize trait, which is derived on the enum in question. So, the choice between enum variants is made by the implementation of deserializer.
To see what is really going on, I've built the simplest possible example:
use borsh::BorshDeserialize;
#[derive(BorshDeserialize)]
enum Enum {
Variant1(u8),
Variant2,
}
By using cargo expand and a little manual cleanup, we can get the following equivalent code:
impl borsh::de::BorshDeserialize for Enum {
fn deserialize(buf: &mut &[u8]) -> Result<Self, std::io::Error> {
let variant_idx: u8 = borsh::BorshDeserialize::deserialize(buf)?;
let return_value = match variant_idx {
0u8 => Enum::Variant1(borsh::BorshDeserialize::deserialize(buf)?),
1u8 => Enum::Variant2,
_ => {
let msg = format!("Unexpected variant index: {}", variant_idx);
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
msg,
));
}
};
Ok(return_value)
}
}
Where the inner deserialize calls refers to impl BorshDeserialize for u8:
fn deserialize(buf: &mut &[u8]) -> Result<Self> {
if buf.is_empty() {
return Err(Error::new(
ErrorKind::InvalidInput,
ERROR_UNEXPECTED_LENGTH_OF_INPUT,
));
}
let res = buf[0];
*buf = &buf[1..];
Ok(res)
}
So, it works the following way:
Deserializer tries to pull one byte from input; if there's none - this is an error.
This byte is interpreted as an index of enum variant; if it doesn't match to one of variants - this is an error.
If the variant contains any data, deserializer tries to pull this data from the input; if it fails (according to the inner type's implementation) - this is an error.
I am wondering is it possible to create enum with constant string values in Rust?
I found this previous question: How do I get an enum as a string? which shows a work around that I can use to stringify variants of an enum (I can use .to_string() on enum variants and get their name as a string).
That question was helpful, but this is what I want to achieve:
enum StringEnum {
Hello = "Hello",
World = "World"
}
If you have an enum like this:
enum HelloWorld {
Hello,
World
}
Hello and World are enum variants. Every variant of an enum is assigned to a single integer value. This is known as the discriminant. Currently, discriminants are only allowed to be integers, not arbitrary types like &'static str, although that may change in the future.
If you want to be able to convert your enum to a string, you can write a method that does this manually:
impl HelloWorld {
fn as_str(&self) -> &'static str {
match self {
HelloWorld::Hello => "Hello",
HelloWorld::World => "World"
}
}
}
Or you can have this done for you with the strum_macros crate:
#[derive(strum_macros::Display)]
pub enum StringEnum {
Hello,
World
}
fn main() {
let hello: &'static str = StringEnum::Hello.into(); // "Hello"
let world: String = StringEnum::World.to_string(); // "World"
}
There are a couple other methods mentioned in How do I get an enum as a string?
You can also have enum with data
pub enum TokenType<'a> {
STRING(&'a str),
}
and the this will give you the "test" value.
pub fn test() {
let token = TokenType::STRING("test");
if let TokenType::STRING(value) = token {
println!("{:?}", value)
}
}
Is it possible to forbid creating an instances directly from member initialization?
e.g.
pub struct Person {
name: String,
age: u8,
}
impl Person {
pub fn new(age: u8, name: String) -> Person {
if age < 18 {
panic!("Can not create instance");
}
Person { age, name }
}
}
I can still use
Person {
age: 6,
name: String::from("mike")
}
to create instance. Is there anyway to avoid this?
Answer to question
You cannot create that struct from member initialization, because members are by default private and cannot be used directly. Only the immediate module and its submodules can access private fields, functions, ... (see the book about visibility).
Your example works, because your function is in that certain scope.
mod foo {
pub struct Person {
name: String,
age: u8,
}
impl Person {
pub fn new(age: u8, name: String) -> Person {
if age < 18 {
panic!("Can not create instance");
}
Person { age, name }
}
}
}
use foo::Person; // imagine foo is an external crate
fn main() {
let p = Person {
name: String::from("Peter"),
age: 8,
};
}
(Playground)
error[E0451]: field `name` of struct `Person` is private
error[E0451]: field `age` of struct `Person` is private
Make it possible to create a struct from the outside
On the other hand, if you want to make it possible to create an instance by member initialization, use the pub keyword in front of all members.
pub struct Person {
pub name: String,
pub age: u8,
}
Make it possible to access the fields, but not creating a struct from the outside
Please see KittenOverflows answer for a better approach to this.
--
Sometimes it's useful to let the user of your crate access the members directly, but you want to restrict the creation of an instance to your "constructors". Just add a private field.
pub struct Person {
pub name: String,
pub age: u8,
_private: ()
}
Because you cannot access _private, you cannot create an instance of Person directly.
Also the _private field prevents creating a struct via the update syntax, so this fails:
/// same code from above
fn main() {
let p = Person::new(8, String::from("Peter"));
let p2 = Person { age: 10, ..p };
}
error[E0451]: field `_private` of struct `foo::Person` is private
--> src/main.rs:27:34
|
27 | let p2 = Person { age: 10, ..p };
| ^ field `_private` is private
For Rust >= 1.40.0, consider applying the non_exhaustive attribute to your struct.
// Callers from outside my crate can't directly construct me
// or exhaustively match on my fields!
#[non_exhaustive]
pub struct Settings {
pub smarf: i32,
pub narf: i32,
}
More info in the 1.40.0 release notes.
Consider the following Rust snippet from The Rust Programming Language, second edition:
pub struct Guess {
value: u32,
}
impl Guess {
pub fn new(value: u32) -> Guess {
if value < 1 || value > 100 {
panic!("Guess value must be between 1 and 100, got {}.", value);
}
Guess {
value
}
}
pub fn value(&self) -> u32 {
self.value
}
}
and commentary from the corresponding tutorial, emphasis mine:
Next, we implement a method named value that borrows self, doesn’t have any
other parameters, and returns a u32. This is a kind of method sometimes
called a getter, since its purpose is to get some data from its fields and
return it. This public method is necessary because the value field of the
Guess struct is private. It’s important that the value field is private so
that code using the Guess struct is not allowed to set value directly:
callers outside the module must use the Guess::new function to create an
instance of Guess, which ensures there’s no way for a Guess to have a
value that hasn’t been checked by the conditions in the Guess::new function.
Why must callers use the new function? Couldn't they get around the requirement that Guess.value be between 1 and 100 by doing something like:
let g = Guess { value: 200 };
This applies only when the Guess struct is defined in a different module than the code using it; the struct itself is public but its value field is not, so you can't access it directly.
You can verify it with the following example (playground link):
use self::guess::Guess;
fn main() {
let guess1 = Guess::new(20); // works
let guess2 = Guess::new(200); // panic: 'Guess value must be between 1 and 100, got 200.'
let guess3 = Guess { value: 20 }; // error: field `value` of struct `guess::Guess` is private
let guess4 = Guess { value: 200 }; // error: field `value` of struct `guess::Guess` is private
}
mod guess {
pub struct Guess {
value: u32,
}
impl Guess {
pub fn new(value: u32) -> Guess {
if value < 1 || value > 100 {
panic!("Guess value must be between 1 and 100, got {}.", value);
}
Guess {
value
}
}
pub fn value(&self) -> u32 {
self.value
}
}
}
The Book explains the rationale behind keeping a struct's contents private pretty well.