I have a file in which each line is of the form :
key$password (key + separator + password)
so that I can do
let (key , password) = line.split_once("$").unwrap() ;** // to get key and password
the first line is special (id, secret_key) and I need this secret key to decode the passwords
in a function where I have declared :
let mount count = 0;
let user_password = String::new();**
Then I run a loop
for line in reader.lines() {
count += 1;
match line {
match count {
1 => { here I split_once and get a value of user_password )
_ => now I want to parse the following lines using user_password obtained from the 1 arm of the match
... etc
}
my problem is that although user_password is valid in arm 1 (or an if then clause), but is not set in the context of arm 2
There is something that I cannot understand : I declare usr_password in the whole context of the function, in the match arm 1 I set the variable to a value ,but when I am in arm 2 (that is for line 2 .. end this variable is not set
any help would be terribly appreciated (I'm a beginner, sorry)
fn logic(file_contents: &str) {
// this is an iterator, it has its own state and you can call
// .next to get one line
let mut lines = file_contents.lines();
// so called `let-else` statement, if `lines.next()` if `None`
// the else block is executed
let Some(header) = lines.next() else {
// `todo!` will terminate your program if reached
// the advantage is that compiler is happy and you
// can debug happy path
todo!("handle missing header");
};
// same as above
let Some((key, password)) = header.split_once("$") else {
todo!("handle invalid header")
};
// now that we taken first line and processed it, you can consume
// the remaining lines by a loop
for line in lines {
// its always good to separate the concerns of your program
let Some(res) = decode(line, key, password) else {
continue; // or handle the error
};
// use `res`
}
}
// TODO: choose appropriate return type, `()` is placeholder for now
// `Option<T>` signifies function can fail and return nothing
fn decode(line: &str, key: &str, password: &str) -> Option<()> {
todo!("implement decode");
}
Related
I have been changing some SWIFT code into OBJECTIVE-C, and I am stuck at certain part of the code, where I am unable to understand if it is a condition or something else.
Following is the code and I am stuck on 9th line stating :
if let channel1Buffer = buffer.floatChannelData?[0]
What I do not understand here is the above if condition is checking if "buffer.floatChannelData" is null, and then proceeding to get the first index, or is it something else.
input.installTap(onBus: 0, bufferSize:4096, format:format, block: { [weak self] buffer, when in
guard let this = self else {
return
}
print("Buffer Float Channel Data: ", buffer.floatChannelData as Any);
**if let channel1Buffer = buffer.floatChannelData?[0]** {
print("channel1Buffer: ", channel1Buffer);
/// encode PCM to mp3
let frameLength = Int32(buffer.frameLength) / 2;
print("frameLength: ", frameLength);
let bytesWritten = lame_encode_buffer_interleaved_ieee_float(this.lame, channel1Buffer, frameLength, this.mp3buf, 4096);
// `bytesWritten` bytes stored in this.mp3buf now mp3-encoded
print("\(bytesWritten) encoded");
this.file.append(this.mp3buf, length: Int(bytesWritten));
// #TODO: send data, better to pass into separate queue for processing
}
})
Let's take it part by part - buffer.floatChannelData?[0]
buffer has property named floatChannelData which is optional so it has ? at the end. then it takes that optional which accepts subscription [0] which also returns optional value. So it continues inside {} only if floatChannelData is not nil AND it's first value is not nil
Your Objc should look like
float *const *channelData = [buffer floatChannelData];
if (channelData) {
float *channel1Buffer = channelData[0]; //this might crash if channelData is empty
...
The line tries to assign the variable channel1Buffer the value of buffer.floatChannelData[0], and the code within {} is only executed if that assignment is successful. It may for instance fail if buffer.floatChannelData is nil or buffer.floatChannelData[0] is nil.
My original goal is to fetch a list of words, one on each line, and to put them in a HashSet, while discarding comment lines and raising I/O errors properly. Given the file "stopwords.txt":
a
# this is actually a comment
of
the
this
I managed to make the code compile like this:
fn stopword_set() -> io::Result<HashSet<String>> {
let words = Result::from_iter(
BufReader::new(File::open("stopwords.txt")?)
.lines()
.filter(|r| match r {
&Ok(ref l) => !l.starts_with('#'),
_ => true
}));
Ok(HashSet::from_iter(words))
}
fn main() {
let set = stopword_set().unwrap();
println!("{:?}", set);
assert_eq!(set.len(), 4);
}
Here's a playground that also creates the file above.
I would expect to have a set of 4 strings at the end of the program. To my surprise, the function actually returns a set containing a single string with all words concatenated:
{"aofthethis"}
thread 'main' panicked at 'assertion failed: `(left == right)` (left: `1`, right: `4`)'
Led by a piece of advice in the docs for FromIterator, I got rid of all calls to from_iter and used collect instead (Playground), which has indeed solved the problem.
fn stopword_set() -> io::Result<HashSet<String>> {
BufReader::new(File::open("stopwords.txt")?)
.lines()
.filter(|r| match r {
&Ok(ref l) => !l.starts_with('#'),
_ => true
}).collect()
}
Why are the previous calls to from_iter leading to unexpected inferences, while collect() works just as intended?
A simpler reproduction:
use std::collections::HashSet;
use std::iter::FromIterator;
fn stopword_set() -> Result<HashSet<String>, u8> {
let input: Vec<Result<_, u8>> = vec![Ok("foo".to_string()), Ok("bar".to_string())];
let words = Result::from_iter(input.into_iter());
Ok(HashSet::from_iter(words))
}
fn main() {
let set = stopword_set().unwrap();
println!("{:?}", set);
assert_eq!(set.len(), 2);
}
The problem is that here, we are collecting from the iterator twice. The type of words is Result<_, u8>. However, Result also implements Iterator itself, so when we call from_iter on that at the end, the compiler sees that the Ok type must be String due to the method signature. Working backwards, you can construct a String from an iterator of Strings, so that's what the compiler picks.
Removing the second from_iter would solve it:
fn stopword_set() -> Result<HashSet<String>, u8> {
let input: Vec<Result<_, u8>> = vec![Ok("foo".to_string()), Ok("bar".to_string())];
Result::from_iter(input.into_iter())
}
Or for your original:
fn stopword_set() -> io::Result<HashSet<String>> {
Result::from_iter(
BufReader::new(File::open("stopwords.txt")?)
.lines()
.filter(|r| match r {
&Ok(ref l) => !l.starts_with('#'),
_ => true
}))
}
Of course, I'd normally recommend using collect instead, as I prefer the chaining:
fn stopword_set() -> io::Result<HashSet<String>> {
BufReader::new(File::open("stopwords.txt")?)
.lines()
.filter(|r| match r {
&Ok(ref l) => !l.starts_with('#'),
_ => true,
})
.collect()
}
I started programming Rust a couple of days ago by working through the official documentation. Now I'm trying to challenge my understanding of Rust by working through the book "Exercises for Programmers" by Brian P. Hogan (The Pragmatic Programmers).
The first exercise is to write a program that asks the user for a name and prints out a greeting using that name. Input, string concatenation and output should be done in three distinct steps.
What is your name? Patrick
Hello, Patrick, nice to meet you.
The name will be entered at the same line as the initial prompt. Here's my solution:
use std::io;
use std::io::Write;
fn main() {
print!("What is your name? ");
match io::stdout().flush() {
Ok(_) => print!(""),
Err(error) => println!("{}", error),
}
let mut name = String::new();
match io::stdin().read_line(&mut name) {
Ok(_) => {
name = name.trim().to_string();
if name.len() > 0 {
let greeting = "Hello, ".to_string() + &name + &", nice to meet you!".to_string();
println!("{}", greeting);
} else {
println!("No name entered, goodbye.");
}
}
Err(error) => println!("{}", error),
}
}
The print! macro doesn't actually output the prompt until I call flush. flush needs error handling, so I need both to handle the Ok and the Err case. In case of Ok, there's nothing useful to do, so I just print! an empty string.
Is there a shorter way to handle this? Maybe the error handling can be skipped or simplified somehow, or the whole print!/flush approach is the wrong one. (Everything works fine, but I could write this shorter in C, after all...)
As other people have said, make sure to read the error handling chapter.
In most cases, you don't want to use println! to report errors. Either you should return the error from your function and let the caller deal with it, or you should use panic! to abort that thread and potentially the process.
match io::stdout().flush() {
Ok(_) => print!(""),
Err(error) => println!("{}", error),
}
Instead of printing nothing (which is inefficient), you can just... do nothing:
match io::stdout().flush() {
Ok(_) => (),
Err(error) => println!("{}", error),
}
Since you don't care about the success case, you can use an if let:
if let Err(error) = io::stdout().flush() {
println!("{}", error);
}
Replacing the println with a panic! would be even better:
if let Err(error) = io::stdout().flush() {
panic!("{}", error);
}
This is almost exactly what Option::unwrap does (source), except it also returns the successful value when present:
pub fn unwrap(self) -> T {
match self {
Some(val) => val,
None => panic!("called `Option::unwrap()` on a `None` value"),
}
}
However, it's even better to use Option::expect which allows you to specify an additional error message:
io::stdout().flush().expect("Unable to flush stdout");
Applying that twice:
use std::io::{self, Write};
fn main() {
print!("What is your name? ");
io::stdout().flush().expect("Unable to flush stdout");
let mut name = String::new();
io::stdin()
.read_line(&mut name)
.expect("Unable to read the line");
let name = name.trim();
if !name.is_empty() {
println!("Hello, {}, nice to meet you!", name);
} else {
println!("No name entered, goodbye.");
}
}
Note that there's no need to re-allocate a String, you can just shadow name, and there's no need to use format just to print out stuff.
Since Rust 1.26.0, you could also choose to return a Result from main:
use std::io::{self, Write};
fn main() -> Result<(), io::Error> {
print!("What is your name? ");
io::stdout().flush()?;
let mut name = String::new();
io::stdin().read_line(&mut name)?;
let name = name.trim();
if !name.is_empty() {
println!("Hello, {}, nice to meet you!", name);
} else {
println!("No name entered, goodbye.");
}
Ok(())
}
but I could write this shorter in C, after all...
I would encourage / challenge you to attempt this. Note that every memory allocation in this program is checked, as is every failure case dealing with the standard output. Many people are not aware that C's printf returns an error code that you should be checking. Try outputting to a pipe that has been closed for an example.
since few days I was struggling on how to proceed with PATCH request in Go REST API until I have found an article about using pointers and omitempty tag which I have populated and is working fine. Fine until I have realized I still have to build an UPDATE SQL query.
My struct looks like this:
type Resource struct {
Name *string `json:"name,omitempty" sql:"resource_id"`
Description *string `json:"description,omitempty" sql:"description"`
}
I am expecting a PATCH /resources/{resource-id} request containing such a request body:
{"description":"Some new description"}
In my handler I will build the Resource object this way (ignoring imports, ignoring error handling):
var resource Resource
resourceID, _ := mux.Vars(r)["resource-id"]
d := json.NewDecoder(r.Body)
d.Decode(&resource)
// at this point our resource object should only contain
// the Description field with the value from JSON in request body
Now, for normal UPDATE (PUT request) I would do this (simplified):
stmt, _ := db.Prepare(`UPDATE resources SET description = ?, name = ? WHERE resource_id = ?`)
res, _ := stmt.Exec(resource.Description, resource.Name, resourceID)
The problem with PATCH and omitempty tag is that the object might be missing multiple properties, thus I cannot just prepare a statement with hardcoded fields and placeholders... I will have to build it dynamically.
And here comes my question: how can I build such UPDATE query dynamically? In the best case I'd need some solution with identifying the set properties, getting their SQL field names (probably from the tags) and then I should be able to build the UPDATE query. I know I can use reflection to get the object properties but have no idea hot to get their sql tag name and of course I'd like to avoid using reflection here if possible... Or I could simply check for each property it is not nil, but in real life the structs are much bigger than provided example here...
Can somebody help me with this one? Did somebody already have to solve the same/similar situation?
SOLUTION:
Based on the answers here I was able to come up with this abstract solution. The SQLPatches method builds the SQLPatch struct from the given struct (so no concrete struct specific):
import (
"fmt"
"encoding/json"
"reflect"
"strings"
)
const tagname = "sql"
type SQLPatch struct {
Fields []string
Args []interface{}
}
func SQLPatches(resource interface{}) SQLPatch {
var sqlPatch SQLPatch
rType := reflect.TypeOf(resource)
rVal := reflect.ValueOf(resource)
n := rType.NumField()
sqlPatch.Fields = make([]string, 0, n)
sqlPatch.Args = make([]interface{}, 0, n)
for i := 0; i < n; i++ {
fType := rType.Field(i)
fVal := rVal.Field(i)
tag := fType.Tag.Get(tagname)
// skip nil properties (not going to be patched), skip unexported fields, skip fields to be skipped for SQL
if fVal.IsNil() || fType.PkgPath != "" || tag == "-" {
continue
}
// if no tag is set, use the field name
if tag == "" {
tag = fType.Name
}
// and make the tag lowercase in the end
tag = strings.ToLower(tag)
sqlPatch.Fields = append(sqlPatch.Fields, tag+" = ?")
var val reflect.Value
if fVal.Kind() == reflect.Ptr {
val = fVal.Elem()
} else {
val = fVal
}
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
sqlPatch.Args = append(sqlPatch.Args, val.Int())
case reflect.String:
sqlPatch.Args = append(sqlPatch.Args, val.String())
case reflect.Bool:
if val.Bool() {
sqlPatch.Args = append(sqlPatch.Args, 1)
} else {
sqlPatch.Args = append(sqlPatch.Args, 0)
}
}
}
return sqlPatch
}
Then I can simply call it like this:
type Resource struct {
Description *string `json:"description,omitempty"`
Name *string `json:"name,omitempty"`
}
func main() {
var r Resource
json.Unmarshal([]byte(`{"description": "new description"}`), &r)
sqlPatch := SQLPatches(r)
data, _ := json.Marshal(sqlPatch)
fmt.Printf("%s\n", data)
}
You can check it at Go Playground. The only problem here I see is that I allocate both the slices with the amount of fields in the passed struct, which may be 10, even though I might only want to patch one property in the end resulting in allocating more memory than needed... Any idea how to avoid this?
I recently had same problem. about PATCH and looking around found this article. It also makes references to the RFC 5789 where it says:
The difference between the PUT and PATCH requests is reflected in the way the server processes the enclosed entity to modify the resource identified by the Request-URI. In a PUT request, the enclosed entity is considered to be a modified version of the resource stored on the origin server, and the client is requesting that the stored version be replaced. With PATCH, however, the enclosed entity contains a set of instructions describing how a resource currently residing on the origin server should be modified to produce a new version. The PATCH method affects the resource identified by the Request-URI, and it also MAY have side effects on other resources; i.e., new resources may be created, or existing ones modified, by the application of a PATCH.
e.g:
[
{ "op": "test", "path": "/a/b/c", "value": "foo" },
{ "op": "remove", "path": "/a/b/c" },
{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
{ "op": "replace", "path": "/a/b/c", "value": 42 },
{ "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
{ "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
]
This set of instructions should make it easier to build the update query.
EDIT
This is how you would obtain sql tags but you will have to use reflection:
type Resource struct {
Name *string `json:"name,omitempty" sql:"resource_id"`
Description *string `json:"description,omitempty" sql:"description"`
}
sp := "sort of string"
r := Resource{Description: &sp}
rt := reflect.TypeOf(r) // reflect.Type
rv := reflect.ValueOf(r) // reflect.Value
for i := 0; i < rv.NumField(); i++ { // Iterate over all the fields
if !rv.Field(i).IsNil() { // Check it is not nil
// Here you would do what you want to having the sql tag.
// Creating the query would be easy, however
// not sure you would execute the statement
fmt.Println(rt.Field(i).Tag.Get("sql")) // Output: description
}
}
I understand you don't want to use reflection, but still this may be a better answer than the previous one as you comment state.
EDIT 2:
About the allocation - read this guide lines of Effective Go about Data structures and Allocation:
// Here you are allocating an slice of 0 length with a capacity of n
sqlPatch.Fields = make([]string, 0, n)
sqlPatch.Args = make([]interface{}, 0, n)
With make(Type, Length, Capacity (optional))
Consider the following example:
// newly allocated zeroed value with Composite Literal
// length: 0
// capacity: 0
testSlice := []int{}
fmt.Println(len(testSlice), cap(testSlice)) // 0 0
fmt.Println(testSlice) // []
// newly allocated non zeroed value with make
// length: 0
// capacity: 10
testSlice = make([]int, 0, 10)
fmt.Println(len(testSlice), cap(testSlice)) // 0 10
fmt.Println(testSlice) // []
// newly allocated non zeroed value with make
// length: 2
// capacity: 4
testSlice = make([]int, 2, 4)
fmt.Println(len(testSlice), cap(testSlice)) // 2 4
fmt.Println(testSlice) // [0 0]
In your case, may want to the following:
// Replace this
sqlPatch.Fields = make([]string, 0, n)
sqlPatch.Args = make([]interface{}, 0, n)
// With this or simple omit the capacity in make above
sqlPatch.Fields = []string{}
sqlPatch.Args = []interface{}{}
// The allocation will go as follow: length - capacity
testSlice := []int{} // 0 - 0
testSlice = append(testSlice, 1) // 1 - 2
testSlice = append(testSlice, 1) // 2 - 2
testSlice = append(testSlice, 1) // 3 - 4
testSlice = append(testSlice, 1) // 4 - 4
testSlice = append(testSlice, 1) // 5 - 8
Alright, I think the solution I used back in 2016 was quite over-engineered for even more over-engineered problem and was completely unnecessary. The question asked here was very generalized, however we were building a solution that was able to build its SQL query on its own and based on the JSON object or query parameters and/or Headers sent in the request. And that to be as generic as possible.
Nowadays I think the best solution is to avoid PATCH unless truly necessary. And even then you still can use PUT and replace the whole resource with patched property/ies coming already from the client - i.e. not giving the client the option/possibility to send any PATCH request to your server and to deal with partial updates on their own.
However this is not always recommended, especially in cases of bigger objects to save some C02 by reducing the amount of redundant transmitted data. Whenever today if I need to enable a PATCH for the client I simply define what can be patched - this gives me clarity and the final struct.
Note that I am using a IETF documented JSON Merge Patch implementation. I consider that of JSON Patch (also documented by IETF) redundant as hypothetically we could replace the whole REST API by having one single JSON Patch endpoint and let clients control the resources via allowed operations. I also think the implementation of such JSON Patch on the server side is way more complicated. The only use-case I could think of using such implementation is if I was implementing a REST API over a file system...
So the struct may be defined as in my OP:
type ResourcePatch struct {
ResourceID some.UUID `json:"resource_id"`
Description *string `json:"description,omitempty"`
Name *string `json:"name,omitempty"`
}
In the handler func I'd decode the ID from the path into the ResourcePatch instance and unmarshall JSON from the request body into it, too.
Sending only this
{"description":"Some new description"}
to PATCH /resources/<UUID>
I should end up with with this object:
ResourcePatch
* ResourceID {"UUID"}
* Description {"Some new description"}
And now the magic: use a simple logic to build the query and exec parameters. For some it may seem tedious or repetitive or unclean for bigger PATCH objects, but my reply to this would be: if your PATCH object consists of more than 50% of the original resource' properties (or simply too many for your liking) use PUT and expect the clients to send (and replace) the whole resource instead.
It could look like this:
func (s Store) patchMyResource(r models.ResourcePatch) error {
q := `UPDATE resources SET `
qParts := make([]string, 0, 2)
args := make([]interface{}, 0, 2)
if r.Description != nil {
qParts = append(qParts, `description = ?`)
args = append(args, r.Description)
}
if r.Name != nil {
qParts = append(qParts, `name = ?`)
args = append(args, r.Name)
}
q += strings.Join(qParts, ',') + ` WHERE resource_id = ?`
args = append(args, r.ResourceID)
_, err := s.db.Exec(q, args...)
return err
}
I think there's nothing simpler and more effective. No reflection, no over-kills, reads quite good.
Struct tags are only visible through reflection, sorry.
If you don't want to use reflection (or, I think, even if you do), I think it is Go-like to define a function or method that "marshals" your struct into something that can easily be turned into a comma-separated list of SQL updates, and then use that. Build small things to help solve your problems.
For example given:
type Resource struct {
Name *string `json:"name,omitempty" sql:"resource_id"`
Description *string `json:"description,omitempty" sql:"description"`
}
You might define:
func (r Resource) SQLUpdates() SQLUpdates {
var s SQLUpdates
if (r.Name != nil) {
s.add("resource_id", *r.Name)
}
if (r.Description != nil) {
s.add("description", *r.Description)
}
}
where the type SQLUpdates looks something like this:
type SQLUpdates struct {
assignments []string
values []interface{}
}
func (s *SQLUpdates) add(key string, value interface{}) {
if (s.assignments == nil) {
s.assignments = make([]string, 0, 1)
}
if (s.values == nil) {
s.values = make([]interface{}, 0, 1)
}
s.assignments = append(s.assignments, fmt.Sprintf("%s = ?", key))
s.values = append(s.values, value)
}
func (s SQLUpdates) Assignments() string {
return strings.Join(s.assignments, ", ")
}
func (s SQLUpdates) Values() []interface{} {
return s.values
}
See it working (sorta) here: https://play.golang.org/p/IQAHgqfBRh
If you have deep structs-within-structs, it should be fairly easy to build on this. And if you change to an SQL engine that allows or encourages positional arguments like $1 instead of ?, it's easy to add that behavior to just the SQLUpdates struct without changing any code that used it.
For the purpose of getting arguments to pass to Exec, you would just expand the output of Values() with the ... operator.
My program should read some parameters from the command line. If someone does not provide an optional password parameter the program should ask for it. Therefore the corresponding field is modeled as an Option type.
This works well if the parameter is provided from the command line ( option having the value of Some("..."), but the branch matching the None case does not ask for input.
The simplified program looks like
fn main() {
use std::io::{self,Read};
let arg : Option<String> = None; // Does not terminate
//let arg : Option<String> = Some("Some arg".to_string()); // works well printing 'Some arg'
println!("Checking for password");
let password = match arg {
Some(val) => val.to_string(),
None => {
print!("Password:");
let mut buffer = String::new();
io::stdin().read_to_string(&mut buffer).unwrap();
buffer
}
};
println!("password is {}", password);
}
Running the program preinitialized with Some("Some arg") prints the string "password is Some arg" to the console as expected, but switching to the None does nothing, even not terminating the program.
Could you spot my mistake or give me some advice? I am using rustc verison rustc 1.4.0 (8ab8581f6 2015-10-27). Thanks in advance.
You need to use read_line():
fn main() {
use std::io::{self,Read};
let arg : Option<String> = None; // Does not terminate
//let arg : Option<String> = Some("Some arg".to_string()); // works well printing 'Some arg'
println!("Checking for password");
let password = match arg {
Some(val) => val.to_string(),
None => {
print!("Password:");
let mut buffer = String::new();
io::stdin().read_line(&mut buffer).unwrap();
buffer
}
};
println!("password is {}", password);
}
The read_to_string() function reads until end of file.
Your program does indeed read input, but you need to send it the EOF character (Ctrl-D on Linux) for it to continue executing.