67 Matching Annotations
  1. Last 7 days
    1. ConvertSaveload

      It would be good to describe why ConvertSaveload is used here, as well as how to configure it in Cargo.toml.

      [dependencies] changes I needed in Cargo.toml:

      serde = { version = "1.0.148", features = ["derive"]} specs = { version = "0.18.0", features = ["serde"]}

      and imports:

      ``` use serde::{Deserialize, Serialize}; use specs::{ prelude::*, saveload::{ConvertSaveload, Marker}, Entity, };

      use specs_derive::{Component, ConvertSaveload}; use std::convert::Infallible;

      // NoError alias is deprecated in specs ... but specs_derive needs it pub type NoError = Infallible; ```

  2. Nov 2022
    1. The function signature now tells Rust that for some lifetime 'a, the function takes two parameters, both of which are string slices that live at least as long as lifetime 'a. The function signature also tells Rust that the string slice returned from the function will live at least as long as lifetime 'a. In practice, it means that the lifetime of the reference returned by the longest function is the same as the smaller of the lifetimes of the values referred to by the function arguments.
    1. Copy and Clone. Clone adds a .clone() method to the type, allowing a copy to be made programmatically. Copy changes the default from moving the object on assignment to making a copy - so tile1 = tile2 leaves both values valid and not in a "moved from" state.
    2. Roguelike. [Rogue](https://en.wikipedia.org/wiki/Rogue_(video_game)

      fix hyperlink

    1. context

      should introduce the context earlier, as well as the main function's BError type.

    2. The "S" in ECS stands for "Systems". A System is a piece of code that gathers data from the entity/components list and does something with it. It's actually quite similar to an inheritance model, but in some ways it's "backwards". For example, drawing in an OOP system is often: For each BaseEntity, call that entity's Draw command. In an ECS system, it would be Get all entities with a position and a renderable component, and use that data to draw them.
    3. You can find the glyphs available here.

      Link is dead, maybe use wikipedia instead.

    4. In our tick function

      Need to introduce the tick function and GameState here.

  3. Sep 2022
    1. To criticise Rust for being a complex language misses the point: it's designed to be expressive, which means having a lot of features, and in many situations that's what you want from a programming language.
    2. If you like the functional style of programming, though, you’ll find a lot more facilities for it in Rust, because Rust has a lot more facilities than Go in general.
  4. Jun 2022
    1. However, there are situations where this rule is not flexible enough

      For example, A and B both hold resource R by reference, and both want to modify R

  5. Mar 2022
    1. That’s a lot of match! The match expression is very useful but also very much a primitive.

      这儿有很多 match! match 语法非常有用,但是也非常原始。

  6. Feb 2022
  7. Nov 2021
    1. call works with any lifetime &self happens to have at that point.

      Do not understand this.

  8. Aug 2021
    1. 幸运的是,Rust 对此提供了一个功能,叫做 引用(references)。

      rust 里引用是为了解决所有权 move 的问题。

  9. Mar 2021
    1. Put another way, it’s become clear to me over time that the problems with data races and memory safety arise when you have both aliasing and mutability. The functional approach to solving this problem is to remove mutability. Rust’s approach would be to remove aliasing. This gives us a story to tell and helps to set us apart. A note on terminology: I think we should refer to aliasing as sharing. In the past, we’ve avoided this because of its multithreaded connotations. However, if/when we implement the data parallelism plans I have proposed, then this connotation is not at all inappropriate. In fact, given the close relationship between memory safety and data races, I actually want to promote this connotation.
    1. Rust Compression Features
      [profile.release]
      panic = "abort"
      codegen-units = 1
      lto = true
      incremental = false
      opt-level = "z"
      
  10. Feb 2021
    1. Bringing a great IDE experience to the Rust programming language.

    1. Goroutines: 11.157259715s total, 11.157259ms avg per iterationTokio Tasks: 19.853376396s total, 19.853376ms avg per iterationRust Threads: 25.489677864s total, 25.489677ms avg per iteration

      Golang rocks

    1. The most widely used form of macros in Rust is declarative macros. These are also sometimes referred to as “macros by example,” “macro_rules! macros,” or just plain “macros.” At their core, declarative macros allow you to write something similar to a Rust match expression.
  11. Jan 2021
    1. As an example, recall the Sync and Send marker traits we discussed in the “Extensible Concurrency with the Sync and Send Traits” section in Chapter 16: the compiler implements these traits automatically if our types are composed entirely of Send and Sync types. If we implement a type that contains a type that is not Send or Sync, such as raw pointers, and we want to mark that type as Send or Sync, we must use unsafe. Rust can’t verify that our type upholds the guarantees that it can be safely sent across threads or accessed from multiple threads; therefore, we need to do those checks manually and indicate as such with unsafe.
    2. Constants and immutable static variables might seem similar, but a subtle difference is that values in a static variable have a fixed address in memory. Using the value will always access the same data. Constants, on the other hand, are allowed to duplicate their data whenever they’re used.
    3. As with references, raw pointers can be immutable or mutable and are written as *const T and *mut T, respectively. The asterisk isn’t the dereference operator; it’s part of the type name. In the context of raw pointers, immutable means that the pointer can’t be directly assigned to after being dereferenced. Different from references and smart pointers, raw pointers: Are allowed to ignore the borrowing rules by having both immutable and mutable pointers or multiple mutable pointers to the same location Aren’t guaranteed to point to valid memory Are allowed to be null Don’t implement any automatic cleanup
    1. Ignoring a function parameter can be especially useful in some cases, for example, when implementing a trait when you need a certain type signature but the function body in your implementation doesn’t need one of the parameters. The compiler will then not warn about unused function parameters, as it would if you used a name instead.
    1. The changes we needed to make to main to reassign post mean that this implementation doesn’t quite follow the object-oriented state pattern anymore: the transformations between the states are no longer encapsulated entirely within the Post implementation. However, our gain is that invalid states are now impossible because of the type system and the type checking that happens at compile time! This ensures that certain bugs, such as display of the content of an unpublished post, will be discovered before they make it to production.

      This is really an amazing chapter for comparing (some aspects) of object oriented and functional programming, and I have to admit I still prefer the functional approach as a default.

    1. You can only make object-safe traits into trait objects. Some complex rules govern all the properties that make a trait object safe, but in practice, only two rules are relevant. A trait is object safe if all the methods defined in the trait have the following properties: The return type isn’t Self. There are no generic type parameters.
    2. Trait Objects Perform Dynamic Dispatch Recall in the “Performance of Code Using Generics” section in Chapter 10 our discussion on the monomorphization process performed by the compiler when we use trait bounds on generics: the compiler generates nongeneric implementations of functions and methods for each concrete type that we use in place of a generic type parameter. The code that results from monomorphization is doing static dispatch, which is when the compiler knows what method you’re calling at compile time. This is opposed to dynamic dispatch, which is when the compiler can’t tell at compile time which method you’re calling. In dynamic dispatch cases, the compiler emits code that at runtime will figure out which method to call.
    1. To many people, polymorphism is synonymous with inheritance. But it’s actually a more general concept that refers to code that can work with data of multiple types. For inheritance, those types are generally subclasses. Rust instead uses generics to abstract over different possible types and trait bounds to impose constraints on what those types must provide. This is sometimes called bounded parametric polymorphism.
    2. For example, we can define a struct AveragedCollection that has a field containing a vector of i32 values. The struct can also have a field that contains the average of the values in the vector, meaning the average doesn’t have to be computed on demand whenever anyone needs it. In other words, AveragedCollection will cache the calculated average for us.

      This is a good example of encapsulation.

    1. The Sync marker trait indicates that it is safe for the type implementing Sync to be referenced from multiple threads. In other words, any type T is Sync if &T (a reference to T) is Send, meaning the reference can be sent safely to another thread. Similar to Send, primitive types are Sync, and types composed entirely of types that are Sync are also Sync.
    2. Any type composed entirely of Send types is automatically marked as Send as well. Almost all primitive types are Send, aside from raw pointers, which we’ll discuss in Chapter 19.
    1. As you might suspect, Mutex<T> is a smart pointer. More accurately, the call to lock returns a smart pointer called MutexGuard, wrapped in a LockResult that we handled with the call to unwrap. The MutexGuard smart pointer implements Deref to point at our inner data; the smart pointer also has a Drop implementation that releases the lock automatically when a MutexGuard goes out of scope, which happens at the end of the inner scope in Listing 16-12. As a result, we don’t risk forgetting to release the lock and blocking the mutex from being used by other threads because the lock release happens automatically.
    1. In this context, by runtime we mean code that is included by the language in every binary. This code can be large or small depending on the language, but every non-assembly language will have some amount of runtime code. For that reason, colloquially when people say a language has “no runtime,” they often mean “small runtime.”
    1. *value.borrow_mut() += 10;

      Note that . has higher precedence than *. Here it's:

      *(value.borrow_mut()) += 10
      

      not:

      (*value).borrow_mut() += 10
      
    1. Here’s how it works: when you call a method with object.something(), Rust automatically adds in &, &mut, or * so object matches the signature of the method. In other words, the following are the same:
    1. We could have called a.clone() rather than Rc::clone(&a), but Rust’s convention is to use Rc::clone in this case. The implementation of Rc::clone doesn’t make a deep copy of all the data like most types’ implementations of clone do. The call to Rc::clone only increments the reference count, which doesn’t take much time. Deep copies of data can take a lot of time. By using Rc::clone for reference counting, we can visually distinguish between the deep-copy kinds of clones and the kinds of clones that increase the reference count. When looking for performance problems in the code, we only need to consider the deep-copy clones and can disregard calls to Rc::clone
    2. We could change the definition of Cons to hold references instead, but then we would have to specify lifetime parameters. By specifying lifetime parameters, we would be specifying that every element in the list will live at least as long as the entire list. The borrow checker wouldn’t let us compile let a = Cons(10, &Nil); for example, because the temporary Nil value would be dropped before a could take a reference to it.
    1. You can use code specified in a Drop trait implementation in many ways to make cleanup convenient and safe: for instance, you could use it to create your own memory allocator! With the Drop trait and Rust’s ownership system, you don’t have to remember to clean up because Rust does it automatically.
    1. Panics: The scenarios in which the function being documented could panic. Callers of the function who don’t want their programs to panic should make sure they don’t call the function in these situations. Errors: If the function returns a Result, describing the kinds of errors that might occur and what conditions might cause those errors to be returned can be helpful to callers so they can write code to handle the different kinds of errors in different ways. Safety: If the function is unsafe to call (we discuss unsafety in Chapter 19), there should be a section explaining why the function is unsafe and covering the invariants that the function expects callers to uphold.

      The four common sections are Examples, Panics, Errors, and Safety. OF these, I'm most uncertain about Errors, as I'd have thought this would largely be taken care of by the type (signature).

  12. Dec 2020
    1. 当持有堆中数据值的变量离开作用域时,其值将通过 drop 被清理掉,除非数据被移动为另一个变量所有

      堆中数据值

    1. You might see suggestions to use the 'static lifetime in error messages. But before specifying 'static as the lifetime for a reference, think about whether the reference you have actually lives the entire lifetime of your program or not. You might consider whether you want it to live that long, even if it could. Most of the time, the problem results from attempting to create a dangling reference or a mismatch of the available lifetimes. In such cases, the solution is fixing those problems, not specifying the 'static lifetime.
    2. and you’ll see that the borrow checker approves of this code;

      I found this post to be helpful in understanding why lifetimes aren't automatically inferred in these cases.

    3. The first rule is that each parameter that is a reference gets its own lifetime parameter. In other words, a function with one parameter gets one lifetime parameter: fn foo<'a>(x: &'a i32); a function with two parameters gets two separate lifetime parameters: fn foo<'a, 'b>(x: &'a i32, y: &'b i32); and so on. The second rule is if there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters: fn foo<'a>(x: &'a i32) -> &'a i32. The third rule is if there are multiple input lifetime parameters, but one of them is &self or &mut self because this is a method, the lifetime of self is assigned to all output lifetime parameters. This third rule makes methods much nicer to read and write because fewer symbols are necessary.
    4. Note: The examples in Listings 10-17, 10-18, and 10-24 declare variables without giving them an initial value, so the variable name exists in the outer scope. At first glance, this might appear to be in conflict with Rust’s having no null values. However, if we try to use a variable before giving it a value, we’ll get a compile-time error, which shows that Rust indeed does not allow null values.
  13. Oct 2020
  14. Sep 2020
  15. Aug 2020
  16. Jul 2020
  17. Jun 2020
    1. fn another_function(x: i32, y: i32) {     println!("x 的值为 : {}", x);     println!("y 的值为 : {}", y); }

      参数类型冒号定义在后面,i32代表整数

  18. May 2020
    1. Programming languages These will probably expose my ignorance pretty nicely.

      When to use different programming languages (advice from an Amazon employee):

      • Java - enterprise applications
      • C# - Microsoft's spin on Java (useful in the Microsoft's ecosystem)
      • Ruby - when speed is more important then legibility or debugging
      • Python - same as Ruby but also for ML/AI (don't forget to use type hinting to make life a little saner)
      • Go/Rust - fresh web service where latency and performance were more important than community/library support
      • Haskell/Erlang - for very elegant/mathematical functional approach without a lot of business logic
      • Clojure - in situation when you love Lisp (?)
      • Kotlin/Scala - languages compiling to JVM bytecode (preferable over Clojure). Kotlin works with Java and has great IntelliJ support
      • C - classes of applications (operating systems, language design, low-level programming and hardware)
      • C++ - robotics, video games and high frequency trading where the performance gains from no garbage collection make it preferable to Java
      • PHP/Hack - testing server changes without rebuilding. PHP is banned at Amazon due to security reasons, but its successor, Hack, runs a lot of Facebook and Slack's backends
  19. Feb 2020
  20. Feb 2019
  21. Nov 2018
  22. Sep 2018
  23. May 2018
  24. Dec 2017
  25. Apr 2017
  26. Aug 2015
    1. Stdlib support for a global Trace trait that everyone derives would be awesome.

      The issue of wanting to augment structs from external crates with additional traits seems like a pretty generic problem. Seems a shame to solve it only for GC tracing.