nested struct initialization literals - struct

How can I do this:
type A struct {
MemberA string
}
type B struct {
A A
MemberB string
}
...
b := B {
MemberA: "test1",
MemberB: "test2",
}
fmt.Printf("%+v\n", b)
Compiling that gives me: "unknown B field 'MemberA' in struct literal"
How can I initialize MemberA (from the "parent" struct) when I provide literal struct member values like this?

While initialization the anonymous struct is only known under its type name (in your case A).
The members and functions associated with the struct are only exported to the outside after the
instance exists.
You have to supply a valid instance of A to initialize MemberA:
b := B {
A: A{MemberA: "test1"},
MemberB: "test2",
}
The compiler error
unknown B field 'MemberA' in struct literal
says exactly that: there's no MemberA as it is still in A and not in B. In fact,
B will never have MemberA, it will always remain in A. Being able to access MemberA
on an instance of B is only syntactic sugar.

The problem is with declaring the struct A in B. Please specify the name along with declaration, then it works.
package main
import "fmt"
type A struct {
MemberA string
}
type B struct {
MemA A
MemberB string
}
func main() {
b := B{MemA: A{MemberA: "test1"}, MemberB: "test2"}
fmt.Println(b.MemberB)
}

Related

How do I implement From<T> for Option<U> in Rust?

Assuming I have an enum as:
enum Foo {
A,
B,
}
...where I want to implement something like this:
impl From<char> for Option<Foo> {
fn from(chr: char) -> Self {
match chr {
'A' => Some(Foo::A),
'B' => Some(Foo::B),
_ => None,
}
}
}
This is currently illegal since Option is out of my own crate, it is owned by std. The compiler error is:
only traits defined in the current crate can be implemented for types defined outside of the crate
define and implement a trait or new type instead rustc(E0117)
As in the case I have shown above, in some cases, I'd like to have None instead of Some. Is there a way to implement a From that I am able to get Option<U> instead of U itself?
Environment
Rust 1.62.1
I think what you actually want in this scenario is to implement the TryFrom trait instead.
For example (ideally you'd make a proper Error type rather than a str):
impl TryFrom<char> for Foo {
type Error = &'static str;
fn try_from(chr: char) -> Result<Foo, Self::Error> {
match chr {
'A' => Ok(Foo::A),
'B' => Ok(Foo::B),
_ => Err("can't convert character to Foo"),
}
}
}

Declare an Enum inline with a struct declaration

I could have a structure like the following:
struct Example {
state: State,
properties: HashMap<String, String>,
}
enum State {
a, b, c,
}
If the Example structure is the only user of the State enum, I think it would make sense to declare it in the struct:
struct Example {
state: enum { a, b, c },
properties: HashMap<String, String>,
}
Is there any valid syntax for this?
No. There is no such syntax.
You can check the Rust grammar for structs, the type of a field must be a type expression. Type expressions cannot create new types.

How to add a constraint to a field of a struct for instantiation?

I have a simple struct with one string field:
pub struct Chunk {
signature: String
}
This string field cannot be just any string, there are bunch of constraints that it needs to satisfy (and if string passed to constructor does not satisfy these constraints, construction of struct should fail).
In object-oriented languages like C++, I would make the explicit constructor that does the needed checks, what is the correct way to do this in Rust?
I came up with this code:
impl Chunk {
pub fn new(s: String) -> Option<Chunk> {
if constraints_fail {
None
} else {
Some(Chunk{signature: s})
}
}
}
I'm not sure if this is a correct approach, since technically the struct can still be instantiated with invalid string parameter without ever calling this function.
Your struct contains a private field, therefore it cannot be instantiated from outside. This is what you get if you try:
error[E0451]: field `signature` of struct `Chunk` is private
--> src/main.rs:8:24
|
8 | let _ = Chunk { signature: "xxx".to_owned() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ private field
You don't need to do anything else - just keep the signature field private.

If struct A is embedded in B, can methods on A access method and fields of B?

struct A {}
func (a *A) BName(id int) string {
return a.Name
}
struct B {
*A
Name string
}
func main() {
b := &B{Name: "abc"}
fmt.Println(b.Name)
}
the code failure, I want know how to write code to achieve, A.BName can access B struct attribute Name
This is not possible. struct A does not know anything about the types it is embedded into. Think about it, A can be embedded into any other struct, so how could you know ahead of time the type of the struct that A is embedded into.
If you want to do this, you need to place a reference to B, the outer structure into A.
type A struct {
*B
}
func (a *A) PrintName() string { return a.B.Name }
type B struct {
A // no need to use a pointer here
Name string
}
var b B
b.A.B = &b
fmt.Println(b.PrintName())
A accessing B reminds me of a is-a relationship, where A "is-a" B.
The article "Is Go an Object Oriented language?" does note that there is no true subtyping in Go:
if it was truly subtyping then the anonymous field would cause the outer type to become the inner type. In Go this is simply not the case. The two types remain distinct.
The anonymous fields are still accessible as if they were embedded
Example:
package main
type A struct{
// doesn't know anything about B
}
type B struct {
A //B is-a A
}
func (a *A) f() { fmt.Println("A.f") }
func (b *B) f() { fmt.Println("B.f") }
func save(A) {
//do something
}
func main() {
b := B
save(&b) //OOOPS! b IS NOT A
b.f() // B.f()
b.A.f() // A.f()
}
One of the issues with multiple inheritance is that languages are often non obvious and sometimes even ambiguous as to which methods are used when identical methods exist on more than one parent class.
With Go you can always access the individual methods through a property which has the same name as the type.
In reality when you are using Anonymous fields, Go is creating an accessor with the same name as your type.
That is what "b.A" is: an accessor to an anonymous field..

How to import a struct that is inside of other package?

I tried to learn Go but I frequently feel frustrating because some basic features that other languages has seems not working in Go. So basically, I would like to use struct type that is
define in other file. I was able to use functions except struct type. In main.go,
package main
import (
"list"
)
func main() {
lst := list.NewList(false)
lst.Insert(5)
lst.Insert(7)
lst.InsertAt(2, 1)
lst.PrintList()
}
This works perfectly (and all other functions) as I expect (list is in $GOPATH). In package list, I defined struct as follow:
type LinkedList struct {
head *node
size int
isFixed bool
}
I wanted to use this struct in other struct, so I attempted to do something like this,
type SomeType struct {
lst *LinkedList
}
But unfortunately, I got error that the type LinkedList is not defined. How can I use a struct that is defined in other package?
The LinkedList type is in the list namespace, so change your usage of the type to:
type SomeType struct {
lst *list.LinkedList
}

Resources