I have a RegistrationRequest struct:
type RegistrationRequest struct {
Email *string
Email2 *string
Username *string
Password *string
Name string
}
Where Email2 is the email value entered again to verify that what the user entered is correct.
I also have a User struct:
type User struct {
Email *string
Username *string
Password *string
Name string
}
Of course, there is no need to store Email2 beyond registration.
So I have two variables: req and u - one for each struct. Is it possible to assign the req struct into to the u struct so that all the common fields will exist in the u struct?
Using simple assignment you can't because even though the fields of User are a subset of RegistrationRequest, they are completely 2 different types, and Assignability rules don't apply.
You could write a function which uses reflection (reflect package), and would copy all the fields from req to u, but that is just ugly (and inefficient).
Best would be to refactor your types, and RegistrationRequest could embed User.
Doing so if you have a value of type RegistrationRequest that means you already also have a value of User:
type User struct {
Email *string
Username *string
Password *string
Name string
}
type RegistrationRequest struct {
User // Embedding User type
Email2 *string
}
func main() {
req := RegistrationRequest{}
s := "as#as.com"
req.Email = &s
s2 := "testuser"
req.Username = &s2
u := User{}
u = req.User
fmt.Println(*u.Username, *u.Email)
}
Output: (try it on the Go Playground)
testuser as#as.com
Also please note that since your structs contain pointers, when copying a struct, pointer values will be copied and not pointed values. I'm not sure why you need pointers here, would be best to just declare all fields to be non-pointers.
Also note that embedding is not really a requirement, it just makes your types and their usage more smooth. User could just as well be an "ordinary" field of RequistrationRequest, e.g.:
type RegistrationRequest struct {
Usr User // This is just an ordinary field, not embedding
Email2 *string
}
You can use "github.com/jinzhu/copier" package to Copy between structs containing same field name. This package uses reflection to do this.
package main
import (
"fmt"
"github.com/jinzhu/copier"
)
type RegistrationRequest struct {
Email *string
Email2 *string
Username *string
Password *string
Name string
}
type User struct {
Email *string
Username *string
Password *string
Name string
}
func main() {
user := new(User)
req := new(RegistrationRequest)
user.Email, user.Password, user.Username = new(string), new(string), new(string)
user.Name = "John Doe"
*user.Email = "a#b.com"
*user.Password = "1234"
*user.Username = "johndoe"
fmt.Println("User :",user.Name, *user.Email, *user.Username, *user.Password)
copier.Copy(req, user)
fmt.Println("RegistrationRequest :",req.Name, *req.Email, *req.Username, *req.Password)
}
Output
User : John Doe a#b.com johndoe 1234
RegistrationRequest : John Doe a#b.com johndoe 1234
func ObjectAssign(target interface{}, object interface{}) {
// object atributes values in target atributes values
// using pattern matching (https://golang.org/pkg/reflect/#Value.FieldByName)
// https://stackoverflow.com/questions/35590190/how-to-use-the-spread-operator-in-golang
t := reflect.ValueOf(target).Elem()
o := reflect.ValueOf(object).Elem()
for i := 0; i < o.NumField(); i++ {
for j := 0; j < t.NumField(); j++ {
if t.Field(j).Name() == o.Field(i).Name() {
t.Field(j).Set(o.Field(i))
}
}
}
}
If the second structure is a clone of the first one with fewer fields you can convert the structures via json.
type user1 struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
UserName string `json:"user_name"`
}
type user2 struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
}
...
u1Json, _ := json.Marshal(u1)
_ = json.Unmarshal(u1Json,&u2)
Related
I have a type with three fields
type Person struct {
FirstName string
LastName string
Age int
}
Creating an instance and using default fmt.Sprint() returns {John Smith 45}. However for my use case I need a string of format John, Smith, 45. A comma delimited list without being surrounded by curly braces. Is there a more reusable and effective way than:
fmt.Sprintf("%s, %s, %d", x.FirstName, x.LastName, x.Age)
I will be using this method alot with other types and I would prefer a generic method rather than having to type out a format for each type I use:
func asFields(data interface{}) string {
// TODO logic here
}
That exact format is not supported by verbs of the fmt package.
The closest would be
s := fmt.Sprintf("%#v", p)
Which generates a string like:
main.Person{FirstName:"John", LastName:"Smith", Age:45}
If you exactly need what you posted in the question, you may use reflection to iterate over the fields and build the result like this:
func asFields(data interface{}) string {
v := reflect.ValueOf(data)
b := &strings.Builder{}
for i := 0; i < v.NumField(); i++ {
if i > 0 {
b.WriteString(", ")
}
b.WriteString(fmt.Sprint(v.Field(i).Interface()))
}
return b.String()
}
This indeed gives:
John, Smith, 45
Try the examples on the Go Playground.
Note that this asFields() function handles all struct types of course not just your Person. Adjustment would be needed to handle pointers and struct of structs of course.
Also note that alternatively to fmt.Sprint() you may also use fmt.Fprint() directed to the buffer in which we're assembling the string:
func asFields(data interface{}) string {
v := reflect.ValueOf(data)
b := &strings.Builder{}
for i := 0; i < v.NumField(); i++ {
if i > 0 {
b.WriteString(", ")
}
fmt.Fprint(b, v.Field(i).Interface())
}
return b.String()
}
Which of course gives the same result (and may or may not be faster, benchmark it). Try it on the Go Playground.
Can we use this approach, it will be applicable only to Person type struct though ?
https://play.golang.org/p/YI2Nu0q51ls
package main
import (
"fmt"
)
type Person struct {
FirstName string
LastName string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%s, %s, %d", p.FirstName, p.LastName, p.Age)
}
func main() {
p := Person{FirstName: "John",LastName: "Doe", Age: 25}
fmt.Printf("%v", p)
}
Output:
John, Doe, 25
Similar SO question:
ToString() function in Go
This is a follow-up to this question: Can I have a Swift protocol without functions
Suppose I want to add more properties to my protocol:
protocol Nameable {
var name: String {get}
var fullName: String: {get}
var nickName: String: {get}
}
However, not every struct that conforms to this protocol may have a fullName and/or nickName. How do I go about this? Can I make these two properties somehow optional? Or maybe I need three separate protocols? Or do I just add them to each struct, but leave them empty, like this:
struct Person : Nameable {
let name: String
let fullName: String
let nickName: String
let age: Int
// other properties of a Person
}
let person = Person(name: "Steve", fullName: "", nickName: "Stevie", age: 21)
That compiles and works, but I don't know if this is the 'correct' approach?
Unlike in Objective-C, you cannot define optional protocol requirements in pure Swift. Types that conform to protocols must adopt all the requirements specified.
One potential way of allowing for optional property requirements is defining them as optionals, with a default implementation of a computed property that just returns nil.
protocol Nameable {
var name : String? { get }
var fullName : String? { get }
var nickname : String? { get }
}
extension Nameable {
var name : String? { return nil }
var fullName : String? { return nil }
var nickname : String? { return nil }
}
struct Person : Nameable {
// Person now has the option not to implement the protocol requirements,
// as they have default implementations that return nil
// What's cool is you can implement the optional typed property requirements with
// non-optional properties – as this doesn't break the contract with the protocol.
var name : String
}
let p = Person(name: "Allan")
print(p.name) // Allan
However the downside to this approach is that you potentially pollute conforming types with properties that they don't implement (fullName & nickName in this case).
Therefore if it makes no logical sense for a type to have these properties (say you wanted to conform City to Nameable – but cities don't (really) have nicknames), you shouldn't be conforming it to Nameable.
A much more flexible solution, as you say, would be to define multiple protocols in order to define these requirements. That way, types can choose exactly what requirements they want to implement.
protocol Nameable {
var name : String { get }
}
protocol FullNameable {
var fullName : String { get }
}
protocol NickNameable {
// Even types that conform to NickNameable may have instances without nicknames.
var nickname : String? { get }
}
// A City only needs a name, not a fullname or nickname
struct City : Nameable {
var name : String
}
let london = City(name: "London")
// Person can have a name, full-name or nickname
struct Person : Nameable, FullNameable, NickNameable {
var name : String
var fullName: String
var nickname: String?
}
let allan = Person(name: "Allan", fullName: "Allan Doe", nickname: "Al")
You could even use protocol composition in order to define a typealias to represent all three of these protocols for convenience, for example:
typealias CombinedNameable = Nameable & FullNameable & NickNameable
struct Person : CombinedNameable {
var name : String
var fullName: String
var nickname: String?
}
You can give a default implementation to these property using protocol extension and override the property in classes/structs where actually you needed
extension Nameable{
var fullName: String{
return "NoFullName"
}
var nickName: String{
return "NoNickName"
}
}
struct Foo : Nameable{
var name: String
}
I'm working with json and golang. I've made a TCP server and, I need to Unmarshal the message to know which type of service is asked, before Unmarshal the contained data. It's a bit hard to explain so this is my code:
package main
import (
"fmt"
"encoding/json"
)
type Container struct {
Type string
Object interface{}
}
type Selling struct {
Surname string
Firstname string
//......
Price int
}
type Buying struct {
ID int
Surname string
Firstname string
//..........
}
/*
type Editing struct {
ID int
...............
}
Informations, etc etc
*/
func main() {
tmp_message_json1 := Selling{Surname: "X", Firstname: "Mister", Price: 10}
//tmp_message_json1 := Buying{ID: 1, Surname: "X", Firstname: "Mister"}
tmp_container_json1 := Container{Type: "Selling", Object: tmp_message_json1}
json_tmp, _ := json.Marshal(tmp_container_json1)
/*...........
We init tcp etc etc and then a message comes up !
...........*/
c := Container{}
json.Unmarshal(json_tmp, &c)
//I unmarshal a first time to know the type of service asked
// first question: Does Unmarshal need to be used only one time?
// does I need to pass c.Object as a string to unmarshal it in the called functions?
if c.Type == "Buying" {
takeInterfaceBuying(c.Object)
} else if c.Type == "client" {
takeInterfaceSelling(c.Object)
} else {
fmt.Println("bad entry")
}
}
func takeInterfaceBuying(Object interface{}) {
bu := Object
fmt.Println(bu.Firstname, bu.Surname, "wants to buy the following product:", bu.ID)
}
func takeInterfaceSelling(Object interface{}) {
se := Object
fmt.Println(se.Firstname, se.Surname, "wants to sell something for:", se.Price)
}
I need to handle messages which comes up like it, but I don't know if it's possible? does it possible?
Thank for help !
There is json.RawMessage for this purpose.
package main
import (
"encoding/json"
"fmt"
)
type Container struct {
Type string
Object json.RawMessage
}
type Selling struct {
Surname string
Firstname string
Price int
}
type Buying struct {
ID int
Surname string
Firstname string
}
func main() {
rawJson1 := []byte(`{"Type":"Selling","Object":{"Surname":"X","Firstname":"Mister","Price":10}}`)
rawJson2 := []byte(`{"Type":"Buying","Object":{"ID":1,"Surname":"X","Firstname":"Mister"}}`)
processMessage(rawJson1)
processMessage(rawJson2)
}
func processMessage(data []byte) {
var c Container
json.Unmarshal(data, &c)
switch {
case c.Type == "Buying":
processBuying(c)
case c.Type == "Selling":
processSelling(c)
default:
fmt.Println("bad entry")
}
}
func processBuying(c Container) {
var bu Buying
json.Unmarshal(c.Object, &bu)
fmt.Println(bu.Firstname, bu.Surname, "wants to buy the following product:", bu.ID)
}
func processSelling(c Container) {
var se Selling
json.Unmarshal(c.Object, &se)
fmt.Println(se.Firstname, se.Surname, "wants to sell something for:", se.Price)
}
I might be wrong, but I don't think you can do it in one step.
First idea: Unmarshal in map[string]interface{}
Don't use type with unmarshal, instead use a map[string]interface{}, and then construct Selling/Buying from this map (or use directly the map)
type Container struct {
Type string
Object map[string]interface{}
}
Second idea: Two steps / clueless container
First: Unmarshall in a clueless Container that doesn't know the type
type CluelessContainer struct {
Type string
Object interface{} `json:"-"` // or just remove this line ?
}
Then unmarshall in the type aware container. You could use a factory pattern to come with the right struct.
I would like to replace my global string constants with a nested enum for the keys I'm using to access columns in a database.
The structure is as follows:
enum DatabaseKeys {
enum User: String {
case Table = "User"
case Username = "username"
...
}
...
}
Each table in the database is an inner enum, with the name of the table being the enum's title. The first case in each enum will be the name of the table, and the following cases are the columns in its table.
To use this, it's pretty simple:
myUser[DatabaseKeys.User.Username.rawValue] = "Johnny"
But I will be using these enums a lot. Having to append .rawValue to every instance will be a pain, and it's not as readable as I'd like it to be. How can I access the String value without having to use rawValue? It'd be great if I can do this:
myUser[DatabaseKeys.User.Username] = "Johnny"
Note that I'm using Swift 2. If there's an even better way to accomplish this I'd love to hear it!
While I didn't find a way to do this using the desired syntax with enums, this is possible using structs.
struct DatabaseKeys {
struct User {
static let identifier = "User"
static let Username = "username"
}
}
To use:
myUser[DatabaseKeys.User.Username] = "Johnny"
Apple uses structs like this for storyboard and row type identifiers in the WatchKit templates.
You can use CustomStringConvertible protocol for this.
From documentation,
String(instance) will work for an instance of any type, returning its
description if the instance happens to be CustomStringConvertible.
Using CustomStringConvertible as a generic constraint, or accessing a
conforming type's description directly, is therefore discouraged.
So, if you conform to this protocol and return your rawValue through the description method, you will be able to use String(Table.User) to get the value.
enum User: String, CustomStringConvertible {
case Table = "User"
case Username = "username"
var description: String {
return self.rawValue
}
}
var myUser = [String: String]()
myUser[String(DatabaseKeys.User.Username)] = "Johnny"
print(myUser) // ["username": "Johnny"]
You can use callAsFunction (New in Swift 5.2) on your enum that conforms to String.
enum KeychainKey: String {
case userId
case email
}
func callAsFunction() -> String {
return self.rawValue
}
usage:
KeychainKey.userId()
You can do this with custom class:
enum Names: String {
case something, thing
}
class CustomData {
subscript(key: Names) -> Any? {
get {
return self.customData[key.rawValue]
}
set(newValue) {
self.customData[key.rawValue] = newValue
}
}
private var customData = [String: Any]()
}
...
let cData = CustomData()
cData[Names.thing] = 56
Edit:
I found an another solution, that working with Swift 3:
enum CustomKey: String {
case one, two, three
}
extension Dictionary where Key: ExpressibleByStringLiteral {
subscript(key: CustomKey) -> Value? {
get {
return self[key.rawValue as! Key]
}
set {
self[key.rawValue as! Key] = newValue
}
}
}
var dict: [String: Any] = [:]
dict[CustomKey.one] = 1
dict["two"] = true
dict[.three] = 3
print(dict["one"]!)
print(dict[CustomKey.two]!)
print(dict[.three]!)
If you are able to use User as dictionary key instead of String (User is Hashable by default) it would be a solution.
If not you should use yours with a nested struct and static variables/constants.
I've got two forms of struct declaration in the function scope. As far as I could see the bellow-listed snippet woks just fine. The question is what's the difference between the two declaration ways? Is that only a semantic question or there is something tricky under the covers?
package main
import "fmt"
func main() {
type Person1 struct {
Name string
Id int
}
person1 := &Person1{Name : "John Smith", Id : 10}
fmt.Printf("(%s, %d)\n", person1.Name, person1.Id)
var person2 struct {
name string
id int
}
person2.name = "Kenneth Box"
person2.id = 20
fmt.Printf("(%s, %d)\n", person2.name, person2.id)
}
One is a named type - you can create multiple variables of that type, if you need to, using the type name.
The other type has no name. You cannot create more variables of the type other than by using the := operator.
person1 is a pointer to a struct, while person2 is a struct value itself. If you had done person1 := Person1{Name : "John Smith", Id : 10} then it would be the same