Convert bytes3 to string in Solidity - string

I need to create function to convert byte3 to string.
On my contract, data is saved into a state variable.
I want to convert content of variable for user.
This is my function:
function convertByteToString() public view returns(string memory){
string memory result = string(symbol);
return result;
}
but I get a compiler error:
TypeError: Explicit type conversion not allowed from "bytes3" to "string memory".
How can this error be resolved?

To convert bytes3 to string you must use the abi.encodePacked(bytes3 parameter) and this result you must convert it into a string.
Change your function with this:
function convertByteToString(bytes3 symbol) public view returns(string memory){
string memory result = string(abi.encodePacked(symbol));
return result;
}

Only a dynamic-length byte array (Solidity type bytes) can be typecasted to a string, but you're passing a fixed-length byte array (Solidity type bytes3).
Use abi.encode() to convert the bytes3 to bytes.
pragma solidity ^0.8;
contract MyContract {
bytes3 symbol = 0x455448; // hex-encoded ASCII value of "ETH"
function convertByteToString() public view returns(string memory){
string memory result = string(abi.encode(symbol));
return result;
}
}

Related

Overload function based on string content in TypeScript

Say I have a function which accepts an input string parameter. If input begins with a "!" character, the function should return a boolean type. If input begins with a "?" character, the function should return a string[] type.
The question is, is it possible to document overloads for this kind of behavior in a TypeScript definition file?
This is not possible.
A string in typescript can either be a constant literal string, for example:
const a = "A"
Or it may be of type string which means it may have any content, for example:
const str = prompt("What is your name?")`
There is no way to define a string type that matches any sort of pattern.
I don't know what you are trying to do, but there's probably a better way to design your API here.
If you do know all possibilities, you can treat them like constant strings.
type Bang = "!A" | "!B" | "!C"
type Question = "?A" | "?B" | "?C"
function doStuff(str: Bang): boolean
function doStuff(str: Question): string[]
function doStuff(str: Bang | Question): boolean | string[] {
if (str.startsWith("!")) {
return true
} else {
return ['strings', 'here']
}
}
doStuff('!A') // boolean
doStuff('?A') // string[]
Playground
Update for Typescript 4.1:
Typescript 4.1 (just released in beta on Sept 18, 2020) includes support for Template Literal Types. This lets you have the contents of string literals be strongly typed. You can now pull parts of string literals out and use them on their own.
With this feature, your problem could be solved like so:
// Typescript 4.1
function doStuff<
Prefix extends '!',
Suffix extends string
>(str: `${Prefix}${Suffix}`): boolean
function doStuff<
Prefix extends '?',
Suffix extends string
>(str: `${Prefix}${Suffix}`): string[]
function doStuff<
Prefix extends '!' | '?',
Suffix extends string
>(str: `${Prefix}${Suffix}`): boolean | string[] {
if (str.startsWith("!")) {
return true
} else {
return ['strings', 'here']
}
}
doStuff('!A') // boolean
doStuff('?A') // string[]
doStuff('bad format') // type error
4.1 Playground

how to create a node from a string literal in rapidjson?

I want to create a JSON node from a string literal in rapidjson, my code is as follows(which doesn't work of cause):
inline rapidjson::Value to_json(const std::string& myStr) {
auto result = rapidjson::Value(rapidjson::kStringType);
result.SetString(myStr);
return result;
}
I remember that Jackson's APIs are so nice that you can create a String node by TextNode.valueOf(myStr).
Is there a similar way to create a JSON node from string literal ?
You will need an allocator. And if you have defined RAPIDJSON_HAS_STDSTRING=1, you can simply:
Document d;
std::string s = "...";
Value v(s, d.GetAllocator());

Cannot convert value of type 'Int' to expected argument type 'Index' (aka 'String.CharacterView.Index')

Code:
let x: String = ("abc".substringFromIndex(1))
print(x)
//func tail(s: String) -> String {
// return s.substringFromIndex(1)
//}
//print(tail("abcd"))
This works as expected.
But if I uncomment the last 4 lines, then I get:
Error: cannot convert value of type 'Int' to expected argument type 'Index' (aka 'String.CharacterView.Index')
Really weird.
This is because the subscripting functions in String no longer operate on ints, but on the inner Index type:
extension String {
public typealias Index = String.CharacterView.Index
//...
public subscript (i: Index) -> Character { get }
So you need to grab some Index values. You can achieve this by obtaining the first index in the string (aka the index of the first character), and navigate from there:
func tail(s: String) -> String {
return s.substringFromIndex(s.startIndex.advancedBy(1))
}
Note that the above code no longer compiles in the latest Swift version, I'll leave for historical purposes and for people stuck in earlier Swift.
These days we can write something along the lines of
extension String {
var tail: String { String(self[index(startIndex, offsetBy: 1)...]) }
// or
var tail: String { String(self[index(after: startIndex)...]) }
// or even this
var tail: String { String(dropFirst()) }
}
In Swift 4:
func tail(s: String) -> String {
return String(s.suffix(from: s.index(s.startIndex, offsetBy: 1)))
}

Get Int from String in Swift

I want to make an Int from an String, but can't find how to.
This is my func:
func setAttributesFromDictionary(aDictionary: Dictionary<String, String>) {
self.appId = aDictionary["id"].toInt()
self.title = aDictionary["title"] as String
self.developer = aDictionary["developer"] as String
self.imageUrl = aDictionary["imageUrl"] as String
self.url = aDictionary["url"] as String
self.content = aDictionary["content"] as String
}
When using toInt() I get the error messag Could not find member 'toInt'. I can't use Int(aDictionary["id"]) either.
Subscripting a dictionary, with the dict[key] method, always returns an optional. For example, if your dictionary is Dictionary<String,String> then subscript will return an object with type String?. Thus the error that you are seeing of "Could not find member 'toInt()'" occurs because String?, an optional, does not support toInt(). But, String does.
You may also note that toInt() returns Int?, an optional.
The recommended approach to your need is something along the lines of:
func setAttributesFromDictionary(aDictionary: Dictionary<String, String>) {
if let value = aDictionary["id"]?.toInt() {
self.appId = value
}
// ...
}
The assignment will occur iff aDictionary has an id mapping and its value is convertible to an Int.
In action:

Using an array as a parameter in Haxe

I have a function that takes an array as a parameter, and it keeps returning the following error message:
Test.hx:34: characters 23-24 : Array<Int> should be { length : Void -> Int }
Test.hx:34: characters 23-24 : Invalid type for field length :
Test.hx:34: characters 23-24 : Int should be Void -> Int
Test.hx:34: characters 23-24 : For function argument 'array'
This is the code that produced the error message:
class Test{
static function main() {
var a = new Array();
a = [1,2,3,4];
enlarge1DArray(a); //why won't it work when I try to invoke this function?
}
static function enlarge1DArray(array){
var i = 0;
while(i < array.length()){
i++;
trace("i is " + i);
}
}
}
The length you are trying to access is a property, not a method. See the Array API Documentation.
Change the while line from this:
while(i < array.length())
to this:
while(i < array.length)
Detailed Answer:
The error you're getting is due to Haxe getting confused as it's guessing at the types. Basically, because you had were treating length as a method, it was assuming that the array parameter in the enlarge1DArray had to be some kind of object that had a method called length, with the type signature "Void->Int".
In short, because you were asking for a method, it was expecting the parameter "array" to have:
{ length : Void -> Int }
when an Array actually has:
{ length : Int }
So the compiler got confused and said you had your typing wrong. You can read more about this on the Haxe wiki page for Type Inference. In future you can explicitly state what the types of each function parameter are, and then Haxe will give you more useful error messages.

Resources