I'm trying to learn Swift and I'm stuck to a very simple thing. How to write a function that returns an enum. The following code doesn't compile:
import Foundation
enum MyResponse {
case Even (String, String)
case Odd (String)
}
func checkNumber(number : Int) -> MyResponse // <---- Error message
{
if (number % 2 == 0) {
return MyResponse.Even(String(number), " is even")
}
return MyResponse.Odd("odd")
}
let v1 = checkNumber(1)
switch v1 {
case .Even(arg1, arg2):
println("\(arg1) --> \(arg2)")
case .Odd(arg):
println("\(arg)")
}
I get the error message "Use of undeclared type".
What am I doing wrong? What is the correct way to return enum value from a function.
Your MyResponse from line #3 is different from MyResponse in line #8. There is unprintable character between "My" and "Response" in line #8.
Related
I have a server set up to send messages over a local host port. I am trying to decode the serialized json messages sent by the server and get this error.
Error decoding message: kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 55: Expected EOF after parsing, but had instead at path: $
JSON input: .....mber":13,"Timestamp":5769784} .....
The Racer State messages are formatted in JSON as follows: { “SensorId”: “value”, “RacerBibNumber” : “value”, “Timestamp” : “value” }, where the value’s are character string representations of the field values. I have also tried changing my RacerStatus Class to take String instead of Int but to a similar error. Am I missing something here? The symbol that is missing in the error was not able to be copied over so I know it's not UTF-8.
I have also added
val inputString = bytes.toString(Charsets.UTF_8)
println("Received input: $inputString")
This gets
Received input: {"SensorId":0,"RacerBibNumber":5254,"Timestamp":3000203}
with a bunch of extraneous symbols at the end.
data class RacerStatus(
var SensorId: Int,
var RacerBibNumber: Int,
var Timestamp: Int
) {
fun encode(): ByteArray {
return Json.encodeToString(serializer(), this).toByteArray()
}
companion object {
fun decode(bytes: ByteArray): RacerStatus {
print(bytes[0])
try {
val mstream = ByteArrayInputStream(bytes)
return Json.decodeFromStream<RacerStatus>(mstream)
} catch (e: SerializationException) {
println("Error decoding message: $e")
return RacerStatus(0, 0, 0)
}
// return Json.decodeFromString(serializer(), mstream.readBytes().toString())
}
}
}
So I found an answer to my question. I added a regex to include just the json components I know my json contains.
val str = bytes.toString(Charsets.UTF_8)
val re = Regex("[^A-Za-z0-9{}:,\"\"]")
return Json.decodeFromString<RacerStatus>(re.replace(str,""))
I thought that Charsets.UTF_8 would remove the misc characters but it did not. Is there a more intiuative solution? Also is there a regex that would cover all possible values in json?
I'm trying to instantiate an instance of a struct (Struct1) in an array. Instances of Struct1 store a function (method) that takes a generic type T for a parameter. The following code is how I attempted to do this:
struct Struct1<T> {
method: fn(T)
}
fn main() {
let arrOfStructs = [
Struct1 {
method: fn(char) {
let a = char; //this does nothing useful, just a mock function
}
}
];
}
But I get the error following errors:
error: expected expression, found keyword `fn`
--> test.rs:8:21
|
7 | Struct1 {
| ------- while parsing this struct
8 | method: fn(char) {
| ^^ expected expression
error[E0063]: missing field `method` in initializer of `Struct1<_>`
--> test.rs:7:9
|
7 | Struct1 {
| ^^^^^^^ missing `method`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0063`.
I'm assuming the second error listed is present simply because the instance's method wasn't properly instantiated, because of the first listed error. But I can't figure out what the first error is trying to say. As far as I know, Rust instantiations can be implicitly typed. I can't figure out what else might be the problem though. Could you guys help me out with this one? Much appreciated!
The syntax to create an anonymous function (a closure) in Rust is not what you tried. Rather, it is:
|arg1, arg2, arg3, ...| body
Where body can be any expression, including a block (|| { body }), parameters can have type annotations (|arg: Type| {}) and the closure may specify the return type explicitly using ->: || -> ReturnType {}.
In your example,
fn main() {
let arrOfStructs = [
Struct1 {
method: |char: YouHaveToSpecifyTheTypeHere| {
let a = char; //this does nothing useful, just a mock function
}
}
];
}
Just to supplement the answer:
There are two ways to construct a function pointer, one is constructing via an existing function,
and the other is using a closure(anonymous function) that doesn't capture any environmental
variables
fn add_one(x: usize) -> usize {
x + 1
}
// using an existing function
let ptr: fn(usize) -> usize = add_one;
assert_eq!(ptr(5), 6);
// using a closure that does not enclose variables
let clos: fn(usize) -> usize = |x| x + 5;
assert_eq!(clos(5), 10);
link to the official doc
I am using serde_json to deserialise a json document. I have a function that given a string (this is the json document), will return a serde_json Value (this is an enum that represents the json type), returns an Option.
This value is passed around to other functions as required.
However, I realised that passing around a Value is not quite what I want, because doing this, the key is not available.
To illustrate my point, if I have a json document that looks like this:
{
"root" : {
"regex" : null,
"prefixes" : [ "a_", "b_" ]
}
}
"root" is a json object, "regex" is json Null and "prefixes" is a json array.
Now, the json type Value is an enum with discriminators representing the json types, eg Object, Null, Array for the examples given above.
The serde_json crate uses std::collections::BTreeMap to represent nodes in the json document, where the String type repesents the json keys (in the above, these would be "root", "regex" and "prefixes". So passing around just references to Values is only partly helpful, I should be passing around BTreeMap instead, so that I can access the key too.
So this is the following function that I am trying to re-write:
fn get_json_content(content_s : &str) -> Option<Value> {
// instead of returning a value, we need to return a BTreeMap, so we can get the
// key and the value.
println!("===>>> json_content obtained: {}", content_s);
match serde_json::from_str(content_s) { // -> Result<Value>
Ok(some_value) => Some(some_value),
Err(_) => None
}
}
So I started to re-write the function but became up against the "the type of this value must be known in this context" error:
fn get_json_content_as_btreemap<'a>(content_s : &str) -> Option<&'a BTreeMap<String, Value>> {
match serde_json::from_str(content_s) { // -> Result<Value>
Ok(some) => {
// I expect the type of key_value_pair to be BTreeMap<String, Value>>
// (but I may be wrong!)
let key_value_pair = some.as_object().unwrap(); // Error here
},
Err(_) => None
}
}
I found other questions on stackoverflow like this one:
the type of this value must be known in this context
and using this as a helper, I tried to insert the type as follows:
let key_value_pair = some.as_object::<BTreeMap<_, _>>().unwrap();
which doesnt fix the issue. Also, tried other similar variations to no avail. So how do I fix this please?
EDIT:
I have another function in this app as follows:
fn get_root_value<'a>(json_documemt : &'a Value) -> Result<&'a Value, JsonErrorCode> {
if json_documemt.is_object() {
for (k, v) in json_documemt.as_object().unwrap().iter() {
if k == "root" {
println!("found root: {}", k);
return Ok(v)
}
}
return Err(JsonErrorCode::Custom("Failed to find root node".to_string()))
}
Err(JsonErrorCode::Custom("Not an object".to_string()))
}
... and this works fine. Here you can see that I can call as_object() and then obtain the key and value as a tuple pair. I don't understand why as_object is working in one case but not the other. I would like to pull out the BTreeMap and pass this around as a borrowed item.
You can change the return type of your initial function and serde_json will deserialize to the appropriate object if it can:
fn get_json_content(content_s : &str) -> Option<BTreeMap<String, Value>> {
// instead of returning a value, we need to return a BTreeMap, so we can get the
// key and the value.
println!("===>>> json_content obtained: {}", content_s);
match serde_json::from_str(content_s) { // -> Result<Value>
Ok(some_value) => Some(some_value),
Err(_) => None
}
// Note: this match statement can be rewritten as
// serde_json::from_str(content_s).ok()
}
Your second example won't work because you are instantiating the Value object inside the function, and then trying to return a reference to the object you just instantiated. This won't work because the object will go out of scope at the end of the function and the reference will then be invalid.
I am trying to use inline if condition as follows:
topDisplay.text!.rangeOfString(".") != nil ? call function A : call function B
The idea here is if there is "." in the topDisplay.text! then call function A, otherwise, call function B. The method, rangeOfString, returns nil if no "." is found. So I am wondering is it possible to check nil within inline condition expression and making function call at the same time.
Your code is correct, assuming you put the calls to actual functions in there, i.e.:
func functionA() -> String { return "A" }
func functionB() -> String { return "B" }
topDisplay.text?.rangeOfString(".") != nil ? functionA() : functionB()
If you’re getting an error message, the most likely reason is functionA and functionB return different types:
func functionA() -> String { return "A" }
func functionB() -> Int { return 1 }
// error: could not find an overload for '!=' that accepts the supplied arguments
topDisplay.text?.rangeOfString(".") != nil ? functionA() : functionB()
In classic Swift error message style, this gives you an error about the valid != comparison not about the problem with A and B returning incompatible types.
However, given you aren’t showing in your code the assignment of the result, I suspect you are actually wanting to run these functions for their side-effects not for the value they return. If this is the case do not do this. The ?: operator is there for evaluating two possibilities as an expression. If you want side effects, use an if:
if topDisplay.text?.rangeOfString(".") != nil {
sideEffectfulFunctionA()
}
else {
sideEffectfulFunctionB()
}
I have the following:
def saveAnnotations(annotation: String) = {
var json = parse(annotation)
var data: List[AnnotationData] = json.extract[List[AnnotationData]]
Presentation.update(
("room" -> "demo-room"),
("$set" -> ("annotation" -> data))
)
}
Where the var "annotation" is a json object array string, e.g
[{"key": "val"},{"key": "val"}]
The field "annotation" is a MongoJsonObjectListField
When compiling I'm recieving the following error:
No implicit view available from (String, List[code.snippet.AnnotationData]) =>
net.liftweb.json.package.JValue.("$set" -> ("annotation" -> data))
^
I'm sure something simple is missing, any help is much appreciated, thanks in advance :)
EDIT
I've just noticed that it compiles if I do:
Presentation.update(
("room" -> "demo-room"),
("$set" -> ("annotation" -> ""))
)
However this obviously sets the annotation field value to an empty string, how would I force the annotation field to be overwritten with the json object array in the data var?