Can 'static be placed along the struct declaration? - syntax

In Rust programming language, can there be a case where 'static is placed here:
struct Abc <'static> {
...

This is a bit like asking if can you specify i32 as a type parameter in a struct declaration:
struct Abc<i32> {}
It doesn't make sense[1].
A type parameter lets fields of a struct be generic:
struct Abc<T> {
foo: T, // a user of this struct can choose the type of T
}
In the same way, a lifetime parameter allows the lifetime of a reference to be generic:
struct Abc<'a> {
foo: &'a str, // a user of this struct can choose the lifetime bound
}
If you want the lifetime to be always static, then just specify that, rather than making it generic:
struct Abc {
foo: &'static str, // this must always be static
}
[1] Actually it declares a type parameter, which just happens to have the same name as the i32 type—but that is unlikely to be what a person who tried writing something like this would have intended.

No.
Every type has an implicit 'static lifetime if no generic lifetime is specified. Lifetimes in the declaration of a structure as in
struct Abc<'here, 'and, 'there>;
are meant to specify that the structure contains shorter lifetimes and give them a name. 'static being a special lifetime doesn't need to be specified here or to have a local name.
This doesn't mean however that those lifetimes can't be 'static for a particular instance of the structure.

Related

How to initialize an array of anonymous struct with generic field

I'd to learn whether it's possible to initialize an array of anonymous struct contains generic-field. Code below doesn't compile, moreover I couldn't find any sample related to:
testCases := type [K comparable, T Numeric] []struct {
name string
args map[K]T
expected int
}{
// items ...
{"integer", map[string]int{ "a":1 },
}
Without anonymous structs it's easy, but not the aimed:
type args[K comparable, T Numeric] struct {
m map[K]T
}
testCases := []struct {
name string
args args[string, int]
expected int
}{}
Thanks!
Type parameters are introduced so when you instantiate the type, you can give concrete types to type parameters. Given that, there is no sense in what you want to do. You want to create a generic anonymous type and instantiate it right away. You can't use this anonymous struct elsewhere (because it's anonymous), so leave out the type parameters and use the concrete types you'd instantiate the type parameters with if it would be a named type.
And to answer your original question: no, you cannot do this. The syntax does not allow this. There was a proposal to support this but was rejected: proposal: spec: generics: Anonymous generic aggregate types #45591. The workaround is to use a named struct type instead of the anonymous struct type, just as you suggested.

Type conversion vs type cast

In Go, because of it's static type language we can see lot of type conversion for example,
var x float64
var y =32
x=float64(32)
Even though Go supports type casting, as far as I know it's very rarely used in. Can someone explain why and usecases that type casting can be used. Following is a one example that use type casting.
type Common struct {
Gender int
From string
To string
}
type Foo struct {
Id string
Name string
Extra Common
}
type Bar struct {
Id string
Name string
Extra Common
}
foo:=Foo{
Id:"123",
Name:"damitha",
Extra: struct {
Gender int
From string
To string
}{Gender:1 , From:"xx", To:"yy" },
}
bar:=*(*Bar)(unsafe.Pointer(&foo))
fmt.Printf("%+v\n",bar)
Even this mapping also possible to achieve in more safer ways.
The unsafe shenanigans in the question are similar to type casting. These shenanigans are not needed. Use a conversion:
bar := *(*Bar)(&foo)
or more simply:
bar := Bar(foo)
The relevant quote from the specification is:
A non-constant value x can be converted to type T in any of these cases:
...
ignoring struct tags (see below), x's type and T have identical underlying types.
ignoring struct tags (see below), x's type and T are pointer types that are not defined types, and their pointer base types have identical underlying types.
The first point in the quote applies to Bar(foo) because Foo and Bar have identical underlying types.
The second point in the quote applies to the conversion (*Bar)(&foo) because:
*Foo and *Bar are pointer types
*Foo and *Bar are not defined types.
The base types Foo and Bar have the same underlying type.
Go supports neither type casting nor implicit type conversion while lot of static support languages like Java C/C++ supporting both. Go only supports for type conversion.

Are there official words about what type is an interface type in Go?

This is a Go grammar question and seems a stupid question but I've been checking the Go language specification to find some official words or definitions to define what type is a xxx type, say, what type is an interface type?
For example, I see words like these:
The method set of an interface type is its interface.
Or
An embedded field must be specified as a type name T or as a pointer to a non-interface type name *T, and T itself may not be a pointer type.
Or
Consider a struct type T with two methods ...
type T struct {
a int
}
....
A type literal like struct {...} is a struct type, what about A in
type A struct {...} and B in type B interface{...}? Is A a struct type and B an interface type?
Yes, from the above sample for the struct type T, I can tell that a defined type (by the "type" declaration) whose given type is a struct type or interface type is also a struct or interface type. So A is a struct type and B is an interface type also. But where are the official definitions of this rule?
For defined types I can only find the following relating to type categories:
A type definition creates a new, distinct type with the same underlying type and operations as the given type, and binds an identifier to it.
So my understanding is that the defined type is a new, distinct type with the given type, but they are in the same type category, say, interface types or struct types. Still, there are no such definitions.
TLDR;
The kind of type T is interface if its underlying type is an interface type.
The kind of type T is struct if its underlying type is a struct type.
Spec: Struct types and Spec: Interface types specifies exactly what are the struct and interface types:
StructType = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] .
EmbeddedField = [ "*" ] TypeName .
Tag = string_lit .
InterfaceType = "interface" "{" { MethodSpec ";" } "}" .
MethodSpec = MethodName Signature | InterfaceTypeName .
MethodName = identifier .
InterfaceTypeName = TypeName .
So for example these are struct types:
struct { A int }
struct {}
struct { _ int }
and these are interface types:
interface { String() string }
interface {}
We may use a type declaration to create a new type, such as:
type Point struct { X, Y int }
The above type definition creates a new, distinct type with the same underlying type and operations as the given type, and binds an identifier to it. The definition of underlying type is recursive:
Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself. Otherwise, T's underlying type is the underlying type of the type to which T refers in its type declaration.
When we talk about arbitrary types being structs or interfaces, we're talking about their kind.
In the light of this, basically your question is equivalent to this:
"When is the kind of an arbitrary type interface or struct?"
The answer to this question is not in the spec, but this is how we could define it:
The kind of a type T is interface if its underlying type is an interface type.
Similarly:
The kind of a type T is struct if its underlying type is a struct type.
So for example:
type Point struct { X, Y int }
type PP Point
Is the type struct { X, Y int } of kind struct? Yes, because since it's a type literal, its underlying type is itself, and it's by definition a struct type.
Is Point a struct? Since the underlying type of Point is the underlying type of the type to which it refers in its type declaration, which is a type literal (see above), it is of struct type (its kind is struct).
Is PP a struct? Since its underlying type is the underlying type of the type to which it refers in its type declaration (which is Point), whose underlying type is a struct type literal, yes, it is also a struct type.
This kind we're talking about is represented by the reflect.Kind type. There are reflect.Interface and reflect.Struct constants (of type reflect.Kind) to represent the struct and interface kinds. And the reflect.Type type descriptor has a Type.Kind() method to access this kind.
This is how you can check if the type (kind) of some value is a struct for example:
func isStruct(i interface{}) bool {
return reflect.TypeOf(i).Kind() == reflect.Struct
}
Testing it (try it on the Go Playground):
fmt.Println(isStruct(Point{})) // true
fmt.Println(isStruct(PP{})) // true
fmt.Println(isStruct(struct{}{})) // true
fmt.Println(isStruct("text")) // false
Checking for interface type is a little more complicated because passing an interface value to a function that expects interface{} will not pass the interface value as-is but the concrete value "stored" in it, and as an interface{} value. We would have to pass a pointer to interface (which otherwise rarely makes sense in Go), access the element type and check its kind. For details, see this answer: What is the difference between reflect.ValueOf() and Value.Elem() in go?
An interface type is a type introduced by the interface keyword, or a name for such a type as defined by type name interface (plus of course the actual requirements for that interface).
Any type, whether it is an interface type or not, implements an interface type if it has the appropriate set of named methods. That is, a struct type may be sufficient to be used with some interface type. Even a non-struct type may be sufficient:
type foo int
func (receiver_arg foo) method1() { ... }
Type-name foo now implements any interface that requires a method named method1 (provided of course that it implements the rest of any required methods).
... the defined type [via the type keyword] is a new, distinct type with the given type, but they are in the same type category ...
Yes, just so. Using reflect, you'll find that they have the same Kind. The word kind isn't in the spec like this but it's quite useful, and the link here enumerates all the fundamental type-kinds in Go.

Golang - add "inheritance" to structs

I would like to optimize my code, I have then the following situation:
I have a general struct where only one field gives the specification, let say a cache struct example:
# the main cache struct
type Cache struct {
name string
memory_cache map[string]interface{}
mutex *sync.Mutex
... ...
# common fields
}
# an element stored in the Cache.memory_cache map
type ElementA {
name string
count int64
}
# an element stored in the Cache.memory_cache map
type ElementB {
name string
tags []string
}
My current solution follow the previously definition and I create a cache for each element (it must be so: one cache per element):
var cache_for_element_A Cache{}
var cache_for_element_B Cache{}
But in this way I must always cast the memory_cache when reading, even if I know already what is the content (then no cast-case should be needed).
The following code do what I would like to have, but it defines twice a lot of redundants/commons fields, for this reason I would like to find another solution.
type CacheForA struct {
name string
memory_cache map[string]ElementA{}
mutex *sync.Mutex
... ...
# common fields
}
type CacheForB struct {
name string
memory_cache map[string]ElementB{}
mutex *sync.Mutex
... ...
# common fields
}
Then, is it possible to define a field in the struct (more precisely Cache.memory_cache) that can be further defined when the declaration occurs and without using interface?
Go doesn't have generics, so there's no simple way of doing this, like you would in Java for instance (class Cache<T>()....).
One thing you can do is wrap your cache with a small typed function that just fetches objects from a generic cache and converts the interface to the right type. This just saves you from writing the interface conversion over and over in your code.
type ElemACache struct {
Cache
}
func (c *ElemeACache)Get(key string) ElemeA {
return c.Cache.Get(key).(ElemeA) //of course add checks here
}
Struct embedding is the main thing you are looking for I think:
type Cache struct {
name string
mutex *sync.Mutex
}
type CacheA struct {
Cache
memory_cache map[string]ElementA{}
}
Then you make a type of interface, say "Cacher" that has a set of methods for the things you need to do with your various caches (cacheA, CacheB). Create those methods for CacheA, CacheB, and assertions are only needed only for the return type:
type Cacher interface {
GetItem(string) (interface{}, error)
}
If all your CacheFor types have that GetItem method, the interface will be fulfilled.
Still a fair amount of boilerplate, but this reduces the problem with redundancy in struct definitions. There are code generation tools if you don't want to type the boiler plate.

Am I using inheritance, borrowed pointers, and explicit lifetime annotations correctly?

I'm learning Rust, coming from an almost exclusively garbage collected background. So I want to make sure I'm getting off on the right foot as I write my first program.
The tutorial on the Rust site said I should be dubious of using pointers that aren't &. With that in mind, here's what I ended up with in my little class hierarchy (names changed to protect innocent). The gist is, I have two different entities, let's say Derived1 and Derived2, which share some behavior and structure. I put the common data into a Foo struct and common behavior into a Fooish trait:
struct Foo<'a> {
name: &'a str,
an_array: &'a [AnEnumType],
/* etc. */
}
struct Derived1<'a> {
foo: &'a Foo<'a>,
other_stuff: &'a str,
}
struct Derived2<'a> {
foo: &'a Foo<'a>,
/* etc. */
}
trait Fooish<'a> {
fn new(foo: &'a Foo<'a>) -> Self;
/* etc. */
}
impl<'a> Fooish<'a> for Derived1<'a> {
fn new(foo: &'a Foo<'a>) -> Derived1<'a> {
Derived1 { foo: foo, other_stuff: "bar" }
}
/* etc. */
}
/* and so forth for Derived2 */
My questions:
Am I "doing inheritance in Rust" more-or-less idiomatically?
Is it correct to use & pointers as struct fields here? (such as for string data, and array fields whose sizes vary from instance to instance? What about for Foo in Derived?)
If the answer to #2 is 'yes', then I need explicit lifetime annotations, right?
Is it common to have so many lifetime annotations everywhere as in my example?
Thanks!
I'd say that this is not idiomatic at all, but sometimes there are tasks which require stepping away from idiomatic approaches, it is just not clear if this is really such a case.
I'd suggest you to refrain from using ideas from OO languages which operate in terms of classes and inheritance - they won't work correctly in Rust. Instead you should think of your data in terms of ownership: ask yourself a question, should the given struct own the data? In other words, does the data belong to the struct naturally or it can be used independently somewhere?
If you apply this reasoning to your structures:
struct Foo<'a> {
name: &'a str,
an_array: &'a [AnEnumType],
/* etc. */
}
struct Derived1<'a> {
foo: &'a Foo<'a>,
other_stuff: &'a str,
}
struct Derived2<'a> {
foo: &'a Foo<'a>,
/* etc. */
}
you would see that it doesn't really make sense to encode inheritance using references. If Derived1 has a reference to Foo, then it is implied that this Foo is created somewhere else, and Derived1 is only borrowing it for a while. While this may be something you really want, this is not how inheritance works: inherited structures/classes usually contain their "parent" contents inside them; in other words, they own their parent data, so this will be more appropriate structure:
struct Foo<'a> {
name: &'a str,
an_array: &'a [AnEnumType],
/* etc. */
}
struct Derived1<'a> {
foo: Foo<'a>
other_stuff: &'a str,
}
struct Derived2<'a> {
foo: Foo<'a>,
/* etc. */
}
Note that Derived* structures now include Foo into them.
As for strings and arrays (string slices and array slices in fact), then yes, if you want to hold them in structures you do have to use lifetime annotations. However, it does not happen that often, and, again, designing structures based on ownership usually helps to decide whether this should be a slice or a dynamically allocated String or Vec. There is a nice tutorial on strings, which explains, among everything else, when you need to use owned strings and when you need slices. Same reasoning applies to &[T]/Vec<T>. In short, if your struct owns the string/array, you have to use String/Vec. Otherwise, consider using slices.

Resources