Adding a integer value to string on a single statement - string

I was wondering how can I add an integer value to a string value like "10". I know I can accomplish this by converting the string into an int first and then after adding the integer I can convert it back into string. But can I accomplish this in a single statement in golang. For example I can do this with multiple lines like this:
i, err := strconv.Atoi("10")
// handle error
i = i + 5
s := strconv.Itoa(i)
But is there any way that I can accomplish this in a single statement?

There is no ready function in the standard library for what you want to do. And the reason for that is because adding a number to a number available as a string and having the result as another string is (terribly) inefficient.
The model (memory representation) of the string type does not support adding numbers to it efficiently (not to mention that string values are immutable, a new one has to be created); the memory model of int does support adding efficiently for example (and CPUs also have direct operations for that). No one wants to add ints to numbers stored as string values. If you want to add numbers, have your numbers ready just as that: numbers. When you want to print or transmit, only then convert it to string (if you must).
But everything becomes a single statement if you have a ready util function for it:
func add(s string, n int) (string, error) {
i, err := strconv.Atoi(s)
if err != nil {
return "", err
}
return strconv.Itoa(i + n), nil
}
Using it:
s, err := add("10", 5)
fmt.Println(s, err)
Output (try it on the Go Playground):
15 <nil>

Related

How to convert String to Primitive.ObjectID in Golang?

There are questions similar to this. But mostly they are using Hex()(like here) for primitive Object to String conversion. I'm using String() for conversion. How do I convert it back to primitive Object type ?
The String() method of types may result in an arbitrary string representation. Parsing it may not always be possible, as it may not contain all the information the original value holds, or it may not be "rendered" in a way that is parsable unambiguously. There's also no guarantee the "output" of String() doesn't change over time.
Current implementation of ObjectID.String() does this:
func (id ObjectID) String() string {
return fmt.Sprintf("ObjectID(%q)", id.Hex())
}
Which results in a string like this:
ObjectID("4af9f070cc10e263c8df915d")
This is parsable, you just have to take the hex number, and pass it to primitive.ObjectIDFromHex():
For example:
id := primitive.NewObjectID()
s := id.String()
fmt.Println(s)
hex := s[10:34]
id2, err := primitive.ObjectIDFromHex(hex)
fmt.Println(id2, err)
This will output (try it on the Go Playground):
ObjectID("4af9f070cc10e263c8df915d")
ObjectID("4af9f070cc10e263c8df915d") <nil>
This solution could be improved to find " characters in the string representation and use the indices instead of the fixed 10 and 34, but you shouldn't be transferring and parsing the result of ObjectID.String() in the first place. You should use its ObjectID.Hex() method in the first place, which can be passed as-is to primitive.ObjectIDFromHex().

How does type conversion internally work? What is the memory utilization for the same?

How does Go type conversion internally work?
What is the memory utilisation for a type cast?
For example:
var str1 string
str1 = "26MB string data"
byt := []byte(str1)
str2 := string(byt)
whenever I type convert any variable, will it consume more memory?
I am concerned about this because when I try to unmarshall, I get "fatal error: runtime: out of memory"
err = json.Unmarshal([]byte(str1), &obj)
str1 value comes from HTTP response, but read using ioutils.ReadAll, hence it contains the complete response.
It's called conversion in Go (not casting), and this is covered in Spec: Conversions:
Specific rules apply to (non-constant) conversions between numeric types or to and from a string type. These conversions may change the representation of x and incur a run-time cost. All other conversions only change the type but not the representation of x.
So generally converting does not make a copy, only changes the type. Converting to / from string usually does, as string values are immutable, and for example if converting a string to []byte would not make a copy, you could change the content of the string by changing elements of the resulting byte slice.
See related question: Does convertion between alias types in Go create copies?
There are some exceptions (compiler optimizations) when converting to / from string does not make a copy, for details see golang: []byte(string) vs []byte(*string).
If you already have your JSON content as a string value which you want to unmarshal, you should not convert it to []byte just for the sake of unmarshaling. Instead use strings.NewReader() to obtain an io.Reader which reads from the passed string value, and pass this reader to json.NewDecoder(), so you can unmarshal without having to make a copy of your big input JSON string.
This is how it could look like:
input := "BIG JSON INPUT"
dec := json.NewDecoder(strings.NewReader(input))
var result YourResultType
if err := dec.Decode(&result); err != nil {
// Handle error
}
Also note that this solution can further be optimized if the big JSON string is read from an io.Reader, in which case you can completely omit reading it first, just pass that to json.NewDecoder() directly, e.g.:
dec := json.NewDecoder(jsonSource)
var result YourResultType
if err := dec.Decode(&result); err != nil {
// Handle error
}

Easy way to get a sub-string/sub-slice of up to N characters/elements in Go

In Python I can slice a string to get a sub-string of up to N characters and if the string is too short it will simply return the rest of the string, e.g.
"mystring"[:100] # Returns "mystring"
What's the easiest way to do the same in Go? Trying the same thing panics:
"mystring"[:100] // panic: runtime error: slice bounds out of range
Of course, I can write it all manually:
func Substring(s string, startIndex int, count int) string {
maxCount := len(s) - startIndex
if count > maxCount {
count = maxCount
}
return s[startIndex:count]
}
fmt.Println(Substring("mystring", 0, n))
But that's rather a lot of work for something so simple and (I would have thought) common. What's more, I don't know how to generalise this function to slices of other types, since Go doesn't support generics. I'm hoping there is a better way. Even Math.Min() doesn't easily work here, because it expects and returns float64.
Note that while a function remains the recommended solution (even if it has to be implemented for slices with different type), it wouldn't work well with string.
fmt.Println(Substring("世界mystring", 0, 5)) would actually print 世�� instead of 世界mys.
See "Code points, characters, and runes": a character may be represented by a number of different sequences of code points, and therefore different sequences of UTF-8 bytes.
And in Go, a "code point" is a rune (as seen here).
Using rune would be more robust (again, in case of strings)
func SubstringRunes(s string, startIndex int, count int) string {
runes := []rune(s)
length := len(runes)
maxCount := length - startIndex
if count > maxCount {
count = maxCount
}
return string(runes[startIndex:count])
}
See it in action in this playground.

Go - Comparing strings/byte slices input by the user

I am getting input from the user, however when I try to compare it later on to a string literal it does not work. That is just a test though.
I would like to set it up so that when a blank line is entered (just hitting the enter/return key) the program exits. I don't understand why the strings are not comparing because when I print it, it comes out identical.
in := bufio.NewReader(os.Stdin);
input, err := in.ReadBytes('\n');
if err != nil {
fmt.Println("Error: ", err)
}
if string(input) == "example" {
os.Exit(0)
}
string vs []byte
string definition:
string is the set of all strings of 8-bit bytes, conventionally but not necessarily representing UTF-8-encoded text. A string may be empty, but not nil. Values of string type are immutable.
byte definition:
byte is an alias for uint8 and is equivalent to uint8 in all ways. It is used, by convention, to distinguish byte values from 8-bit unsigned integer values.
What does it mean?
[]byte is a byte slice. slice can be empty.
string elements are unicode characters, which can have more then 1 byte.
string elements keep a meaning of data (encoding), []bytes not.
equality operator is defined for string type but not for slice type.
As you see they are two different types with different properties.
There is a great blog post explaining different string related types [1]
Regards the issue you have in your code snippet.
Bear in mind that in.ReadBytes(char) returns a byte slice with char inclusively. So in your code input ends with '\n'. If you want your code to work in desired way then try this:
if string(input) == "example\n" { // or "example\r\n" when on windows
os.Exit(0)
}
Also make sure that your terminal code page is the same as your .go source file. Be aware about different end-line styles (Windows uses "\r\n"), Standard go compiler uses utf8 internally.
[1] Comparison of Go data types for string processing.

Ada string comparison

I am new to Ada and currently trying to write a simple program involving an if-else if statement. The code is as follows:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Year_Codes is
Year : String(1..9) := " ";
CharsRead : Natural;
function YearCode(Name : in String) return Integer is
begin
if(Name = "freshman")then
return 1;
elsif(Name = "sophomore")then
return 2;
elsif(Name = "junior")then
return 3;
elsif(Name = "senior")then
return 4;
else
return 0;
end if;
end YearCode;
begin
Put("Enter your academic year: "); -- Prompt for input
Get_Line(Year, CharsRead); -- Input
Put( YearCode(Year) ); -- Convert and output
New_Line;
end Year_Codes;
I am getting 0 for every answer. Any input on what I am doing wrong?
The "=" operation on strings compares the entire strings. If the user's input is "freshman", the value of Name will be "freshman ", not "freshman". Read the documentation for the Get_Line procedure.
You should probably pass YearCode a slice of the Year string, not the entire string; CharsRead tells you what that slice should be.
Specifically, the call should be:
Put( YearCode(Year(Year'First..CharsRead)) );
Here's a case-insensitive version using attributes:
function YearCode(Name : in String) return Integer is
Type Class is (Freshman, Sophmore, Junior, Senior);
begin
Return 1 + Class'Pos(Class'Value(Name));
exception
When CONSTRAINT_ERROR => Return 0;
end YearCode;
With that extra character in your buffer, it looks to me like you are thinking of strings in C terms. You need to stop that. Of everything in the language, string handling is the most different between Ada and C.
While C strings are null terminated, Ada strings are not. Instead, an Ada string is assumed to be the size of the string array object. Its a simple difference, but it has enormous consequences in how you handle strings.
I go into this a bit in my answer to How to I build a string from other strings in Ada? The basic gist is that in Ada you always try to build perfectly-sized string objects on the fly.
Sadly, Text_IO input is one place that has traditionally made that really hard, due to its string buffer-based input. In that case, you are forced to use an overly large string object as a buffer, and use the returned value as the end of the defined area of the buffer, as Keith showed.
However, if you have a new version of the compiler, you can use the function version of Get_Line to fix that. Simply change your middle two lines to:
Put( YearCode(Get_Line) );

Resources