In trying to understand Go, I ran into this piece of code in websocket.go (snipped):
type frameHandler interface {
HandleFrame(frame frameReader) (r frameReader, err error)
WriteClose(status int) (err error)
}
// Conn represents a WebSocket connection.
type Conn struct {
config *Config
request *http.Request
.
.
frameHandler
PayloadType byte
defaultCloseStatus int
}
In the Conn type the frameHandler stands there all alone? An interface without a name?
Later on in the code they even try check if the poor interface is nil:
Conn(a).frameHandler == nil
My own guess is that the frameHandler within the struct is a type which matches the frameHandler interface, and on top of that will have the name frameHandler. Is this correct? Hehe, fun language anyhow.
This line:
frameHandler
is roughly equivalent to this:
frameHandler frameHandler
in that frameHandler is both the name of the field and its type. In addition, it adds all the fields and methods of the frameHandler to the Conn, so if conn is a Conn, then conn.WriteClose(0) means conn.frameHandler.WriteClose(0).
As the Go Programming Language Specification puts it:
A field declared with a type but no explicit field name is an anonymous field (colloquially called an embedded field). Such a field type 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. The unqualified type name acts as the field name. // A struct with four anonymous fields of type T1, *T2, P.T3 and *P.T4
struct {
T1 // field name is T1
*T2 // field name is T2
P.T3 // field name is T3
*P.T4 // field name is T4
x, y int // field names are x and y
} The following declaration is illegal because field names must be unique in a struct type: struct {
T // conflicts with anonymous field *T and *P.T
*T // conflicts with anonymous field T and *P.T
*P.T // conflicts with anonymous field T and *T
} Fields and methods (§Method declarations) of an anonymous field are promoted to be ordinary fields and methods of the struct (§Selectors). The following rules apply for a struct type named S and a type named T:
If S contains an anonymous field T, the
method set of S includes the
method set of T.
If S contains an anonymous field *T, the
method set of S includes the method set of *T
(which itself includes the method set of T).
If S contains an anonymous field T or
*T, the method set of *S includes the
method set of *T (which itself includes the method
set of T).
A field declaration may be followed by an optional string literal tag, which becomes an attribute for all the fields in the corresponding field declaration. The tags are made visible through a reflection interface but are otherwise ignored. // A struct corresponding to the TimeStamp protocol buffer.
// The tag strings define the protocol buffer field numbers.
struct {
microsec uint64 "field 1"
serverIP6 uint64 "field 2"
process string "field 3"
}
Related
// it compiles without any problems, regardless ModifiedContent is not a View
func modify(with viewModifier: some ViewModifier) -> some View {
let content: ModifiedContent<Self, some ViewModifier> = modifier(viewModifier)
return content
}
but if we write same in generic way, we got expected error message
func modify<V>(with viewModifier: some ViewModifier) -> V where V : View {
let content: ModifiedContent<Self, some ViewModifier> = modifier(viewModifier)
return content // error: Cannot convert return expression of type
// 'ModifiedContent<Self, some ViewModifier>' to return type 'V'
}
Here's your first, working declaration:
func modify(with viewModifier: some ViewModifier) -> some View
You used the some keyword twice in that function declaration. It is important to understand that some means different things in those two uses.
In the first use (viewModifier: some ViewModifier), the some keyword is “syntactic sugar” for a implicit, unnamed generic parameter. We can de-sugar the use of some there by replacing it with an explicit, named generic parameter, like this:
// Replace `some` in parameter position with an explicit generic parameter:
func modify<VM: ViewModifier>(with viewModifier: VM) -> some View
When you call that modify method, you as the caller choose a real type to replace the VM parameter. So you can call modify many times, with a different type to replace VM each time. The only constraint is the replacement type must always conform to the ViewModifier protocol.
The second use of some in your first function declaration (in -> some View) has a different meaning. It means the function will return a value whose type conforms to View, but the specific type is chosen by the body of the function. You as the function caller do not choose the type.
To summarize the differences:
The some keyword in parameter position
represents an implicit, unnamed generic type parameter;
can be de-sugared to an explicit, named generic parameter without changing the function body;
is replaced by a type chosen by the caller of the function.
The some keyword in return type position
represents a type known to conform to a protocol;
is a type chosen by the body of the function.
Now let's look at your second, broken function declaration:
func modify<V>(with viewModifier: some ViewModifier) -> V where V : View
This is like your first function declaration, except that you have replaced the some in return type position with the generic parameter V.
The problem is that these don't mean the same things. As I explained above, a return type of some View means the function body chooses the actual type, but a generic parameter is always chosen by the caller of the function.
That's why you get the error when your function tries to return content. There's no guarantee that content has type V. Your function knows so little about type V (you only know it conforms to View) that there's no way for the function to even create a value of type V (because the View protocol doesn't have any init requirements).
You also have this comment on your first, working function declaration:
// it compiles without any problems, regardless ModifiedContent is not a View
I assume you declared the modify(withViewModifier:) method in an extension View. That means Self conforms to View, so ModifiedContent<Self, some ViewModifier> conforms to View.
ModifiedContent is a generic View so you can return it as opaque result type some View.
when returning -> V where V : View ModifiedContent has to match any V type where it is called from, which is not possible.
see as well: https://forums.swift.org/t/how-to-use-a-generic-type-as-the-functions-return-type/37666/2
Thanks to #robmayoff and #jrturton i finally figured out.
ModifiedContent conforms to some View because ModifiedContent conditionally conforms to View. We can make sure of this by watching definition of ModifiedContent. If we scroll down, we can see:
extension ModifiedContent : View where Content : View, Modifier : ViewModifier { ... }
I have the following struct:
struct Thing<VerticalOffsetRange: RangeExpression> {
var verticalOffsetRange: VerticalOffsetRange
}
I'm using the type parameter VerticalOffsetRange because I'd like to accept both open ranges (Range) and closed ranges (ClosedRange). I cannot use RangeExpression directly as the type for the verticalOffsetRange property because it has associated type or self requirements.
Now I'd like to provide a default value for that property, so that when the struct is initialized with the default memberwise initializer, the verticalOffsetRange parameter is optional.
struct Thing<VerticalOffsetRange: RangeExpression> {
var verticalOffsetRange: VerticalOffsetRange = 0..<2
// BOOM: Cannot convert value of type 'Range<Int>' to specified type 'VerticalOffsetRange'
}
This does not compile (error shown in line with comment). I'm certain that the value 0..<2 does conform to the RangeExpression protocol because before adding the default value, the following code works.
let myThing = Thing(verticalOffsetRange: 0..<2)
How can I provide a default value for the verticalOffsetRange property?
Note: This is a simplified version of the code I'm actually trying to write. But I think this is the part I'm stuck on at the moment.
If you want the verticalOffsetRange parameter to be optional, you can add it as a specialized init that applies when the type can be inferred:
extension Thing where VerticalOffsetRange == Range<Int> {
init() {
self.verticalOffsetRange = 0..<2
}
}
Then Thing() will implicitly mean a Thing<Range<Int>> with the value you'd like, if Thing<Range<Int>> is valid in the context.
I have a slice of structs that I want to pass into a stored procedure to be used as an array of user defined types t but I can't figure out a way of doing this is in Go.
For example the structs in go:
type a struct {
ID int `db:"id"`
Name string `db:"name"`
Created time.Time `db:"created"`
IsNew bool `db:"is_new"`
}
And the create statement for the user defined type
CREATE TYPE custom_type AS
(
id int,
name varchar,
created timestamp,
is_new boolean
)
and then the stored procedure
create or replace procedure custom_procedure(
input custom_type[]
)
So far I have tried doing
func Save(records []a) error {
_, err := p.client.Exec("CALL custom_procedure($1)", pq.Array(records))
return err
}
but I just get an error "sql: converting argument $1 type: unsupported type a, a struct"
You'll have to implement the driver.Valuer interface on the a type and have the Value method return a postgres composite type literal of the instance of a.
You can read this documentation on how to properly construct composite row type values. Just keep in mind that, since you're using pq.Array, which will quote the output of the Value method, you yourself SHOULD NOT put quotes around the output and also you SHOULD NOT use the ROW keyword.
For example:
type a struct {
ID int `db:"id"`
Name string `db:"name"`
Created time.Time `db:"created"`
IsNew bool `db:"is_new"`
}
func (v a) Value() (driver.Value, error) {
s := fmt.Sprintf("(%d,%q,%s,%t)",
v.ID,
v.Name,
v.Created.Format("2006-01-02 15:04:05"),
v.IsNew,
)
return []byte(s), nil
}
I need to convert an Integer value to String. I made a variable with an Integer value and then I have printed that using print. What is the different between the below approaches?
var word = "Count is "
var count = 100
print(word+String(describing: count)); // Count is 100
print(word+String(count)); // Count is 100
Your question is actually unnecessary because if all you want to do here is print, you can just do it directly:
print("Count is", count) // Count is 100
That's because print takes a variadic parameter and inserts space as the default separator.
However, let's answer the question anyway.
Answer
It's the difference between coercion and representation.
Coercion. Certain types can be changed into certain other types. You can change a Double to an Int and an Int to a Double. You can change an Int to a String and a String (maybe) to an Int. This is possible because the second type has an initializer whose parameter is the first type. This is something you would do in your actual program, like this:
let sum : Int = x + y
self.myLabel.text = "Your total is \(String(sum))"
Representation. For debugging purposes, all types can benefit from being representable as a string. Suppose you have a Person type. You can't change a Person to a String and vice versa — that makes no sense — but you would surely like to be able to print a Person to the console to see if you are getting the right results. This is possible because the Person type itself supplies a printable description. This is something you would do for debugging purposes:
let p = Person(first:"Matt", last:"Neuburg")
print("p is \(String(describing:p))")
Comments
Comment 1. This distinction is fairly new in Swift. It used to be that String(...) was used to express both notions. But the powers that be realized that that was a confusing conflation of the two distinct mechanisms. So nowadays, an attempt to write String(p) will fail, whereas earlier it would have succeeded. String has no Person initializer, so String(p) is forbidden; you now have to say explicitly that you are describing, not coercing.
Comment 2. The need to print a description is so obviously common that you do not have to pass thru String(describing:) if all you want to do is log the object itself. You can write print(p), because this is a shorthand for print(String(describing:p)). Similarly, string interpolation calls String(describing:) for you, so you can write print("p is \(p)"). And, as I said at the outset, print takes a variadic parameter and inserts space as the default separator, so you can write print("p is", p).
Reading the docs might help!
Here's an excerpt from String.init(describing:)
Use this initializer to convert an instance of any type to its
preferred representation as a String instance. The initializer creates
the string representation of instance in one of the following ways,
depending on its protocol conformance:
If instance conforms to the TextOutputStreamable protocol, the result is obtained by calling instance.write(to: s) on an empty string
s.
If instance conforms to the CustomStringConvertible protocol, the result is instance.description.
If instance conforms to the CustomDebugStringConvertible protocol, the result is instance.debugDescription.
An unspecified result is supplied automatically by the Swift standard library.
Int conforms to CustomStringConvertible, so String(describing: someInt) is the same as someInt.description.
Now let's look at String(someInt), this calls this initializer:
public init<T>(_ value: T) where T : LosslessStringConvertible
Int also conforms to LosslessStringConvertible. In fact, LosslessStringConvertible inherits from CustomStringConvertible. LosslessStringConvertible specifies only one requirement - an initializer that takes a string.
The docs for init<T>(_:) says this:
Creates an instance from the description of a given LosslessStringConvertible instance.
Even though description is not in a monospace font, I am quite sure (though not 100%) that this refers to the description property of CustomStringConvertible.
Assuming that init<T>(_:) indeed returns the description, String(describing: someInt) always returns the same value as String(someInt).
Note that this does not hold true for all types. It only holds true for types that conforms to LosslessStringConvertible but not TextOutputStreamable. If you have a type that conforms to both, results can be different:
struct A: TextOutputStreamable, LosslessStringConvertible {
init?(_ description: String) { }
init() { }
var description: String {
return "foo"
}
func write<Target>(to target: inout Target) where Target : TextOutputStream {
target.write("bar")
}
}
String(describing: A()) // bar
String(A()) // foo
I have a function as below which decodes some json data and returns it as an interface
package search
func SearchItemsByUser(r *http.Request) interface{} {
type results struct {
Hits hits
NbHits int
NbPages int
HitsPerPage int
ProcessingTimeMS int
Query string
Params string
}
var Result results
er := json.Unmarshal(body, &Result)
if er != nil {
fmt.Println("error:", er)
}
return Result
}
I'm trying to access the data fields ( e.g. Params) but for some reasons it says that the interface has no such field. Any idea why ?
func test(w http.ResponseWriter, r *http.Request) {
result := search.SearchItemsByUser(r)
fmt.Fprintf(w, "%s", result.Params)
An interface variable can be used to store any value that conforms to the interface, and call methods that art part of that interface. Note that you won't be able to access fields on the underlying value through an interface variable.
In this case, your SearchItemsByUser method returns an interface{} value (i.e. the empty interface), which can hold any value but doesn't provide any direct access to that value. You can extract the dynamic value held by the interface variable through a type assertion, like so:
dynamic_value := interface_variable.(typename)
Except that in this case, the type of the dynamic value is private to your SearchItemsByUser method. I would suggest making two changes to your code:
Define your results type at the top level, rather than within the method body.
Make SearchItemsByUser directly return a value of the results type instead of interface{}.