Assuming I have an int64 variable (or other integer size) representing a valid unicode code-point, and I want to convert it into a rune in Go, what do I do?
In C I would have used a type cast something like:
c = (char) i; // 7 bit ascii only
But in Go, a type assertion won't work:
c, err = rune.( i)
Suggestions?
You just want rune(i). Casting is done via type(x).
Type assertions are something different. You use a type assertion when you need to go from a less specific type (like interface{}) to a more specific one. Additionally, a cast is checked at compile time, where type assertions happen at runtime.
Here's how you use a type assertion:
var (
x interface{}
y int
z string
)
x = 3
// x is now essentially boxed. Its type is interface{}, but it contains an int.
// This is somewhat analogous to the Object type in other languages
// (though not exactly).
y = x.(int) // succeeds
z = x.(string) // compiles, but fails at runtime
In Go, you want to do a conversion.
Conversions
Conversions are expressions of the form T(x) where T is a type and
x is an expression that can be converted to type T.
Conversion = Type "(" Expression ")" .
A non-constant value x can be converted to type T in any of these
cases:
x is assignable to T.
x's type and T have identical underlying types.
x's type and T are unnamed pointer types and their pointer base types have identical underlying types.
x's type and T are both integer or floating point types.
x's type and T are both complex types.
x is an integer or has type []byte or []rune and T is a string type.
x is a string and T is []byte or []rune.
You want to convert x, of type int, int32, or int64, to T of type rune, an alias for type int32. x's type and T are both integer types.
Therefore, T(x) is allowed and is written rune(x), for your example, c = rune(i).
Related
I'm just starting to learn OCaml, and I was confused by how the OCaml compiler determines the input type of arguments in certain situations where the argument could be multiple types. I'm assuming I would need to explicitly state the type in these instances? For example:
let sign x =
if x > 0 then 1
else if x < 0 then -1
else 0
let _ = print_int(sign 1.5)
Throws "Error: This expression has type float but an expression was expected of type int"
But don't the comparison operators work with floats as well? Why does the compiler assume that the argument should be an int instead of saying something like the argument type is ambiguous (unless I'm mistaken and the type actually is not ambiguous)?
The built-in comparison operators in OCaml have the following type signature:
'a -> 'a -> bool. Note that while the argument types are generic ('a), they are both the same. So, when you have a comparison like x < 0, the compiler sees that the type of the second argument is int and then infer that the type of x must be int as well. Changing your comparisons to use floats, e.g. x < 0. will make your code type-check, but then it would no longer work for int inputs.
I have a c++ project that have a struct with int32_t member data type and i want to assign bool and float variables to it, will that ruin the value of the variable? If yes, what should i do other than changing the struct member data type?
Whenever the compiler has to use a value of a type in a context where another type is expected, an implicit conversion is performed.
The rules for implicit conversions are numerous, but under Floating–integral conversions, there is the following paragraph:
A prvalue of floating-point type can be converted to a prvalue of any
integer type. The fractional part is truncated, that is, the
fractional part is discarded. If the value cannot fit into the
destination type, the behavior is undefined (even when the destination
type is unsigned, modulo arithmetic does not apply). If the
destination type is bool, this is a boolean conversion (see below).
So, you can safely assign a floating point type (e.g. float or double) to an integer. Provided that the value can fit, the decimal part will be truncated. This implies a loss of data, and might be a source of bugs, or might be done on purpose in certain applications. Note that the floating point types have a larger range than int32_t, and if the value cannot be stored, it is undefined behaviour as per the standard.
Bools, on the other hand, can be safely assigned to integer types under all circumstances:
If the source type is bool, the value false is converted to zero and
the value true is converted to the value one of the destination type
(note that if the destination type is int, this is an integer
promotion, not an integer conversion).
The value you assign will be converted to int32_t. The bool value will not lose anything. The float value will be truncated. Only the integral part of it will be stored.
If yes, what should i do other than changing the struct member data type?
That depends on whether the type of the values you want to store are determined at runtime or compile-time. If it's determined at runtime, you can use an std::any instead of an int32_t:
#include <any>
struct MyStruct {
std::any val;
};
// ...
MyStruct s;
s.val = true; // val now contains a bool
s.val = 3.1415; // val now contains a double
s.val = 3.1415f; // val now contains a float
s.val = 42; // val now contains an int
If the type is determined at compile-time, you can make a struct template:
template <typename T>
struct MyStruct {
T val;
};
// ...
MyStruct<bool> s1;
s1 = false;
MyStruct<float> s2;
s2 = 3.1415;
I can cast between types by using either from or as:
i64::from(42i32);
42i32 as i64;
What is the difference between those?
as can only be used in a small, fixed set of transformations. The reference documents as:
as can be used to explicitly perform coercions, as
well as the following additional casts. Here *T means either *const T or
*mut T.
Type of e
U
Cast performed by e as U
Integer or Float type
Integer or Float type
Numeric cast
C-like enum
Integer type
Enum cast
bool or char
Integer type
Primitive to integer cast
u8
char
u8 to char cast
*T
*V where V: Sized *
Pointer to pointer cast
*T where T: Sized
Numeric type
Pointer to address cast
Integer type
*V where V: Sized
Address to pointer cast
&[T; n]
*const T
Array to pointer cast
Function item
Function pointer
Function item to function pointer cast
Function item
*V where V: Sized
Function item to pointer cast
Function item
Integer
Function item to address cast
Function pointer
*V where V: Sized
Function pointer to pointer cast
Function pointer
Integer
Function pointer to address cast
Closure **
Function pointer
Closure to function pointer cast
* or T and V are compatible unsized types, e.g., both slices, both the
same trait object.
** only for closures that do not capture (close over) any local variables
Because as is known to the compiler and only valid for certain transformations, it can do certain types of more complicated transformations.
From is a trait, which means that any programmer can implement it for their own types and it is thus able to be applied in more situations. It pairs with Into. TryFrom and TryInto have been stable since Rust 1.34.
Because it's a trait, it can be used in a generic context (fn foo(name: impl Into<String>) { /* ... */ }). This is not possible with as (although see AsPrimitive from the num crate).
When converting between numeric types, one thing to note is that From is only implemented for lossless conversions (e.g. you can convert from i32 to i64 with From, but not the other way around), whereas as works for both lossless and lossy conversions (if the conversion is lossy, it truncates). Thus, if you want to ensure that you don't accidentally perform a lossy conversion, you may prefer using From::from rather than as.
See also:
When should I implement std::convert::From vs std::convert::Into?
From some C legacy code I get a number of constants as int *. In the C++ part, I have an enum of underlying type int. Conversion between the enum and int on a single value basis works. However, conversion between int * and enum * is not possible. See code example below.
Why is that and how would I convert a pointer to some int values to a pointer to int enums and vice versa? I kind of expect it to work since the single value conversions work and the underlying types are the same. I read about What happens if you static_cast invalid value to enum class?
but could not determine if potentially invalid values play a role here.
int i = 3;
enum E : int;
E e;
e = static_cast<E>(i); // ok
i = static_cast<int>(e); // ok
int *j;
E * f;
j = static_cast<int *>(&i); // ok
f = static_cast<E *>(&i); // 'static_cast': cannot convert from 'int *' to 'E *'
j = static_cast<int *>(&e); // 'static_cast': cannot convert from 'E *' to 'int *'
// now use j and f
*j = *f;
Why is that?
From the compiler point of view int* and E* are pointers of different non-related types, that is why static_cast is not applicable here.
How would I convert a pointer to some int values to a pointer to int enums and vice versa?
You might try reinterpret_cast instead of static_cast:
f = reinterpret_cast<E *>(&i);
j = reinterpret_cast<int *>(&e);
From reinterpret_cast:
Any pointer to object of type T1 can be converted to pointer to object of another type cv T2
However, note, that dereferencing f or j (i.e. with *f or *j) will be a violation of the strict aliasing rule (for more details see the discussion below). This means that this kind of conversion, though strictly possible, is usually not useful.
The default 'base type' of an enum is int and can be explicitly specified in the OP. Logically the value stored at E* e where E is an enumeration with base type int is an int. It can't be statically cast.
There's no guarantee in C++ that an enum of base type (say) is layout compatible with short but even if the language tightened up that point there could be issues of type compatibility/
One issue is that E* to int*pi would violate type-safety because pi could be used to quietly set values outside the enumeration.
Similarly int* to E* may violate type safety if the integer value isn't in the enumeration.
Note however the standard makes a clear note that there's nothing to preclude an enum taking a value outside its defined set of values:
This set of values is used to define promotion and conversion semantics for the enumeration type. It does not preclude an
expression of enumeration type from having a value that falls outside this range.
See here: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf (see note 95 bottom of p. 156)
The only case that could (if layout-compatibility were assured) be valid is E* to const int* because all values of E* are ints and the value cannot be (correctly) modified through the int * pointer without a further violation of the type system.
But I think the language definition is not that subtle.
What is Type Conversion and what is Type Casting?
When should I use each of them?
Detail: Sorry if this is an obvious question; I'm new to C++, coming from a ruby background and being used to to_s and to_i and the like.
Conversion is when a value is, um, converted to a different type. The result is a value of the target type, and there are rules for what output value results from what input (of the source type).
For example:
int i = 3;
unsigned int j;
j = i; // the value of "i" is converted to "unsigned int".
The result is the unsigned int value that is equal to i modulo UINT_MAX+1, and this rule is part of the language. So, in this case the value (in English) is still "3", but it's an unsigned int value of 3, which is subtly different from a signed int value of 3.
Note that conversion happened automatically, we just used a signed int value in a position where an unsigned int value is required, and the language defines what that means without us actually saying that we're converting. That's called an "implicit conversion".
"Casting" is an explicit conversion.
For example:
unsigned int k = (unsigned int)i;
long l = long(i);
unsigned int m = static_cast<unsigned int>(i);
are all casts. Specifically, according to 5.4/2 of the standard, k uses a cast-expression, and according to 5.2.3/1, l uses an equivalent thing (except that I've used a different type). m uses a "type conversion operator" (static_cast), but other parts of the standard refer to those as "casts" too.
User-defined types can define "conversion functions" which provide specific rules for converting your type to another type, and single-arg constructors are used in conversions too:
struct Foo {
int a;
Foo(int b) : a(b) {} // single-arg constructor
Foo(int b, int c) : a(b+c) {} // two-arg constructor
operator float () { return float(a); } // conversion function
};
Foo f(3,4); // two-arg constructor
f = static_cast<Foo>(4); // conversion: single-arg constructor is called
float g = f; // conversion: conversion function is called
Classic casting (something like (Bar)foo in C, used in C++ with reinterpret_cast<>) is when the actual memory contents of a variable are assumed to be a variable of a different type. Type conversion (ie. Boost's lexical_cast<> or other user-defined functions which convert types) is when some logic is performed to actually convert a variable from one type to another, like integer to a string, where some code runs to logically form a string out of a given integer.
There is also static and dynamic casting, which are used in inheritance, for instance, to force usage of a parent's member functions on a child's type (dynamic_cast<>), or vice-versa (static_cast<>). Static casting also allows you to perform the typical "implicit" type conversion that occurs when you do something like:
float f = 3.14;
int i = f; //float converted to int by dropping the fraction
which can be rewritten as:
float f = 3.14;
int i = static_cast<int>(f); //same thing
In C++, any expression has a type. when you use an expression of one type (say type S) in a context where a value of another type is required (say type D), the compiler tries to convert the expression from type S to type D. If such an implicit conversion doesn't exist, this results in an error. The word type cast is not standard but is the same as conversion.
E.G.
void f(int x){}
char c;
f(c); //c is converted from char to int.
The conversions are ranked and you can google for promotions vs. conversions for more details.
There are 5 explicit cast operators in C++ static_cast, const_cast, reinterpret_cast and dynamic_cast, and also the C-style cast
Type conversion is when you actually convert a type in another type, for example a string into an integer and vice-versa, a type casting is when the actual content of the memory isn't changed, but the compiler interpret it in a different way.
Type casting indicates you are treating a block of memory differently.
int i = 10;
int* ip = &i;
char* cp = reinterpret_cast<char*>(ip);
if ( *cp == 10 ) // Here, you are treating memory that was declared
{ // as int to be char.
}
Type conversion indicates that you are converting a value from one type to another.
char c = 'A';
int i = c; // This coverts a char to an int.
// Memory used for c is independent of memory
// used for i.