I want to write a Join function that takes arbitrary objects with a String() method:
package main
import (
"fmt"
"strings"
)
type myint int
func (i myint) String() string {
return fmt.Sprintf("%d", i)
}
func main() {
parts := []myint{myint(1), myint(5), myint(6)}
fmt.Println(Join(parts, ", "))
}
func Join(parts []fmt.Stringer, sep string) string {
stringParts := make([]string, len(parts))
for i, part := range(parts) {
stringParts [i] = part.String()
}
return strings.Join(stringParts , sep)
}
http://play.golang.org/p/EhkbyibzHw
[]myint cannot be passed to Join, because it is not of type fmt.Stringer, so I have to write:
parts := []fmt.Stringer{myint(1), myint(5), myint(6)}
But what if I need parts for another operation where the values have to be ints? Should I cast a slice of myint to a slice of Stringer then?
Q: Should I cast a slice of myint to a slice of Stringer then?
There are no casts in Go - only conversions. But conversion from a slice of concrete, non interface type to a slice of interface type is not possible, except by doing it explicitly in a loop. The reason is that, as for example in your case, the []myint backing array has a different memory layout than []fmt.Stringer has. (Related FAQ)
On a side note, you don't have to write:
parts := []myint{myint(1), myint(5), myint(6)}
This should work identically:
parts := []myint{1, 5, 6}
Change the Join function to
func Join(sep string, parts ...fmt.Stringer) string {
}
makes it a lot easier:
package main
import (
"fmt"
"strings"
)
type myint int
func (i myint) String() string {
return fmt.Sprintf("%d", i)
}
type myfloat float32
func (f myfloat) String() string {
return fmt.Sprintf("%0.2f", f)
}
func main() {
fmt.Println(Join(", ", myint(3), myfloat(3.5543)))
}
func Join(sep string, parts ...fmt.Stringer) string {
stringParts := make([]string, len(parts))
for i, part := range parts {
stringParts[i] = part.String()
}
return strings.Join(stringParts, sep)
}
Related
I would like to define a unlines function which works which any Sequence whose elements conform to the StringProtocol; this is my attempt:
func unlines<S: StringProtocol>(_ xs: Sequence<S>) -> S {
return xs.joined(separator: "\n")
}
Error: Use of protocol 'Sequence' as a type must be written 'any Sequence'
A version defined for a concrete type does work:
func unlines(_ xs: [String]) -> String {
return xs.joined(separator: "\n")
}
but can only be applied with list of String.
How can I develop a general definition ?
EDIT:
For example, I would like to apply it to the following value:
["Hello", "World"].lazy.map { $0.lowercased() }
joined returns a String so you need to change the return type and use any Sequence
func unlines<S: StringProtocol>(_ xs: any Sequence<S>) -> String {
return xs.joined(separator: "\n")
}
This then works both with String and Substring
String example:
let result = unlines(["A", "B", "C"])
Substring example:
let result = unlines("A-B-C".split(separator: "-"))
both returns
A
B
C
In Swift, you'd typically use a protocol extension to define instance functions that should operate on an instance, rather than using free functions that take a first argument.
Here's how that might work:
extension Sequence where Element: StringProtocol {
// FIXME: This is a pretty Haskelly, non-Swifty name
func unlines() -> String {
joined(separator: "\n")
}
}
let input = ["Hello", "World"]
.lazy
.map { $0.lowercased() }
.unlines()
print(input)
// Prints:
// hello
// world
I am trying to replicate the Array.reduce() method in my custom class and realised that it uses Result as type. Just could not understand that is the Result type been created as Enum or is it something else.
import Foundation
public class MyArray {
private var arr: [Int] = []
internal static var instance: MyArray?
private init() {}
public static func getInstance() -> MyArray {
if self.instance == nil {
self.instance = MyArray()
}
return self.instance!
}
public func insert(value val: Int) {
arr.append(val)
}
/*************** Custom reduce like function ***************/
public func perform(_ initialResult: Int, _ nextPartialResult: (Int, Int) -> Int) -> Int {
var result = initialResult
for element in arr {
result = nextPartialResult(result, element) // calling the closure
}
return result
}
}
Now accessing the MyArray class from outside
var arr1 = MyArray.getInstance()
arr1.insert(value: 1)
arr1.insert(value: 2)
arr1.insert(value: 4)
arr1.insert(value: 3)
arr1.insert(value: 2)
arr1.insert(value: 5)
arr1.insert(value: 2)
arr1.insert(value: 2)
// :Complex calculations left for user to implement
var result = arr1.perform(0) {
return $0 + ( $1 * $1)
}
print("Complex calculation in elements of MEMBER array of arr1: \(result)")
// :Just another way of writing the above closure
result = arr1.perform(0) { (result, num1) -> Int in
return result + ( num1 * num1)
}
print("Complex calculation in elements of MEMBER array of hello arr1: \(result)")
// :Simple calculations
print("Factorial of elements in MEMBER array of arr1: \(arr1.perform(1, *))")
print("Sum of elements in MEMBER array of arr1: \(arr1.perform(0, +))")
The problem is that I have to define my perform() function with one particular type at a time ( Int or String or Double etc ). I am trying to create my function to work with any type just like the reduce() function.
I am not able to understand how to define the Result type in my class and then use it in my function !!
I understand that Result type is not a part of standard library in swift.
The standard reduce function makes use of generics. See the Generics chapter in the Swift book.
func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
It has two generic types: Result and Element. Element comes from the type of the values in the collection and Result comes from the result type of the reduced value.
So your first step is to use the identical signature in your own perform function.
But in doing so you will discover that you now need to make your MyArray class also based on a generic instead of being hardcoded to work only with Int.
And in attempting to do that you will discover that you can't define MyArray to be generic and support the singleton pattern at the same time. So you need to remove instance and getIntance().
The end result becomes:
public class MyArray<Element> {
private var arr: [Element] = []
public init() {}
public func insert(value val: Element) {
arr.append(val)
}
/*************** Custom reduce like function ***************/
public func perform<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) -> Result) -> Result {
var result = initialResult
for element in arr {
result = nextPartialResult(result, element)
}
return result
}
}
With this in place, your first example becomes:
var arr1 = MyArray<Int>()
arr1.insert(value: 1)
arr1.insert(value: 2)
arr1.insert(value: 4)
arr1.insert(value: 3)
arr1.insert(value: 2)
arr1.insert(value: 5)
arr1.insert(value: 2)
arr1.insert(value: 2)
// :Complex calculations left for user to implement
var result = arr1.perform(0) {
return $0 + ( $1 * $1)
}
print(result)
And this outputs the desired result of 67.
In the end, it works but if you'll notice, there's no point to this MyArray class (other than a learning exercise). Just use Array.
Reference Go equivalent of a void pointer in C
this is a demo.
package main
import (
"fmt"
)
func map_exist(map_val map[string]interface{}, key string) bool {
_, ok := map_val[key]
return ok
}
func main() {
var one map[string][]string
one["A"] = []string{"a", "b", "c"}
fmt.Println(map_exist(one, "A"))
var two map[string]string
two["B"] = "a"
fmt.Println(map_exist(two, "B"))
}
run result:
./main.go:15: cannot use one (type map[string][]string) as type map[string]interface {} in argument to map_exist
./main.go:19: cannot use two (type map[string]string) as type map[string]interface {} in argument to map_exist
I can not find a data structure to be able to contain any type .
It's true that interface{} is kind of like C's void *, but you can't implicitly convert a map[string]string into a map[string]interface{}. The key is to define your map objects at their declaration as map[string]interface{} objects. Unfortunately, you cannot assign new values to such a map, since Go can't know how much memory to allocate for each instance.
func main() {
one := map[string]interface{} {
"A": []string{"a", "b", "c"},
}
fmt.Println(map_exist(one, "A"))
two := map[string]interface{} {
"B": "a",
}
fmt.Println(map_exist(two, "B"))
}
This works, but it probably isn't useful enough for your intended use case.
Another approach is to define a generic map interface and make sure that the functions you intend to use are defined for the types you want to support. Basically, your goal is to build a library that's useful enough that you can reasonably offload the work of implementing your interface to the library's users. It would be nice if you could declare a default function or maybe just a macro to prevent the copy-paste, but I'm not aware of such a mechanism.
Here's an example using an interface:
type GenericMap interface{
ValueForKey(string) (interface{}, bool)
}
type SliceMap map[string][]string
type StringMap map[string]string
type VoidMap map[string]interface{}
func map_exist(map_val GenericMap, key string) bool {
_, ok := map_val.ValueForKey(key)
return ok
}
func (map_val SliceMap) ValueForKey(key string) (interface{}, bool) {
val, ok := map_val[key]
return val, ok
}
func (map_val StringMap) ValueForKey(key string) (interface{}, bool) {
val, ok := map_val[key]
return val, ok
}
func (map_val VoidMap) ValueForKey(key string) (interface{}, bool) {
val, ok := map_val[key]
return val, ok
}
func main() {
one := SliceMap {
"A": []string{"a", "b", "c"},
}
fmt.Println(map_exist(GenericMap(one), "A"))
two := StringMap {
"B": "a",
}
fmt.Println(map_exist(GenericMap(two), "B"))
}
In the end, Go programmers tend to prefer a simple, straight-forward solution over all this misdirection, so your best bet is to just use the construct proposed by #Logiraptor:
if _, ok := m[key]; ok {
// You're ok!
}
Go does not support parametric polymorphism. What you're trying to do is only possible with reflection which will be much longer and more error prone than just using the _, ok := m[key] form. Usually you would write it like so:
if _, ok := m[key]; ok {
// do something conditionally.
}
I am trying to create a closure that keeps a reference to the local variable of the outer function and I keep getting this ambigious error int is not identical to unint8. It does not make sense to me because there no arrays involved here. There are also no UInt8s involved here too.
func increment(n:Int)-> ()->Int {
var i = 0
var incrementByN = {
() -> Int in
i += n
}
return incrementByN
}
var inner = increment(4)
inner()
inner()
inner()
I found that I can fix this by returning i after i+=n. I thought that i+=n would return on it's own but apparently it does not.
+= for (Int, Int) is declared as
func +=(inout lhs: Int, rhs: Int)
It returns nothing.
I don't know why UInt8 involves, though.
Maybe, it's because func +=(inout lhs: UInt8, rhs: UInt8) is the last one of func +=(...) declarations.
Not sure what the UInt8 is about, but it seems that += does not have a value.
var i = 1;
let x = i += 3; // now x is of type ()
You can explicitly return the new value of i:
var incrementByN = {
() -> Int in
i += n
return i
}
I'm writing some code, and I need it to catch the arguments and pass them through fmt.Println
(I want its default behaviour, to write arguments separated by spaces and followed by a newline). However it takes []interface {} but flag.Args() returns a []string.
Here's the code example:
package main
import (
"fmt"
"flag"
)
func main() {
flag.Parse()
fmt.Println(flag.Args()...)
}
This returns the following error:
./example.go:10: cannot use args (type []string) as type []interface {} in function argument
Is this a bug? Shouldn't fmt.Println take any array? By the way, I've also tried to do this:
var args = []interface{}(flag.Args())
but I get the following error:
cannot convert flag.Args() (type []string) to type []interface {}
Is there a "Go" way to workaround this?
This is not a bug. fmt.Println() requires a []interface{} type. That means, it must be a slice of interface{} values and not "any slice". In order to convert the slice, you will need to loop over and copy each element.
old := flag.Args()
new := make([]interface{}, len(old))
for i, v := range old {
new[i] = v
}
fmt.Println(new...)
The reason you can't use any slice is that conversion between a []string and a []interface{} requires the memory layout to be changed and happens in O(n) time. Converting a type to an interface{} requires O(1) time. If they made this for loop unnecessary, the compiler would still need to insert it.
In this case, a type conversion is unnecessary. Simply pass the flag.Args() value to fmt.Println.
Question:
Cannot convert []string to []interface {}
I'm writing some code, and I need it to catch the arguments and pass
them through fmt.Println (I want its default behaviour, to write
arguments separated by spaces and followed by a newline).
Here's the code example:
package main
import (
"fmt"
"flag"
)
func main() {
flag.Parse()
fmt.Println(flag.Args()...)
}
Package flag
import "flag"
func Args
func Args() []string
Args returns the non-flag command-line arguments.
Package fmt
import "fmt"
func Println
func Println(a ...interface{}) (n int, err error)
Println formats using the default formats for its operands and
writes to standard output. Spaces are always added between operands
and a newline is appended. It returns the number of bytes written and
any write error encountered.
In this case, a type conversion is unnecessary. Simply pass the flag.Args() value to fmt.Println, which uses reflection to interpret the value as type []string. Package reflect implements run-time reflection, allowing a program to manipulate objects with arbitrary types. For example,
args.go:
package main
import (
"flag"
"fmt"
)
func main() {
flag.Parse()
fmt.Println(flag.Args())
}
Output:
$ go build args.go
$ ./args arg0 arg1
[arg0 arg1]
$
If it's only a slice of strings you want to print, you can avoid conversion and get the exact same output by joining:
package main
import (
"fmt"
"flag"
"strings"
)
func main() {
flag.Parse()
s := strings.Join(flag.Args(), " ")
fmt.Println(s)
}
In Go, a function can only accept arguments of the types specified in the parameter list in the function definition. The variadic parameter language feature complicates that a bit, but it follows well-defined rules.
The function signature for fmt.Println is:
func Println(a ...interface{}) (n int, err error)
Per the language specifiction,
The final incoming parameter in a function signature may have a type prefixed with .... A function with such a parameter is called variadic and may be invoked with zero or more arguments for that parameter.
This means you can pass Println a list of arguments of interface{} type. Since all types implement the empty interface, you can pass a list of arguments of any type, which is how you're able to call Println(1, "one", true), for example, without error. See the "Passing arguments to ... parameters" section of the language specification:
the value passed is a new slice of type []T with a new underlying array whose successive elements are the actual arguments, which all must be assignable to T.
The part that's giving you trouble is right after that in the specification:
If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created.
flag.Args() is type []string. Since T in Println is interface{}, []T is []interface{}. So the question comes down to whether a string slice value is assignable to a variable of interface slice type. You can easily test that in your go code by attempting an assignment, for example:
s := []string{}
var i []interface{}
i = s
If you attempt such an assignment, the compiler will output this error message:
cannot use s (type []string) as type []interface {} in assignment
And that's why you can't use the ellipsis after a string slice as an argument to fmt.Println. It's not a bug, it's working as intended.
There are still lots of ways you can print flag.Args() with Println, such as
fmt.Println(flag.Args())
(which will output as [elem0 elem1 ...], per fmt package documentation)
or
fmt.Println(strings.Join(flag.Args(), ` `)
(which will output the string slice elements, each separated by a single space) using the Join function in the strings package with a string separator, for example.
Another option is to just iterate the slice:
package main
import "flag"
func main() {
flag.Parse()
for _, each := range flag.Args() {
println(each)
}
}
I think it's possible using reflection, but I don't know if it's a good solution
package main
import (
"fmt"
"reflect"
"strings"
)
type User struct {
Name string
Age byte
}
func main() {
flag.Parse()
fmt.Println(String(flag.Args()))
fmt.Println(String([]string{"hello", "world"}))
fmt.Println(String([]int{1, 2, 3, 4, 5, 6}))
u1, u2 := User{Name: "John", Age: 30},
User{Name: "Not John", Age: 20}
fmt.Println(String([]User{u1, u2}))
}
func String(v interface{}) string {
val := reflect.ValueOf(v)
if val.Kind() == reflect.Array || val.Kind() == reflect.Slice {
l := val.Len()
if l == 0 {
return ""
}
if l == 1 {
return fmt.Sprint(val.Index(0))
}
sb := strings.Builder{}
sb.Grow(l * 4)
sb.WriteString(fmt.Sprint(val.Index(0)))
for i := 1; i < l; i++ {
sb.WriteString(",")
sb.WriteString(fmt.Sprint(val.Index(i)))
}
return sb.String()
}
return fmt.Sprintln(v)
}
Output:
$ go run .\main.go arg1 arg2
arg1,arg2
hello,world
1,2,3,4,5,6
{John 30},{Not John 20}
fmt.Println takes variadic parameter
func Println(a ...interface{}) (n int, err error)
Its possible to print flag.Args() without converting into []interface{}
func main() {
flag.Parse()
fmt.Println(flag.Args())
}