Golang: convertor function - string

We have some structure S. Is it possible to make a converter so that the expression
s := S(a_string)
began to compile, where a_string is actually a string.

The allowed conversions are listed in Spec: Conversions. There's a section for "Conversions to and from a string type". Only those are allowed, you can't "extend" or change the behavior of conversions.
You may however always write a function that takes a string and returns a value of type S.
func Parse(s string) S {
var r S
// Parsing logic
return r
}
Using it is / looks like the same as a conversion:
s := Parse(a_string)

Related

Easy way to get string pointers

A library I am using has a very weird API that often takes string pointers. Currently I am doing this:
s := "foobar"
weirdFun(&s)
to pass strings. Is there a way to do this without the variable?
Maybe you should inform the author of the library, that the strings in Go are already references (to a structure, which is internally represented as a slice of runes), so no expensive copy operation is made by passing string to a function, it's call by reference.
Hope this helps!
The address operation &x can be used with addressable values.
According to the language specification:
The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.
So, you can work around this using a composite literal:
package main
import (
"fmt"
)
func main() {
s := "text"
fmt.Printf("value: %v, type: %T\n", &s, &s)
fmt.Printf("value: %v, type: %T\n", &[]string{"literal"}[0], &[]string{"literal"}[0])
}
Even though it's possible I don't recommend using this. This is not an example of clear code.
The Azure SDK uses string pointers to distinguish between no value and the empty string.
Use Azure's StringPtr function to create a pointer to a string literal.
import (
⋮
"github.com/Azure/go-autorest/autorest/to"
)
⋮
res, err := someClient.Create(ctx, someService.ExampleParameters{
Location: to.StringPtr(location),
})
The library is really weird, but
you can do this in one line with function wrap, for example
func PointerTo[T ~string](s T) *T {
return &s
}
s := "string"
weirdFun(PointerTo(s))

How to convert data type if Variant.Type is known?

How do I convert the data type if I know the Variant.Type from typeof()?
for example:
var a=5;
var b=6.9;
type_cast(b,typeof(a)); # this makes b an int type value
How do I convert the data type if I know the Variant.Type from typeof()?
You can't. GDScript does not have generics/type templates, so beyond simple type inference, there is no way to specify a type without knowing the type.
Thus, any workaround to cast the value to a type only known at runtime would have to be declared to return Variant, because there is no way to specify the type.
Furthermore, to store the result on a variable, how do you declare the variable if you don't know the type?
Let us have a look at variable declarations. If you do not specify a type, you get a Variant.
For example in this code, a is a Variant that happens to have an int value:
var a = 5
In this other example a is an int:
var a:int = 5
This is also an int:
var a := 5
In this case the variable is typed according to what you are using to initialized, that is the type is inferred.
You may think you can use that like this:
var a = 5
var b := a
Well, no. That is an error. "The variable type can't be inferred". As far as Godot is concerned a does not have a type in this example.
I'm storing data in a json file: { variable:[ typeof(variable), variable_value ] } I added typeof() because for example I store an int but when I reassign it from the file it gets converted to float (one of many other examples)
It is true that JSON is not good at storing Godot types. Which is why many authors do not recommend using JSON to save state.
Now, be aware that we can't get a variable with the right type as explained above. Instead we should try to get a Variant of the right type.
If you cannot change the serialization format, then you are going to need one big match statement. Something like this:
match type:
TYPE_NIL:
return null
TYPE_BOOL:
return bool(value)
TYPE_INT:
return int(value)
TYPE_REAL:
return float(value)
TYPE_STRING:
return str(value)
Those are not all the types that a Variant can hold, but I think it would do for JSON.
Now, if you can change the serialization format, then I will suggest to use str2var and var2str.
For example:
var2str(Vector2(1, 10))
Will return a String value "Vector2( 1, 10 )". And if you do:
str2var("Vector2( 1, 10 )")
You get a Variant with a Vector2 with 1 for the x, and 10 for the y.
This way you can always store Strings, in a human readable format, that Godot can parse. And if you want to do that for whole objects, or you want to put them in a JSON structure, that is up to you.
By the way, you might also be interested in ResourceFormatSaver and ResourceFormatLoader.

TypeScript > 4.1 Fixed Length String Literal Type

The TypeScript team has been doing great work on string literal typing in recent updates (4.1 & 4.2). I am wondering if there is a way to type a fixed length string.
Ex.
type LambdaServicePrefix = 'my-application-service';
type LambdaFunctionIdentifier = 'dark-matter-upgrader';
type LambdaFunctionName = `${LambdaServicePrefix}-${LambdaFunctionIdentifier}`; // error: longer than 32 characters...
How I imagine it would go is something like, Array<64, string>;. TypeScript has the Tuple type so as an array I could fix length of an array. [string, ... string * 62, string].
type FutureLambdaIdType = `${LambdaServicePrefix}-${string[32]}`;
UPDATED to reflect better recursive conditional type support
There are still, as of TS 4.7, no regular-expression-validated string types in TypeScript. Template literal types handle some, but not all, of the use cases for such regex types. If you have a situation like this where template literal types are insufficient, you might want to go to microsoft/TypeScript#41160 and describe your use case. The idea of a "string whose maximum length is N characters" for some N extends number would be easy enough to express with regex types, but is not easily achievable with template literals.
Still, let's see how close we can get.
A major roadblock stands in the way. TypeScript cannot easily represent the set of all strings less than N characters as a specific type StringsOfLengthUpTo<N>. Conceptually any given StringsOfLengthUpTo<N> is a large union, but since the compiler balks at unions with more than ~10,000 members, you can only describe strings of up to a few characters this way. Assuming you want to support the 95 characters of 7-bit printable ASCII, you will be able to represent StringsOfLengthUpTo<0>, StringsOfLengthUpTo<1>, and even StringsOfLengthUpTo<2>. But StringsOfLengthUpTo<3> would exceed the compiler's capacity, since it would be a union of over 800,000 members. So we have to give up on specific types.
Instead we can think of our type as a constraint used with generics. We need a type like TruncateTo<T, N> which takes a type T extends string and an N extends number and returns T truncated to N characters. Then we can constrain T extends TruncateTo<T, N> and the compiler would automatically warn on too-long strings.
It used to be that shallow recursion limits would prevent us from writing TruncateTo<T, N> for N greater than about 20 or so, but TypeScript 4.5 introduced support for tail recursion elimination on conditional types. That means we can write TruncateTo<T, N> by adding some extra accumulator arguments like this:
type TruncateTo<T extends string, N extends number,
L extends any[] = [], A extends string = ""> =
N extends L['length'] ? A :
T extends `${infer F}${infer R}` ? (
TruncateTo<R, N, [0, ...L], `${A}${F}`>
) :
A
This works by having an A accumulator to store the string we're building up, and an L arraylike accumulator that keeps track of how long that A string is (string literal types don't have a strongly typed length property, see ms/TS#34692 for the relevant request). We build up A one character at a time until we either run out of the original string, or until we reach a length of N. Let's see it in action:
type Fifteen = TruncateTo<"12345678901234567890", 15>;
// type Fifteen = "123456789012345"
type TwentyFive = TruncateTo<"123456789012345678901234567", 25>;
// type TwentyFive = "1234567890123456789012345"
We can't directly write T extends TruncateTo<T, N> as TypeScript complains that this is a circular constraint. But we can at least write a helper function like this:
const atMostN = <T extends string, N extends number>(
num: N, str: T extends TruncateTo<T, N> ? T : TruncateTo<T, N>
) => str;
and then you could call atMostN(32, "someStringLiteral") and it would either succeed or warn based on the the length of the string literal argument. Note that the str input is of a weird conditional type, whose sole purpose is to avoid the circular constraint. T is inferred from str, and then checked against TruncateTo<T, N>. If it succeeds, great. Otherwise, we give str the type of TruncateTo<T, N>, and we'll see an error message. It works like this:
const okay = atMostN(32, "ThisStringIs28CharactersLong"); // okay
type Okay = typeof okay; // "ThisStringIs28CharactersLong"
const bad = atMostN(32, "ThisStringHasALengthOf34Characters"); // error!
// -------------------> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// '"ThisStringHasALengthOf34Characters"' is not assignable to parameter of type
// '"ThisStringHasALengthOf34Characte"'.
type Bad = typeof bad; // "ThisStringHasALengthOf34Characte"
Is it worth it? Maybe. The original answer here had to do some unsavory things to get even a fixed-length check. The current one isn't so bad, but it's still a bunch of effort to get a compile-time check. So you might still have a use case for regex-validated string types.
Playground link to code
There is no way to represent fixed-length strings with Typescript. There is a very upvoted proposal here, but still this feature has not been released.
If the length is very little, there are some workarounds suchs as the following:
type Char = 'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j'|'k'|'l'|'m'|'n'|'o'|'p'|'q'|'r'|'s'|'t'|'u'|'v'|'w'|'x'|'y'|'z'
type String3 = `${Char}${Char}${Char}`
const a: String3 = 'aa' // error
const b: String3 = 'bbbbb' // error
const c: String3 = 'ccc' // OK
const d: String3 = 'abc' // OK
But you can't handle big lengths since you will run into a "Expression produces a union type that is too complex to represent" error.
It is impossible to limit the length of string by typing or typescript utils.
You can, however, use regex to validate the string (including length):
/^([a-zA-Z0-9_-]){1,64}$/
type IsThirteen<T extends number> = 13 extends T ? true : never
type IsFifteen<T extends number> = 15 extends T ? true : never
type LengthOfString<S extends string, T extends string[] = []> = S extends `${string}${infer R}`
? LengthOfString<R, [...T, string]>
: T['length'];
type IsLengthThirteenOrFifteen<T extends string> = true extends IsThirteen<LengthOfString<T>>
? T
: true extends IsFifteen<LengthOfString<T>>
? T
: never
function IsLengthThirteenOrFifteenGuard <T extends string>(a: IsLengthThirteenOrFifteen<T>) {
return a;
}
const b = IsLengthThirteenOrFifteenGuard('1131111111111')
Sources:
StringOfLength
Playground

Best way to convert string of digits into its numerical big.Rat value

I'm working with math/big.
I was wondering if somebody knows a short way to convert a string of digits like "2023930943509509" to a big.Rat type value.
I know .SetString() can be used for big.Int types, but can the same be done for the Rat type?
You don't have to learn these methods and functions by heart, whenever you look for something, check the package documentation. The doc of the package in question can be found here: math/big.
As you can see in the doc, there is a Rat.SetString() method for the big.Rat type too which you can use for this purpose:
func (z *Rat) SetString(s string) (*Rat, bool)
SetString sets z to the value of s and returns z and a boolean indicating success. s can be given as a fraction "a/b" or as a floating-point number optionally followed by an exponent. The entire string (not just a prefix) must be valid for success. If the operation failed, the value of z is un- defined but the returned value is nil.
Example using it:
r := big.NewRat(1, 1)
if _, ok := r.SetString("2023930943509509"); !ok {
fmt.Println("Failed to parse the string!")
}
fmt.Println(r)
fmt.Println(r.FloatString(2))
Output (try it on the Go Playground):
2023930943509509/1
2023930943509509.00

lua_isstring() check for real strings in Lua

int lua_isstring (lua_State *L, int index);
This function returns 1 if the value at the given acceptable index is
a string or a number (which is always convertible to a string), and 0
otherwise. (Source)
Is there a (more elegant) way to really proof if the given string really is a string and not a number in Lua? This function makes absolutely no sense to me!
My first idea is to additionally examine the string-length with
`if(string.len(String) > 1) {/* this must be a string */}`
... but that does not feel so good.
You can replace
lua_isstring(L, i)
which returns true for either a string or a number by
lua_type(L, i) == LUA_TSTRING
which yields true only for an actual string.
Similarly,
lua_isnumber(L, i)
returns true either for a number or for a string that can be converted to a number; if you want more strict checking, you can replace this with
lua_type(L, i) == LUA_TNUMBER
(I've written wrapper functions, lua_isstring_strict() and lua_isnumber_strict().)
This function makes absolutely no sense to me!
It makes sense in light of Lua's coercion rules. Any function that accepts a string should also accept a number, converting that number to a string. That's just how the language semantics are defined. The way lua_isstring and lua_tostring work allow you automatically implement those semantics in your C bindings with no additional effort.
If you don't like those semantics and want to disable automation conversion between string and number, you can define LUA_NOCVTS2N and/or LUA_NOCVTN2S in your build. In particular, if you define LUA_NOCVTN2S, lua_isstring will return false for numbers.

Resources