Popular New Releases in Go
kubernetes
Kubernetes v1.24.0-rc.0
moby
v20.10.12
hugo
v0.97.3
gin
Release v1.7.7
frp
v0.41.0
Popular Libraries in Go
by golang go
97672
NOASSERTION
The Go programming language
by kubernetes go
87661
Apache-2.0
Production-Grade Container Scheduling and Management
by avelino go
76582
MIT
A curated list of awesome Go frameworks, libraries and software
by moby go
62382
Apache-2.0
Moby Project - a collaborative project for the container ecosystem to assemble container-based systems
by gohugoio go
58416
Apache-2.0
The world’s fastest framework for building websites.
by gin-gonic go
56154
MIT
Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.
by fatedier go
55464
Apache-2.0
A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.
by syncthing go
44131
MPL-2.0
Open Source Continuous File Synchronization
by junegunn go
43649
MIT
:cherry_blossom: A command-line fuzzy finder
Trending New libraries in Go
by gofiber go
19407
MIT
⚡️ Express inspired web framework written in Go
by zeromicro go
16273
MIT
A web and RPC framework written in Go. It's born to ensure the stability of the busy sites with resilient design. Builtin goctl greatly improves the development productivity.
by greyireland go
12016
算法模板,最科学的刷题方式,最快速的刷题路径,你值得拥有~
by tal-tech go
10720
MIT
go-zero is a web and rpc framework written in Go. It's born to ensure the stability of the busy sites with resilient design. Builtin goctl greatly improves the development productivity.
by charmbracelet go
9726
MIT
A powerful little TUI framework 🏗
by muesli go
8271
NOASSERTION
Disk Usage/Free Utility - a better 'df' alternative
by XTLS go
8099
MPL-2.0
Xray, Penetrates Everything. Also the best v2ray-core, with XTLS support. Fully compatible configuration.
by projectdiscovery go
7947
MIT
Fast and customizable vulnerability scanner based on simple YAML based DSL.
by lima-vm go
7768
Apache-2.0
Linux virtual machines, typically on macOS, for running containerd
Top Authors in Go
1
321 Libraries
21651
2
316 Libraries
0
3
268 Libraries
183422
4
235 Libraries
180804
5
233 Libraries
18842
6
212 Libraries
7560
7
198 Libraries
2566
8
195 Libraries
0
9
188 Libraries
1559
10
159 Libraries
13
1
321 Libraries
21651
2
316 Libraries
0
3
268 Libraries
183422
4
235 Libraries
180804
5
233 Libraries
18842
6
212 Libraries
7560
7
198 Libraries
2566
8
195 Libraries
0
9
188 Libraries
1559
10
159 Libraries
13
Trending Kits in Go
Here are some of the famous Go Telegram Bot Libraries. These Libraries are used for Building custom bots for customer service, Developing bots for e-commerce and Building bots for entertainment.
Go Telegram Bot Libraries are libraries written in the programming language Go which provide an interface to the Telegram Bot API. They allow developers to create and interact with Telegram bots in their own applications. They provide a range of features such as easy setup, custom commands, webhooks, and more.
Let us have a look at these libraries in detail below.
Telegram
- Provides a highly customizable environment to create bots.
- Provides a Botstore, which is a library of bots created by other developers.
- Provides excellent security for bots, with end-to-end encryption and access control.
telegram-bot-api
- Provides webhooks and inline keyboards for interaction with users.
- Supports deep linking to external websites and content within the Telegram app.
- Offers a unique set of features such as group chats, channels, and sticker sets.
TelegramBots
- Offers advanced features such as game playing, natural language processing, and automated responses.
- Supports webhooks which allow you to receive messages and updates from other services and systems.
- Allows you to customize your bots with a variety of useful features such as message templates
Telebot
- Offers secure bot creation and hosting with built-in features to protect user data.
- Designed to deliver reliable performance even when handling large volumes of requests.
- Offers advanced features such as inline keyboards, custom commands and user profiles.
telegram-bot-sdk
- Supports multiple programming languages, such as JavaScript, Python, and Java.
- Included in Telegram-bot-sdk is well-documented and easy to understand.
- Enables developers to quickly create and customize powerful bots to fit their needs.
go-tgbot
- Provides a powerful command line tool that helps developers to quickly create and manage their Telegram bots.
- Supports all the standard Telegram API features and adds several unique features such as custom keyboards, inline bot queries and more.
- Supports a wide range of databases, including MongoDB, Redis, BoltDB and more.
telegram-bot-go
- Quickly build and deploy a Telegram bot with minimal effort.
- Comes with comprehensive documentation and tutorials.
- Offers advanced features such as custom commands, inline commands, and support for multiple languages.
gotelebot
- Provides a convenient way to create custom commands for your bot.
- Supports webhooks, allowing you to create more interactive bots quickly and easily.
- Support for all the major Telegram Bot API features and extras.
Go Database libraries offer a generic SQL database interface. It supports databases like MySQL, SQLite, PostgreSQL, and many more. This library offers an effortless way to connect various databases and manage those connections. It supports the execution of SQL queries and prepared statements, allowing easy and secure access to databases.
Go Database libraries offer a simple and intuitive way to manage database transactions, allowing the execution of different SQL statements as a single unit of work. This library offers detailed error handling, providing developers with more information on what went wrong in case of any error. This library supports prepared statements, which will help prevent SQL injection attacks and make it a secure way to interact with databases. It is a generic SQL database interface and supports multiple database drivers making it a flexible and versatile choice for building database-driven applications.
Here is the list of the 13 best Go Database libraries that are handpicked to help developers:
prometheus:
- Is designed for collecting metrics from various sources, storing, and querying them to provide insights into a system's health and performance.
- Offers a set of tools to build applications that exposes metrics in a format that prometheus can understand.
- Supports several metrics like gauges, summaries, counters, and histograms.
tidb:
- Is an open source, MySQL-compatible, distributed RDBMS built for scalability and performance.
- Offers a way for executing SQL queries against TiDB databases.
- Offers a way to create, modify, and delete database schemas, indexes, and tables.
cockroach:
- Is an open source, distributed SQL DBMS designed to provide reliable, scalable, and universally available transactional data storage.
- Offers a way for executing SQL queries against CockroachDB databases.
- Offers a simple and intuitive way to manage transactions in CockroachDB databases, allowing you to execute multiple SQL statements as a single unit of work.
influxdb:
- Offers an easy-to-use interface to perform common database operations like creating and deleting databases, reading, and writing data, and managing users.
- Is available in various programming languages like Java, JavaScript, Go, and Python.
- Every library implementation offers a set of classes and functions which can be used for interacting with InfluxDB.
dgraph:
- Is a distributed graph database that supports a flexible query and schema and is optimized for handling large-scale graph data.
- Offers an easy-to-use interface to perform common database operations like creating and deleting edges and nodes, reading, and writing data, and managing indexes.
- Includes writing data to the database, querying data from the database, and managing schema and indexes.
milvus:
- Is an open source vector database designed for storing and searching large-scale vector data like videos, images, and audio.
- Supports similarity search, allowing users to search for similar vectors in a dataset.
- Is a software library that will allow developers to interact with Milvus from within their programs.
sqlx:
- Is an open source library that offers an enhanced interface for working with SQL databases in Rust.
- Offers a simple and ergonomic API for interacting with databases, making it easier to write robust and efficient database code and reducing boilerplate code.
- Supports Rust’s async/await syntax, allowing non-blocking I/O operations and efficient use of system resources.
teleport:
- Is an open source library that offers secure access to computing resources like containers, Kubernetes clusters, and servers.
- Offers a unified access layer that can be used for authorized and authenticated users, managing access to resources, and auditing user activity.
- Can be integrated into existing applications and supports different authentication like MFA and SSO.
rqlite:
- Is an open source distributed SQL database designed for use in high-throughput and low-latency environments.
- Offers consistent performance, fault tolerance, and scalability by distributing SQL queries and data across different nodes in a cluster.
- Can make it easier for developers to build applications that use rqlite as their data store.
immudb:
- Is a key-value database, open source transactional with built-in cryptographic verification.
- Offers tamper-evident storage, is immutable, and supports ACID transactions.
- Includes executing transactions that modify the database, configuring the cryptographic verification settings, and monitoring database health and performance.
db:
- Is a productive data access layer for the Go programming language, which offers agnostic tools to work with various data sources.
- Provides tools for common operations with databases and stays out of the way with advanced cases.
- Offers a common interface for developers to work with different NoSQL and SQL database engines.
cayley:
- Allows developers to store and query graph data using various query languages like SPARQL, Gremlin, and GraphQL.
- Is a software library that will allow developers to interact with Cayley from within their programs.
- Can make it easier for developers to build applications that use Cayley as their data store.
vitess:
- Offers horizontal resharding, scaling, and failover capabilities for MySQL databases.
- Is a software library that will allow developers to interact with Vitess from within their programming.
- Developers can focus on building their application's logic and let the library handle the low-level details of communicating with the Vitess database cluster.
Go Math Libraries offer various features, making working with mathematical computations and analysis easy. These libraries offer various mathematical functions which can be used for performing common calculations. These functions include logarithmic functions, trigonometric functions, and many more.
The Go Math programming language is known for offering high performance, so the math libraries built with Go are often fast and efficient. It makes it ideal for larger datasets or when performing complex calculations. They also offer various data structures which can be used for storing and manipulating mathematical data like matrices, vectors, and different data types. It also offers tools for visualizing mathematical data like charts and graphs. These tools will help make complex mathematical concepts easy to understand.
Here is the list of the top 6 Go Math Libraries handpicked to help developers perform mathematical computations and analysis easily and efficiently.
gonum:
- Offers a package for performing linear algebra operations like vector operations, matrix operations, and solving linear systems of equations.
- Provides a package for optimization that includes constrained, unconstrained, and gradient-based optimization algorithms.
- Offers a package for working with graphs, like algorithms for shortest path finding, graph traversal, and many more.
stats:
- Offers functions for calculating basic statistics like median, variance, standard deviation, mean, and mode.
- Offers functions for working with a probability distribution, like calculating probability density functions, generating random numbers from different distributions, and cumulative distribution functions.
- Offers functions for conducting hypothesis tests like chi-squared tests, ANOVA tests, and t-tests.
gosl:
- Provides various numerical methods like numerical integration, optimization algorithms, and root finding.
- Provides a package for linear algebra operations like vector and matrix operations, eigenvalue and eigenvector calculations, linear systems solve, and more.
- Offers a package for solving differential equations, including partial differential equations and ordinary differential equations.
mathgl:
- Provides various tools for creating 2D and 3D plots of mathematical data like line plots, scatter plots, contour plots, and more.
- Offers functions for visualizing vector fields, including vector fields and streamline plots.
- Offers a package for symbolic math operations like integration, simplification, and differentiation of mathematical equations.
fixed:
- Offers functions for performing arithmetic operations like subtraction, addition, division, and multiplication.
- Provides functions for calculating trigonometric functions like cosine, sine, and tangent.
- Offers functions for calculating logarithmic and exponential functions like the base 2 and natural logarithm.
gomatrix:
- Provides various matrix operations like matrix addition, subtraction, multiplication, division, and many more.
- Offers functions for linear algebra operations like matrix decomposition, eigenvector, and eigenvalue calculations, inversion, singular value decomposition, and many more.
- Offers functions for vector operations like cross and dot product and normalization.
Facebook's Metaverse is vaporware as of today, but it has people talking and looking at new opportunities. Especially the developers: with virtual reality all set to raid the mainstream, application development that can support 3-dimensional experiences do display certain developmental complications and require experimentation. In fact, Statista reports that virtual reality is a market the size of $4.8 billion (2021). That being so, there is immense potential and a bright future for developers honing their skills in the niche.
Metaverse isn’t a single entity, as opposed to common belief: it is merely a “status” or a platform where people can gather, kind of like social media. In fact, tech-biggies like Microsoft and Nvidia have their own purpose-driven versions of metaverse platforms where users can log on and accomplish certain goals. Commercial biggie metaverses apart, there are quite a few open-source metaverses in the realm – like that of Mozilla i.e. Mozilla Hub.
Developers take note: virtual reality is soon coming into the mainstream, and the development of applications that can bridge the real and the virtual is going to be in demand. Open source holds quite a leverage in the development of metaverse components, being universal and readily implementable. Much like the 1900s saw a boom in two-dimensional internet, 2020 and onwards is the era of three-dimensional experiences in virtual reality. There is a high opportunity and potential for the developers here.
Go is a programming language that makes it easy to build simple, reliable, and efficient software. Go is a programming language developed by Google in 2009. In recent years, it has gained popularity among developers due to its easy-to-learn and use syntax and the fact that it is an open source language. Go has been used for building server applications, websites, games and also mobile apps. There are many free Go coding assessment libraries available for developers to use. These libraries help in improving the performance of the application and make it more user friendly. Go can be used to create high performing applications that are easy to maintain. Some of the most popular Go Coding Assessment Open Source libraries among developers are: kube-scan - kubescan: Octarine k8s cluster risk assessment tool; recursebuster - rapid content discovery tool for recursively querying webservers; paf-credentials-checker - high performing offline tool to easily assess.
Trending Discussions on Go
Why is Rust NLL not working for multiple borrows in the same statement?
Docker push to AWS ECR hangs immediately and times out
How does Java know which overloaded method to call with lambda expressions? (Supplier, Consumer, Callable, ...)
pip-compile raising AssertionError on its logging handler
Is if(A | B) always faster than if(A || B)?
What is the proper evaluation order when assigning a value in a map?
Unable to specify `edition2021` in order to use unstable packages in Rust
Android Studio strange code sub-windows after upgrade to Arctic Fox (2020.3.1)
ellipsis ... as function in substitute?
Python 3.10 pattern matching (PEP 634) - wildcard in string
QUESTION
Why is Rust NLL not working for multiple borrows in the same statement?
Asked 2022-Apr-12 at 00:43First, I tried something like this:
1let mut vec = vec![0];
2vec.rotate_right(vec.len());
3
It can't be compiled because:
error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable
I thought that the Rust borrow checker could be smarter than this, so I found something called NLL, and it should solve this problem.
I tried the sample:
1let mut vec = vec![0];
2vec.rotate_right(vec.len());
3let mut vec = vec![0];
4vec.resize(vec.len(), 0);
5
It could work, but why is it not working with rotate_right
? Both of them take a &mut self
. What's going on?
ANSWER
Answered 2022-Apr-12 at 00:43It is definitely an interesting one.
They are similar - but not quite the same. resize()
is a member of Vec
. rotate_right()
, on the other hand, is a method of slices.
Vec<T>
derefs to [T]
, so most of the time this does not matter. But actually, while this call:
1let mut vec = vec![0];
2vec.rotate_right(vec.len());
3let mut vec = vec![0];
4vec.resize(vec.len(), 0);
5vec.resize(vec.len(), 0);
6
Desugars to something like:
1let mut vec = vec![0];
2vec.rotate_right(vec.len());
3let mut vec = vec![0];
4vec.resize(vec.len(), 0);
5vec.resize(vec.len(), 0);
6<Vec<i32>>::resize(&mut vec, <Vec<i32>>::len(&vec), 0);
7
This call:
1let mut vec = vec![0];
2vec.rotate_right(vec.len());
3let mut vec = vec![0];
4vec.resize(vec.len(), 0);
5vec.resize(vec.len(), 0);
6<Vec<i32>>::resize(&mut vec, <Vec<i32>>::len(&vec), 0);
7vec.rotate_right(vec.len());
8
Is more like:
1let mut vec = vec![0];
2vec.rotate_right(vec.len());
3let mut vec = vec![0];
4vec.resize(vec.len(), 0);
5vec.resize(vec.len(), 0);
6<Vec<i32>>::resize(&mut vec, <Vec<i32>>::len(&vec), 0);
7vec.rotate_right(vec.len());
8<[i32]>::rotate_right(
9 <Vec<i32> as DerefMut>::deref_mut(&mut vec),
10 <Vec<i32>>::len(&vec),
11);
12
But in what order?
This is the MIR for rotate_right()
(simplified a lot):
1let mut vec = vec![0];
2vec.rotate_right(vec.len());
3let mut vec = vec![0];
4vec.resize(vec.len(), 0);
5vec.resize(vec.len(), 0);
6<Vec<i32>>::resize(&mut vec, <Vec<i32>>::len(&vec), 0);
7vec.rotate_right(vec.len());
8<[i32]>::rotate_right(
9 <Vec<i32> as DerefMut>::deref_mut(&mut vec),
10 <Vec<i32>>::len(&vec),
11);
12fn foo() -> () {
13 _4 = <Vec<i32> as DerefMut>::deref_mut(move _5);
14 _6 = Vec::<i32>::len(move _7);
15 _2 = core::slice::<impl [i32]>::rotate_right(move _3, move _6);
16}
17
And this is the MIR for resize()
(again, simplified a lot):
1let mut vec = vec![0];
2vec.rotate_right(vec.len());
3let mut vec = vec![0];
4vec.resize(vec.len(), 0);
5vec.resize(vec.len(), 0);
6<Vec<i32>>::resize(&mut vec, <Vec<i32>>::len(&vec), 0);
7vec.rotate_right(vec.len());
8<[i32]>::rotate_right(
9 <Vec<i32> as DerefMut>::deref_mut(&mut vec),
10 <Vec<i32>>::len(&vec),
11);
12fn foo() -> () {
13 _4 = <Vec<i32> as DerefMut>::deref_mut(move _5);
14 _6 = Vec::<i32>::len(move _7);
15 _2 = core::slice::<impl [i32]>::rotate_right(move _3, move _6);
16}
17fn foo() -> () {
18 _4 = Vec::<i32>::len(move _5);
19 _2 = Vec::<i32>::resize(move _3, move _4, const 0_i32);
20}
21
In the resize()
example, we first call Vec::len()
with a reference to vec
. This returns usize
. Then we call Vec::resize()
, when we have no outstanding references to vec
, so mutably borrowing it is fine!
However, with rotate_right()
, first we call <Vec<i32> as DerefMut>::deref_mut(&mut vec)
. This returns &mut [i32]
, with its lifetime tied to vec
. That is, as long as this reference (mutable reference!) is alive, we are not allowed to use have any other reference to vec
. But then we try to borrow vec
in order to pass the (shared, but it doesn't matter) reference to Vec::len()
, while we still need to use the mutable reference from deref_mut()
later, in the call to <[i32]>::rotate_right()
! This is an error.
This is because Rust defines an evaluation order for operands:
Expressions taking multiple operands are evaluated left to right as written in the source code.
Because vec.resize()
is actually (&mut *vec).rotate_right()
, we first evaluate the dereference+reference, then the arguments:
1let mut vec = vec![0];
2vec.rotate_right(vec.len());
3let mut vec = vec![0];
4vec.resize(vec.len(), 0);
5vec.resize(vec.len(), 0);
6<Vec<i32>>::resize(&mut vec, <Vec<i32>>::len(&vec), 0);
7vec.rotate_right(vec.len());
8<[i32]>::rotate_right(
9 <Vec<i32> as DerefMut>::deref_mut(&mut vec),
10 <Vec<i32>>::len(&vec),
11);
12fn foo() -> () {
13 _4 = <Vec<i32> as DerefMut>::deref_mut(move _5);
14 _6 = Vec::<i32>::len(move _7);
15 _2 = core::slice::<impl [i32]>::rotate_right(move _3, move _6);
16}
17fn foo() -> () {
18 _4 = Vec::<i32>::len(move _5);
19 _2 = Vec::<i32>::resize(move _3, move _4, const 0_i32);
20}
21let dereferenced_vec = &mut *vec;
22let len = vec.len();
23dereferencec_vec.rotate_right(len);
24
Which is obviously a violation of the borrow rules.
On the other hand, vec.resize(vec.len())
has no work to do on the callee (vec
), and so we first evaluate vec.len()
, and then the call itself.
Solving this is as easy as extracting the vec.len()
to a new line (new statement, to be precise), and the compiler also suggests that.
QUESTION
Docker push to AWS ECR hangs immediately and times out
Asked 2022-Mar-30 at 07:53I'm trying to push my first docker image to ECR. I've followed the steps provided by AWS and things seem to be going smoothly until the final push which immediately times out. Specifically, I pass my aws ecr credentials to docker and get a "login succeeded" message. I then tag the image which also works. pushing to the ecr repo I get no error message, just the following:
1The push refers to repository [xxxxxxxxxxx.dkr.ecr.ca-central-1.amazonaws.com/reponame]
2714c1b96dd83: Retrying in 1 second
3d2cdc77dd068: Retrying in 1 second
430aad807caf5: Retrying in 1 second
50559774c4ea2: Retrying in 1 second
6285b8616682f: Retrying in 1 second
74aeea0ec2b15: Waiting
81b1312f842d8: Waiting
9c310009e0ef3: Waiting
10a48777e566d3: Waiting
112a0c9f28029a: Waiting
12EOF
13
It tries a bunch of times and then exits with no message. Any idea what's wrong?
ANSWER
Answered 2022-Jan-02 at 14:23I figured out my issue. I wasn't using the correct credentials. I had a personal AWS account as my default credentials and needed to add my work profile to my credentials.
EDIT
If you have multiple aws profiles, you can mention the profile name at the docker login as below (assuming you have done aws configure --profile someprofile
at earlier day),
1The push refers to repository [xxxxxxxxxxx.dkr.ecr.ca-central-1.amazonaws.com/reponame]
2714c1b96dd83: Retrying in 1 second
3d2cdc77dd068: Retrying in 1 second
430aad807caf5: Retrying in 1 second
50559774c4ea2: Retrying in 1 second
6285b8616682f: Retrying in 1 second
74aeea0ec2b15: Waiting
81b1312f842d8: Waiting
9c310009e0ef3: Waiting
10a48777e566d3: Waiting
112a0c9f28029a: Waiting
12EOF
13aws ecr get-login-password --region us-east-1 --profile someprofile | docker login ....
14
QUESTION
How does Java know which overloaded method to call with lambda expressions? (Supplier, Consumer, Callable, ...)
Asked 2022-Mar-17 at 08:29First off, I have no idea how to decently phrase the question, so this is up for suggestions.
Lets say we have following overloaded methods:
1void execute(Callable<Void> callable) {
2 try {
3 callable.call();
4 } catch (Exception e) {
5 e.printStackTrace();
6 }
7}
8
9<T> T execute(Supplier<T> supplier) {
10 return supplier.get();
11}
12
13void execute(Runnable runnable) {
14 runnable.run();
15}
16
Going off from this table, I got from another SO question
1void execute(Callable<Void> callable) {
2 try {
3 callable.call();
4 } catch (Exception e) {
5 e.printStackTrace();
6 }
7}
8
9<T> T execute(Supplier<T> supplier) {
10 return supplier.get();
11}
12
13void execute(Runnable runnable) {
14 runnable.run();
15}
16Supplier () -> x
17Consumer x -> ()
18BiConsumer x, y -> ()
19Callable () -> x throws ex
20Runnable () -> ()
21Function x -> y
22BiFunction x,y -> z
23Predicate x -> boolean
24UnaryOperator x1 -> x2
25BinaryOperator x1,x2 -> x3
26
These are the results I get locally:
1void execute(Callable<Void> callable) {
2 try {
3 callable.call();
4 } catch (Exception e) {
5 e.printStackTrace();
6 }
7}
8
9<T> T execute(Supplier<T> supplier) {
10 return supplier.get();
11}
12
13void execute(Runnable runnable) {
14 runnable.run();
15}
16Supplier () -> x
17Consumer x -> ()
18BiConsumer x, y -> ()
19Callable () -> x throws ex
20Runnable () -> ()
21Function x -> y
22BiFunction x,y -> z
23Predicate x -> boolean
24UnaryOperator x1 -> x2
25BinaryOperator x1,x2 -> x3
26// Runnable -> expected as this is a plain void
27execute(() -> System.out.println());
28
29// Callable -> why is it not a Supplier? It does not throw any exceptions..
30execute(() -> null);
31
32// Supplier -> this returns an Object, but how is that different from returning null?
33execute(() -> new Object());
34
35// Callable -> because it can throw an exception, right?
36execute(() -> {throw new Exception();});
37
How does the compiler know which method to call?
How does it for example make the distinction between what's a Callable
and what's a Runnable
?
ANSWER
Answered 2022-Mar-17 at 08:29It all makes sense and has a simple pattern besides () -> null
being a Callable
I think. The Runnable
is clearly different from the Supplier
/Callable
as it has no input and output values. The difference between Callable
and Supplier
is that with the Callable
you have to handle exceptions.
The reason that () -> null
is a Callable without an exception is the return type of your definition Callable<Void>
. It requires you to return the reference to some object. The only possible reference to return for Void
is null
. This means that the lambda () -> null
is exactly what your definition demands. It would also work for your Supplier
example if you would remove the Callable
definition. However, it uses Callable<Void>
over Supplier<T>
as the Callable
has the exact type.
Callable
is chosen over Supplier
as it is more specific (as a comment already suggested). The Java Docs state that it chooses the most specific type if possible:
Type inference is a Java compiler's ability to look at each method invocation and corresponding declaration to determine the type argument (or arguments) that make the invocation applicable. The inference algorithm determines the types of the arguments and, if available, the type that the result is being assigned, or returned. Finally, the inference algorithm tries to find the most specific type that works with all of the arguments.
QUESTION
pip-compile raising AssertionError on its logging handler
Asked 2022-Feb-13 at 12:37I have a dockerfile that currently only installs pip-tools
1FROM python:3.9
2
3RUN pip install --upgrade pip && \
4 pip install pip-tools
5
6COPY ./ /root/project
7
8WORKDIR /root/project
9
10ENTRYPOINT ["tail", "-f", "/dev/null"]
11
I build and open a shell in the container using the following commands:
1FROM python:3.9
2
3RUN pip install --upgrade pip && \
4 pip install pip-tools
5
6COPY ./ /root/project
7
8WORKDIR /root/project
9
10ENTRYPOINT ["tail", "-f", "/dev/null"]
11docker build -t brunoapi_image .
12docker run --rm -ti --name brunoapi_container --entrypoint bash brunoapi_image
13
Then, when I try to run pip-compile
inside the container I get this very weird error (full traceback):
1FROM python:3.9
2
3RUN pip install --upgrade pip && \
4 pip install pip-tools
5
6COPY ./ /root/project
7
8WORKDIR /root/project
9
10ENTRYPOINT ["tail", "-f", "/dev/null"]
11docker build -t brunoapi_image .
12docker run --rm -ti --name brunoapi_container --entrypoint bash brunoapi_image
13root@727f1f38f095:~/project# pip-compile
14Traceback (most recent call last):
15 File "/usr/local/bin/pip-compile", line 8, in <module>
16 sys.exit(cli())
17 File "/usr/local/lib/python3.9/site-packages/click/core.py", line 1128, in __call__
18 return self.main(*args, **kwargs)
19 File "/usr/local/lib/python3.9/site-packages/click/core.py", line 1053, in main
20 rv = self.invoke(ctx)
21 File "/usr/local/lib/python3.9/site-packages/click/core.py", line 1395, in invoke
22 return ctx.invoke(self.callback, **ctx.params)
23 File "/usr/local/lib/python3.9/site-packages/click/core.py", line 754, in invoke
24 return __callback(*args, **kwargs)
25 File "/usr/local/lib/python3.9/site-packages/click/decorators.py", line 26, in new_func
26 return f(get_current_context(), *args, **kwargs)
27 File "/usr/local/lib/python3.9/site-packages/piptools/scripts/compile.py", line 342, in cli
28 repository = PyPIRepository(pip_args, cache_dir=cache_dir)
29 File "/usr/local/lib/python3.9/site-packages/piptools/repositories/pypi.py", line 106, in __init__
30 self._setup_logging()
31 File "/usr/local/lib/python3.9/site-packages/piptools/repositories/pypi.py", line 455, in _setup_logging
32 assert isinstance(handler, logging.StreamHandler)
33AssertionError
34
I have no clue what's going on and I've never seen this error before. Can anyone shed some light into this?
Running on macOS Monterey
ANSWER
Answered 2022-Feb-05 at 16:30It is a bug, you can downgrade using:
pip install "pip<22"
QUESTION
Is if(A | B) always faster than if(A || B)?
Asked 2022-Feb-11 at 05:03I am reading this book by Fedor Pikus and he has some very very interesting examples which for me were a surprise.
Particularly this benchmark caught me, where the only difference is that in one of them we use || in if and in another we use |.
1void BM_misspredict(benchmark::State& state)
2{
3
4 std::srand(1);
5 const unsigned int N = 10000;;
6 std::vector<unsigned long> v1(N), v2(N);
7 std::vector<int> c1(N), c2(N);
8
9 for (int i = 0; i < N; ++i)
10 {
11 v1[i] = rand();
12 v2[i] = rand();
13 c1[i] = rand() & 0x1;
14 c2[i] = !c1[i];
15 }
16
17 unsigned long* p1 = v1.data();
18 unsigned long* p2 = v2.data();
19 int* b1 = c1.data();
20 int* b2 = c2.data();
21
22 for (auto _ : state)
23 {
24 unsigned long a1 = 0, a2 = 0;
25 for (size_t i = 0; i < N; ++i)
26 {
27 if (b1[i] || b2[i]) // Only difference
28 {
29 a1 += p1[i];
30 }
31 else
32 {
33 a2 *= p2[i];
34 }
35 }
36 benchmark::DoNotOptimize(a1);
37 benchmark::DoNotOptimize(a2);
38 benchmark::ClobberMemory();
39
40 }
41 state.SetItemsProcessed(state.iterations());
42}
43
44void BM_predict(benchmark::State& state)
45{
46
47 std::srand(1);
48 const unsigned int N = 10000;;
49 std::vector<unsigned long> v1(N), v2(N);
50 std::vector<int> c1(N), c2(N);
51
52 for (int i = 0; i < N; ++i)
53 {
54 v1[i] = rand();
55 v2[i] = rand();
56 c1[i] = rand() & 0x1;
57 c2[i] = !c1[i];
58 }
59
60 unsigned long* p1 = v1.data();
61 unsigned long* p2 = v2.data();
62 int* b1 = c1.data();
63 int* b2 = c2.data();
64
65 for (auto _ : state)
66 {
67 unsigned long a1 = 0, a2 = 0;
68 for (size_t i = 0; i < N; ++i)
69 {
70 if (b1[i] | b2[i]) // Only difference
71 {
72 a1 += p1[i];
73 }
74 else
75 {
76 a2 *= p2[i];
77 }
78 }
79 benchmark::DoNotOptimize(a1);
80 benchmark::DoNotOptimize(a2);
81 benchmark::ClobberMemory();
82
83 }
84 state.SetItemsProcessed(state.iterations());
85}
86
I will not go in all the details explained in the book why the latter is faster, but the idea is that hardware branch predictor is given 2 chances to misspredict in slower version and in the | (bitwise or) version. See the benchmark results below.
So the question is why don't we always use | instead of || in branches?
ANSWER
Answered 2022-Feb-08 at 19:57Code readability, short-circuiting and it is not guaranteed that Ord will always outperform a ||
operand.
Computer systems are more complicated than expected, even though they are man-made.
There was a case where a for loop with a much more complicated condition ran faster on an IBM. The CPU didn't cool and thus instructions were executed faster, that was a possible reason. What I am trying to say, focus on other areas to improve code than fighting small-cases which will differ depending on the CPU and the boolean evaluation (compiler optimizations).
QUESTION
What is the proper evaluation order when assigning a value in a map?
Asked 2022-Feb-02 at 09:25I know that compiler is usually the last thing to blame for bugs in a code, but I do not see any other explanation for the following behaviour of the following C++ code (distilled down from an actual project):
1#include <iostream>
2#include <map>
3
4int main()
5{
6 auto values = { 1, 3, 5 };
7 std::map<int, int> valMap;
8
9 for (auto const & val : values) {
10 std::cout << "before assignment: valMap.size() = " << valMap.size();
11 valMap[val] = valMap.size();
12 std::cout << " -> set valMap[" << val << "] to " << valMap[val] << "\n";
13 }
14}
15
The expected output of this code is:
1#include <iostream>
2#include <map>
3
4int main()
5{
6 auto values = { 1, 3, 5 };
7 std::map<int, int> valMap;
8
9 for (auto const & val : values) {
10 std::cout << "before assignment: valMap.size() = " << valMap.size();
11 valMap[val] = valMap.size();
12 std::cout << " -> set valMap[" << val << "] to " << valMap[val] << "\n";
13 }
14}
15before assignment: valMap.size() = 0 -> set valMap[1] to 0
16before assignment: valMap.size() = 1 -> set valMap[3] to 1
17before assignment: valMap.size() = 2 -> set valMap[5] to 2
18
However, when I build a Release version with the (default) C++14 compiler, the output becomes:
1#include <iostream>
2#include <map>
3
4int main()
5{
6 auto values = { 1, 3, 5 };
7 std::map<int, int> valMap;
8
9 for (auto const & val : values) {
10 std::cout << "before assignment: valMap.size() = " << valMap.size();
11 valMap[val] = valMap.size();
12 std::cout << " -> set valMap[" << val << "] to " << valMap[val] << "\n";
13 }
14}
15before assignment: valMap.size() = 0 -> set valMap[1] to 0
16before assignment: valMap.size() = 1 -> set valMap[3] to 1
17before assignment: valMap.size() = 2 -> set valMap[5] to 2
18before assignment: valMap.size() = 0 -> set valMap[1] to 1
19before assignment: valMap.size() = 1 -> set valMap[3] to 2
20before assignment: valMap.size() = 2 -> set valMap[5] to 3
21
In other words, all values in valMap
are larger by 1 than what they should be - it looks like the map gets appended before the right-hand-side of the assignment is evaluated.
This happens only in a Release build with C++14 language standard (which is the default in VS2019). Debug builds work fine (I hate when this happens - it took me hours to find out what is going on), as do Release builds of C++17 and C++20. This is why it looks like a bug to me.
My question is: is this a compiler bug, or am I doing something wrong/dangerous by using .size()
in the assignment?
ANSWER
Answered 2022-Feb-01 at 15:49The evaluation order of A = B
was not specified before c++17, after c++17 B
is guaranteed to be evaluated before A
, see https://en.cppreference.com/w/cpp/language/eval_order rule 20.
The behaviour of valMap[val] = valMap.size();
is therefore unspecified in c++14, you should use:
1#include <iostream>
2#include <map>
3
4int main()
5{
6 auto values = { 1, 3, 5 };
7 std::map<int, int> valMap;
8
9 for (auto const & val : values) {
10 std::cout << "before assignment: valMap.size() = " << valMap.size();
11 valMap[val] = valMap.size();
12 std::cout << " -> set valMap[" << val << "] to " << valMap[val] << "\n";
13 }
14}
15before assignment: valMap.size() = 0 -> set valMap[1] to 0
16before assignment: valMap.size() = 1 -> set valMap[3] to 1
17before assignment: valMap.size() = 2 -> set valMap[5] to 2
18before assignment: valMap.size() = 0 -> set valMap[1] to 1
19before assignment: valMap.size() = 1 -> set valMap[3] to 2
20before assignment: valMap.size() = 2 -> set valMap[5] to 3
21auto size = valMap.size();
22valMap[val] = size;
23
Or avoid the problem by using emplace
which is more explicit than relying on []
to automatically insert a value if it doesn't already exist:
1#include <iostream>
2#include <map>
3
4int main()
5{
6 auto values = { 1, 3, 5 };
7 std::map<int, int> valMap;
8
9 for (auto const & val : values) {
10 std::cout << "before assignment: valMap.size() = " << valMap.size();
11 valMap[val] = valMap.size();
12 std::cout << " -> set valMap[" << val << "] to " << valMap[val] << "\n";
13 }
14}
15before assignment: valMap.size() = 0 -> set valMap[1] to 0
16before assignment: valMap.size() = 1 -> set valMap[3] to 1
17before assignment: valMap.size() = 2 -> set valMap[5] to 2
18before assignment: valMap.size() = 0 -> set valMap[1] to 1
19before assignment: valMap.size() = 1 -> set valMap[3] to 2
20before assignment: valMap.size() = 2 -> set valMap[5] to 3
21auto size = valMap.size();
22valMap[val] = size;
23valMap.emplace(val, size);
24
QUESTION
Unable to specify `edition2021` in order to use unstable packages in Rust
Asked 2022-Feb-02 at 07:05I want to run an example via Cargo but I am facing an error:
1error: failed to parse manifest at `/Users/aviralsrivastava/dev/subxt/Cargo.toml`
2
The full stacktrace is:
1error: failed to parse manifest at `/Users/aviralsrivastava/dev/subxt/Cargo.toml`
2error: failed to parse manifest at `/Users/aviralsrivastava/dev/subxt/Cargo.toml`
3
4Caused by:
5 feature `edition2021` is required
6
7 The package requires the Cargo feature called `edition2021`, but that feature is not stabilized in this version of Cargo (1.56.0-nightly (b51439fd8 2021-08-09)).
8 Consider adding `cargo-features = ["edition2021"]` to the top of Cargo.toml (above the [package] table) to tell Cargo you are opting in to use this unstable feature.
9 See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#edition-2021 for more information about the status of this feature.
10
Based on the suggestion, I go ahead and modify the Cargo.toml:
1error: failed to parse manifest at `/Users/aviralsrivastava/dev/subxt/Cargo.toml`
2error: failed to parse manifest at `/Users/aviralsrivastava/dev/subxt/Cargo.toml`
3
4Caused by:
5 feature `edition2021` is required
6
7 The package requires the Cargo feature called `edition2021`, but that feature is not stabilized in this version of Cargo (1.56.0-nightly (b51439fd8 2021-08-09)).
8 Consider adding `cargo-features = ["edition2021"]` to the top of Cargo.toml (above the [package] table) to tell Cargo you are opting in to use this unstable feature.
9 See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#edition-2021 for more information about the status of this feature.
10 Consider adding `cargo-features = ["edition2021"]` to the top of Cargo.toml (above the [package] table) to tell Cargo you are opting in to use this unstable feature.
11diff --git a/Cargo.toml b/Cargo.toml
12index 26a02c7..186d09b 100644
13--- a/Cargo.toml
14+++ b/Cargo.toml
15@@ -1,6 +1,6 @@
16 [workspace]
17 members = [".", "cli", "codegen", "macro"]
18-
19+cargo-features = ["edition2021"]
20 [package]
21 name = "subxt"
22 version = "0.15.0"
23(END)
24
I still face the same error as if nothing was changed in the toml file.
How do I resolve the above error in order to use unstable packages?
ANSWER
Answered 2021-Dec-14 at 14:09Update the Rust to satisfy the new edition 2021.
rustup default nightly && rustup update
Thanks to @ken.
Yes, you can use the stable
channel too!
But I love nightly
personally.
QUESTION
Android Studio strange code sub-windows after upgrade to Arctic Fox (2020.3.1)
Asked 2022-Jan-14 at 09:18After Android Studio upgraded itself to version Arctic Fox, I now get these strange sub-windows in my code editor that I can't get rid of. If I click in either of the 2 sub-windows (a one-line window at the top or a 5-line window underneath it (see pic below), it scrolls to the code in question and the sub-windows disappear. But as soon as I navigate away from that code, these sub-windows mysteriously reappear. I can't figure out how to get rid of this.
I restarted Studio and it seemed to go away. Then I refactored a piece of code (Extract to Method Ctrl+Alt+M) and then these windows appeared again. Sometimes these windows appear on a 2nd monitor instead of on top of the code area on the monitor with Android Studio. But eventually they end up back on top of my code editor window.
I have searched hi and low for what this is. Studio help, new features, blog, etc. I am sure that I am just using the wrong terminology to find the answer, so hoping someone else knows.
ANSWER
Answered 2021-Aug-15 at 15:29Just stumbled upon the same thing (strange windows upon attempting to refactor some code after updating to Arctic Fox). After a lot of searching around the options/menus/internet this fixed it for me:
Navigate to:
File > Settings... > Editor > Code Editing
under
Refactorings > Specify refactoring options:
select
In modal dialogs
Press OK.
Fingers crossed refactoring works.
🤞
Further step: Restart Android Studio
QUESTION
ellipsis ... as function in substitute?
Asked 2022-Jan-13 at 06:04I'm having trouble understanding how/why parentheses work where they otherwise should not work®.
1f = function(...) substitute(...()); f(a, b)
2[[1]]
3a
4[[2]]
5b
6# but, substitute returns ..1
7f2 = function(...) substitute(...); f2(a, b)
8a
9
Normally an error is thrown, could not find function "..." or '...' used in an incorrect context, for example when calling (\(...) ...())(5)
.
What I've tried
I have looked at the source code of substitute
to find out why this doesn't happen here. R Internals 1.1.1 and 1.5.2 says ...
is of SEXPTYPE DOTSXP, a pairlist of promises. These promises are what is extracted by substitute
.
1f = function(...) substitute(...()); f(a, b)
2[[1]]
3a
4[[2]]
5b
6# but, substitute returns ..1
7f2 = function(...) substitute(...); f2(a, b)
8a
9# \-substitute #R
10# \-do_substitute #C
11# \-substituteList #C recursive
12# \-substitute #C
13
Going line-by-line, I am stuck at substituteList
, in which h is the current element of ...
being processed. This happens recursively at line 2832 if (TYPEOF(h) == DOTSXP) h = substituteList(h, R_NilValue);
. I haven't found exception handling of a ...()
case in the source code, so I suspect something before this has happened.
In ?substitute
we find substitute works on a purely lexical basis. Does it mean ...()
is a parser trick?
1f = function(...) substitute(...()); f(a, b)
2[[1]]
3a
4[[2]]
5b
6# but, substitute returns ..1
7f2 = function(...) substitute(...); f2(a, b)
8a
9# \-substitute #R
10# \-do_substitute #C
11# \-substituteList #C recursive
12# \-substitute #C
13parse(text = "(\\(...) substitute(...()))(a, b)") |> getParseData() |> subset(text == "...", select = c(7, 9))
14
15#> token text
16#> 4 SYMBOL_FORMALS ...
17#> 10 SYMBOL_FUNCTION_CALL ...
18
The second ellipsis is recognized during lexical analysis as the name of a function call. It doesn't have its own token like |>
does. The output is a pairlist ( typeof(f(a, b))
), which in this case is the same as a regular list (?). I guess it is not a parser trick. But whatever it is, it has been around for a while!
Question:
How does ...()
work?
ANSWER
Answered 2022-Jan-09 at 16:14Note: When referring to documentation and source code, I provide links to an unofficial GitHub mirror of R's official Subversion repository. The links are bound to commit 97b6424 in the GitHub repo, which maps to revision 81461
in the Subversion repo (the latest at the time of this edit).
substitute
is a "special" whose arguments are not evaluated (doc).
1f = function(...) substitute(...()); f(a, b)
2[[1]]
3a
4[[2]]
5b
6# but, substitute returns ..1
7f2 = function(...) substitute(...); f2(a, b)
8a
9# \-substitute #R
10# \-do_substitute #C
11# \-substituteList #C recursive
12# \-substitute #C
13parse(text = "(\\(...) substitute(...()))(a, b)") |> getParseData() |> subset(text == "...", select = c(7, 9))
14
15#> token text
16#> 4 SYMBOL_FORMALS ...
17#> 10 SYMBOL_FUNCTION_CALL ...
18typeof(substitute)
19
1f = function(...) substitute(...()); f(a, b)
2[[1]]
3a
4[[2]]
5b
6# but, substitute returns ..1
7f2 = function(...) substitute(...); f2(a, b)
8a
9# \-substitute #R
10# \-do_substitute #C
11# \-substituteList #C recursive
12# \-substitute #C
13parse(text = "(\\(...) substitute(...()))(a, b)") |> getParseData() |> subset(text == "...", select = c(7, 9))
14
15#> token text
16#> 4 SYMBOL_FORMALS ...
17#> 10 SYMBOL_FUNCTION_CALL ...
18typeof(substitute)
19[1] "special"
20
That means that the return value of substitute
may not agree with parser logic, depending on how the unevaluated arguments are processed internally.
In general, substitute
receives the call ...(<exprs>)
as a LANGSXP
of the form (pseudocode) pairlist(R_DotsSymbol, <exprs>)
(doc). The context of the substitute
call determines how the SYMSXP
R_DotsSymbol
is processed. Specifically, if substitute
was called inside of a function with ...
as a formal argument and rho
as its execution environment, then the result of
1f = function(...) substitute(...()); f(a, b)
2[[1]]
3a
4[[2]]
5b
6# but, substitute returns ..1
7f2 = function(...) substitute(...); f2(a, b)
8a
9# \-substitute #R
10# \-do_substitute #C
11# \-substituteList #C recursive
12# \-substitute #C
13parse(text = "(\\(...) substitute(...()))(a, b)") |> getParseData() |> subset(text == "...", select = c(7, 9))
14
15#> token text
16#> 4 SYMBOL_FORMALS ...
17#> 10 SYMBOL_FUNCTION_CALL ...
18typeof(substitute)
19[1] "special"
20findVarInFrame3(rho, R_DotsSymbol, TRUE)
21
in the body of C utility substituteList
(source) is either a DOTSXP
or R_MissingArg
—the latter if and only if f
was called without arguments (doc). In other contexts, the result is R_UnboundValue
or (exceptionally) some other SEXP
—the latter if and only if a value is bound to the name ...
in rho
. Each of these cases is handled specially by substituteList
.
The multiplicity in the processing of R_DotsSymbol
is the reason why these R statements give different results:
1f = function(...) substitute(...()); f(a, b)
2[[1]]
3a
4[[2]]
5b
6# but, substitute returns ..1
7f2 = function(...) substitute(...); f2(a, b)
8a
9# \-substitute #R
10# \-do_substitute #C
11# \-substituteList #C recursive
12# \-substitute #C
13parse(text = "(\\(...) substitute(...()))(a, b)") |> getParseData() |> subset(text == "...", select = c(7, 9))
14
15#> token text
16#> 4 SYMBOL_FORMALS ...
17#> 10 SYMBOL_FUNCTION_CALL ...
18typeof(substitute)
19[1] "special"
20findVarInFrame3(rho, R_DotsSymbol, TRUE)
21f0 <- function() substitute(...(n = 1)); f0()
22## ...(n = 1)
23f1 <- function(...) substitute(...(n = 1)); f1()
24## $n
25## [1] 1
26g0 <- function() {... <- quote(x); substitute(...(n = 1))}; g0()
27## Error in g0() : '...' used in an incorrect context
28g1 <- function(...) {... <- quote(x); substitute(...(n = 1))}; g1()
29## Error in g1() : '...' used in an incorrect context
30h0 <- function() {... <- NULL; substitute(...(n = 1))}; h0()
31## $n
32## [1] 1
33h1 <- function(...) {... <- NULL; substitute(...(n = 1))}; h1()
34## $n
35## [1] 1
36
Given how ...(n = 1)
is parsed, you might have expected f1
to return call("...", n = 1)
, both g0
and g1
to return call("x", n = 1)
, and both h0
and h1
to throw an error, but that is not the case for the above, mostly undocumented reasons.
When called inside of the R function f
,
1f = function(...) substitute(...()); f(a, b)
2[[1]]
3a
4[[2]]
5b
6# but, substitute returns ..1
7f2 = function(...) substitute(...); f2(a, b)
8a
9# \-substitute #R
10# \-do_substitute #C
11# \-substituteList #C recursive
12# \-substitute #C
13parse(text = "(\\(...) substitute(...()))(a, b)") |> getParseData() |> subset(text == "...", select = c(7, 9))
14
15#> token text
16#> 4 SYMBOL_FORMALS ...
17#> 10 SYMBOL_FUNCTION_CALL ...
18typeof(substitute)
19[1] "special"
20findVarInFrame3(rho, R_DotsSymbol, TRUE)
21f0 <- function() substitute(...(n = 1)); f0()
22## ...(n = 1)
23f1 <- function(...) substitute(...(n = 1)); f1()
24## $n
25## [1] 1
26g0 <- function() {... <- quote(x); substitute(...(n = 1))}; g0()
27## Error in g0() : '...' used in an incorrect context
28g1 <- function(...) {... <- quote(x); substitute(...(n = 1))}; g1()
29## Error in g1() : '...' used in an incorrect context
30h0 <- function() {... <- NULL; substitute(...(n = 1))}; h0()
31## $n
32## [1] 1
33h1 <- function(...) {... <- NULL; substitute(...(n = 1))}; h1()
34## $n
35## [1] 1
36f <- function(...) substitute(...(<exprs>))
37
substitute
evaluates a call to the C utility do_substitute
—you can learn this by looking here—in which argList
gets a LISTSXP
of the form pairlist(x, R_MissingArg)
, where x
is a LANGSXP
of the form pairlist(R_DotsSymbol, <exprs>)
(source).
If you follow the body of do_substitute
, then you will find that the value of t
passed to substituteList
from do_substitute
is a LISTSXP
of the form pairlist(copy_of_x)
(source).
It follows that the while
loop inside of the substituteList
call (source) has exactly one iteration and that the statement CAR(el) == R_DotsSymbol
in the body of the loop (source) is false
in that iteration.
In the false
branch of the conditional (source), h
gets the value
pairlist(substituteList(copy_of_x, env))
. The loop exits and substituteList
returns h
to do_substitute
, which in turn returns CAR(h)
to R (source 1, 2, 3).
Hence the return value of substitute
is substituteList(copy_of_x, env)
, and it remains to deduce the identity of this SEXP
. Inside of this call to substituteList
, the while
loop has 1+m
iterations, where m
is the number of <exprs>
. In the first iteration, the statement CAR(el) == R_DotsSymbol
in the body of the loop is true
.
In the true
branch of the conditional (source), h
is either a DOTSXP
or R_MissingArg
, because f
has ...
as a formal argument (doc). Continuing, you will find that substituteList
returns:
R_NilValue
ifh
wasR_MissingArg
in the firstwhile
iteration andm = 0
,
or, otherwise,
- a
LISTSXP
listing the expressions inh
(ifh
was aDOTSXP
in the firstwhile
iteration) followed by<exprs>
(ifm > 1
), all unevaluated and without substitutions, because the execution environment off
is empty at the time of thesubstitute
call.
Indeed:
1f = function(...) substitute(...()); f(a, b)
2[[1]]
3a
4[[2]]
5b
6# but, substitute returns ..1
7f2 = function(...) substitute(...); f2(a, b)
8a
9# \-substitute #R
10# \-do_substitute #C
11# \-substituteList #C recursive
12# \-substitute #C
13parse(text = "(\\(...) substitute(...()))(a, b)") |> getParseData() |> subset(text == "...", select = c(7, 9))
14
15#> token text
16#> 4 SYMBOL_FORMALS ...
17#> 10 SYMBOL_FUNCTION_CALL ...
18typeof(substitute)
19[1] "special"
20findVarInFrame3(rho, R_DotsSymbol, TRUE)
21f0 <- function() substitute(...(n = 1)); f0()
22## ...(n = 1)
23f1 <- function(...) substitute(...(n = 1)); f1()
24## $n
25## [1] 1
26g0 <- function() {... <- quote(x); substitute(...(n = 1))}; g0()
27## Error in g0() : '...' used in an incorrect context
28g1 <- function(...) {... <- quote(x); substitute(...(n = 1))}; g1()
29## Error in g1() : '...' used in an incorrect context
30h0 <- function() {... <- NULL; substitute(...(n = 1))}; h0()
31## $n
32## [1] 1
33h1 <- function(...) {... <- NULL; substitute(...(n = 1))}; h1()
34## $n
35## [1] 1
36f <- function(...) substitute(...(<exprs>))
37f <- function(...) substitute(...())
38is.null(f())
39## [1] TRUE
40f <- function(...) substitute(...(n = 1))
41identical(f(a = sin(x), b = zzz), pairlist(a = quote(sin(x)), b = quote(zzz), n = 1))
42## [1] TRUE
43
FWIW, it helped me to recompile R after adding some print statements to coerce.c
. For example, I added the following before UNPROTECT(3);
in the body of do_substitute
(source):
1f = function(...) substitute(...()); f(a, b)
2[[1]]
3a
4[[2]]
5b
6# but, substitute returns ..1
7f2 = function(...) substitute(...); f2(a, b)
8a
9# \-substitute #R
10# \-do_substitute #C
11# \-substituteList #C recursive
12# \-substitute #C
13parse(text = "(\\(...) substitute(...()))(a, b)") |> getParseData() |> subset(text == "...", select = c(7, 9))
14
15#> token text
16#> 4 SYMBOL_FORMALS ...
17#> 10 SYMBOL_FUNCTION_CALL ...
18typeof(substitute)
19[1] "special"
20findVarInFrame3(rho, R_DotsSymbol, TRUE)
21f0 <- function() substitute(...(n = 1)); f0()
22## ...(n = 1)
23f1 <- function(...) substitute(...(n = 1)); f1()
24## $n
25## [1] 1
26g0 <- function() {... <- quote(x); substitute(...(n = 1))}; g0()
27## Error in g0() : '...' used in an incorrect context
28g1 <- function(...) {... <- quote(x); substitute(...(n = 1))}; g1()
29## Error in g1() : '...' used in an incorrect context
30h0 <- function() {... <- NULL; substitute(...(n = 1))}; h0()
31## $n
32## [1] 1
33h1 <- function(...) {... <- NULL; substitute(...(n = 1))}; h1()
34## $n
35## [1] 1
36f <- function(...) substitute(...(<exprs>))
37f <- function(...) substitute(...())
38is.null(f())
39## [1] TRUE
40f <- function(...) substitute(...(n = 1))
41identical(f(a = sin(x), b = zzz), pairlist(a = quote(sin(x)), b = quote(zzz), n = 1))
42## [1] TRUE
43 Rprintf("CAR(t) == R_DotsSymbol? %d\n",
44 CAR(t) == R_DotsSymbol);
45 if (TYPEOF(CAR(t)) == LISTSXP || TYPEOF(CAR(t)) == LANGSXP) {
46 Rprintf("TYPEOF(CAR(t)) = %s, length(CAR(t)) = %d\n",
47 type2char(TYPEOF(CAR(t))), length(CAR(t)));
48 Rprintf("CAR(CAR(t)) = R_DotsSymbol? %d\n",
49 CAR(CAR(t)) == R_DotsSymbol);
50 Rprintf("TYPEOF(CDR(CAR(t))) = %s, length(CDR(CAR(t))) = %d\n",
51 type2char(TYPEOF(CDR(CAR(t)))), length(CDR(CAR(t))));
52 }
53 if (TYPEOF(s) == LISTSXP || TYPEOF(s) == LANGSXP) {
54 Rprintf("TYPEOF(s) = %s, length(s) = %d\n",
55 type2char(TYPEOF(s)), length(s));
56 Rprintf("TYPEOF(CAR(s)) = %s, length(CAR(s)) = %d\n",
57 type2char(TYPEOF(CAR(s))), length(CAR(s)));
58 }
59
which helped me confirm what was going into and coming out of the substituteList
call on the previous line:
1f = function(...) substitute(...()); f(a, b)
2[[1]]
3a
4[[2]]
5b
6# but, substitute returns ..1
7f2 = function(...) substitute(...); f2(a, b)
8a
9# \-substitute #R
10# \-do_substitute #C
11# \-substituteList #C recursive
12# \-substitute #C
13parse(text = "(\\(...) substitute(...()))(a, b)") |> getParseData() |> subset(text == "...", select = c(7, 9))
14
15#> token text
16#> 4 SYMBOL_FORMALS ...
17#> 10 SYMBOL_FUNCTION_CALL ...
18typeof(substitute)
19[1] "special"
20findVarInFrame3(rho, R_DotsSymbol, TRUE)
21f0 <- function() substitute(...(n = 1)); f0()
22## ...(n = 1)
23f1 <- function(...) substitute(...(n = 1)); f1()
24## $n
25## [1] 1
26g0 <- function() {... <- quote(x); substitute(...(n = 1))}; g0()
27## Error in g0() : '...' used in an incorrect context
28g1 <- function(...) {... <- quote(x); substitute(...(n = 1))}; g1()
29## Error in g1() : '...' used in an incorrect context
30h0 <- function() {... <- NULL; substitute(...(n = 1))}; h0()
31## $n
32## [1] 1
33h1 <- function(...) {... <- NULL; substitute(...(n = 1))}; h1()
34## $n
35## [1] 1
36f <- function(...) substitute(...(<exprs>))
37f <- function(...) substitute(...())
38is.null(f())
39## [1] TRUE
40f <- function(...) substitute(...(n = 1))
41identical(f(a = sin(x), b = zzz), pairlist(a = quote(sin(x)), b = quote(zzz), n = 1))
42## [1] TRUE
43 Rprintf("CAR(t) == R_DotsSymbol? %d\n",
44 CAR(t) == R_DotsSymbol);
45 if (TYPEOF(CAR(t)) == LISTSXP || TYPEOF(CAR(t)) == LANGSXP) {
46 Rprintf("TYPEOF(CAR(t)) = %s, length(CAR(t)) = %d\n",
47 type2char(TYPEOF(CAR(t))), length(CAR(t)));
48 Rprintf("CAR(CAR(t)) = R_DotsSymbol? %d\n",
49 CAR(CAR(t)) == R_DotsSymbol);
50 Rprintf("TYPEOF(CDR(CAR(t))) = %s, length(CDR(CAR(t))) = %d\n",
51 type2char(TYPEOF(CDR(CAR(t)))), length(CDR(CAR(t))));
52 }
53 if (TYPEOF(s) == LISTSXP || TYPEOF(s) == LANGSXP) {
54 Rprintf("TYPEOF(s) = %s, length(s) = %d\n",
55 type2char(TYPEOF(s)), length(s));
56 Rprintf("TYPEOF(CAR(s)) = %s, length(CAR(s)) = %d\n",
57 type2char(TYPEOF(CAR(s))), length(CAR(s)));
58 }
59f <- function(...) substitute(...(n = 1))
60invisible(f(hello, world, hello(world)))
61
1f = function(...) substitute(...()); f(a, b)
2[[1]]
3a
4[[2]]
5b
6# but, substitute returns ..1
7f2 = function(...) substitute(...); f2(a, b)
8a
9# \-substitute #R
10# \-do_substitute #C
11# \-substituteList #C recursive
12# \-substitute #C
13parse(text = "(\\(...) substitute(...()))(a, b)") |> getParseData() |> subset(text == "...", select = c(7, 9))
14
15#> token text
16#> 4 SYMBOL_FORMALS ...
17#> 10 SYMBOL_FUNCTION_CALL ...
18typeof(substitute)
19[1] "special"
20findVarInFrame3(rho, R_DotsSymbol, TRUE)
21f0 <- function() substitute(...(n = 1)); f0()
22## ...(n = 1)
23f1 <- function(...) substitute(...(n = 1)); f1()
24## $n
25## [1] 1
26g0 <- function() {... <- quote(x); substitute(...(n = 1))}; g0()
27## Error in g0() : '...' used in an incorrect context
28g1 <- function(...) {... <- quote(x); substitute(...(n = 1))}; g1()
29## Error in g1() : '...' used in an incorrect context
30h0 <- function() {... <- NULL; substitute(...(n = 1))}; h0()
31## $n
32## [1] 1
33h1 <- function(...) {... <- NULL; substitute(...(n = 1))}; h1()
34## $n
35## [1] 1
36f <- function(...) substitute(...(<exprs>))
37f <- function(...) substitute(...())
38is.null(f())
39## [1] TRUE
40f <- function(...) substitute(...(n = 1))
41identical(f(a = sin(x), b = zzz), pairlist(a = quote(sin(x)), b = quote(zzz), n = 1))
42## [1] TRUE
43 Rprintf("CAR(t) == R_DotsSymbol? %d\n",
44 CAR(t) == R_DotsSymbol);
45 if (TYPEOF(CAR(t)) == LISTSXP || TYPEOF(CAR(t)) == LANGSXP) {
46 Rprintf("TYPEOF(CAR(t)) = %s, length(CAR(t)) = %d\n",
47 type2char(TYPEOF(CAR(t))), length(CAR(t)));
48 Rprintf("CAR(CAR(t)) = R_DotsSymbol? %d\n",
49 CAR(CAR(t)) == R_DotsSymbol);
50 Rprintf("TYPEOF(CDR(CAR(t))) = %s, length(CDR(CAR(t))) = %d\n",
51 type2char(TYPEOF(CDR(CAR(t)))), length(CDR(CAR(t))));
52 }
53 if (TYPEOF(s) == LISTSXP || TYPEOF(s) == LANGSXP) {
54 Rprintf("TYPEOF(s) = %s, length(s) = %d\n",
55 type2char(TYPEOF(s)), length(s));
56 Rprintf("TYPEOF(CAR(s)) = %s, length(CAR(s)) = %d\n",
57 type2char(TYPEOF(CAR(s))), length(CAR(s)));
58 }
59f <- function(...) substitute(...(n = 1))
60invisible(f(hello, world, hello(world)))
61CAR(t) == R_DotsSymbol? 0
62TYPEOF(CAR(t)) = language, length(CAR(t)) = 2
63CAR(CAR(t)) = R_DotsSymbol? 1
64TYPEOF(CDR(CAR(t))) = pairlist, length(CDR(CAR(t))) = 1
65TYPEOF(s) = pairlist, length(s) = 1
66TYPEOF(CAR(s)) = pairlist, length(CAR(s)) = 4
67
1f = function(...) substitute(...()); f(a, b)
2[[1]]
3a
4[[2]]
5b
6# but, substitute returns ..1
7f2 = function(...) substitute(...); f2(a, b)
8a
9# \-substitute #R
10# \-do_substitute #C
11# \-substituteList #C recursive
12# \-substitute #C
13parse(text = "(\\(...) substitute(...()))(a, b)") |> getParseData() |> subset(text == "...", select = c(7, 9))
14
15#> token text
16#> 4 SYMBOL_FORMALS ...
17#> 10 SYMBOL_FUNCTION_CALL ...
18typeof(substitute)
19[1] "special"
20findVarInFrame3(rho, R_DotsSymbol, TRUE)
21f0 <- function() substitute(...(n = 1)); f0()
22## ...(n = 1)
23f1 <- function(...) substitute(...(n = 1)); f1()
24## $n
25## [1] 1
26g0 <- function() {... <- quote(x); substitute(...(n = 1))}; g0()
27## Error in g0() : '...' used in an incorrect context
28g1 <- function(...) {... <- quote(x); substitute(...(n = 1))}; g1()
29## Error in g1() : '...' used in an incorrect context
30h0 <- function() {... <- NULL; substitute(...(n = 1))}; h0()
31## $n
32## [1] 1
33h1 <- function(...) {... <- NULL; substitute(...(n = 1))}; h1()
34## $n
35## [1] 1
36f <- function(...) substitute(...(<exprs>))
37f <- function(...) substitute(...())
38is.null(f())
39## [1] TRUE
40f <- function(...) substitute(...(n = 1))
41identical(f(a = sin(x), b = zzz), pairlist(a = quote(sin(x)), b = quote(zzz), n = 1))
42## [1] TRUE
43 Rprintf("CAR(t) == R_DotsSymbol? %d\n",
44 CAR(t) == R_DotsSymbol);
45 if (TYPEOF(CAR(t)) == LISTSXP || TYPEOF(CAR(t)) == LANGSXP) {
46 Rprintf("TYPEOF(CAR(t)) = %s, length(CAR(t)) = %d\n",
47 type2char(TYPEOF(CAR(t))), length(CAR(t)));
48 Rprintf("CAR(CAR(t)) = R_DotsSymbol? %d\n",
49 CAR(CAR(t)) == R_DotsSymbol);
50 Rprintf("TYPEOF(CDR(CAR(t))) = %s, length(CDR(CAR(t))) = %d\n",
51 type2char(TYPEOF(CDR(CAR(t)))), length(CDR(CAR(t))));
52 }
53 if (TYPEOF(s) == LISTSXP || TYPEOF(s) == LANGSXP) {
54 Rprintf("TYPEOF(s) = %s, length(s) = %d\n",
55 type2char(TYPEOF(s)), length(s));
56 Rprintf("TYPEOF(CAR(s)) = %s, length(CAR(s)) = %d\n",
57 type2char(TYPEOF(CAR(s))), length(CAR(s)));
58 }
59f <- function(...) substitute(...(n = 1))
60invisible(f(hello, world, hello(world)))
61CAR(t) == R_DotsSymbol? 0
62TYPEOF(CAR(t)) = language, length(CAR(t)) = 2
63CAR(CAR(t)) = R_DotsSymbol? 1
64TYPEOF(CDR(CAR(t))) = pairlist, length(CDR(CAR(t))) = 1
65TYPEOF(s) = pairlist, length(s) = 1
66TYPEOF(CAR(s)) = pairlist, length(CAR(s)) = 4
67invisible(substitute(...()))
68
1f = function(...) substitute(...()); f(a, b)
2[[1]]
3a
4[[2]]
5b
6# but, substitute returns ..1
7f2 = function(...) substitute(...); f2(a, b)
8a
9# \-substitute #R
10# \-do_substitute #C
11# \-substituteList #C recursive
12# \-substitute #C
13parse(text = "(\\(...) substitute(...()))(a, b)") |> getParseData() |> subset(text == "...", select = c(7, 9))
14
15#> token text
16#> 4 SYMBOL_FORMALS ...
17#> 10 SYMBOL_FUNCTION_CALL ...
18typeof(substitute)
19[1] "special"
20findVarInFrame3(rho, R_DotsSymbol, TRUE)
21f0 <- function() substitute(...(n = 1)); f0()
22## ...(n = 1)
23f1 <- function(...) substitute(...(n = 1)); f1()
24## $n
25## [1] 1
26g0 <- function() {... <- quote(x); substitute(...(n = 1))}; g0()
27## Error in g0() : '...' used in an incorrect context
28g1 <- function(...) {... <- quote(x); substitute(...(n = 1))}; g1()
29## Error in g1() : '...' used in an incorrect context
30h0 <- function() {... <- NULL; substitute(...(n = 1))}; h0()
31## $n
32## [1] 1
33h1 <- function(...) {... <- NULL; substitute(...(n = 1))}; h1()
34## $n
35## [1] 1
36f <- function(...) substitute(...(<exprs>))
37f <- function(...) substitute(...())
38is.null(f())
39## [1] TRUE
40f <- function(...) substitute(...(n = 1))
41identical(f(a = sin(x), b = zzz), pairlist(a = quote(sin(x)), b = quote(zzz), n = 1))
42## [1] TRUE
43 Rprintf("CAR(t) == R_DotsSymbol? %d\n",
44 CAR(t) == R_DotsSymbol);
45 if (TYPEOF(CAR(t)) == LISTSXP || TYPEOF(CAR(t)) == LANGSXP) {
46 Rprintf("TYPEOF(CAR(t)) = %s, length(CAR(t)) = %d\n",
47 type2char(TYPEOF(CAR(t))), length(CAR(t)));
48 Rprintf("CAR(CAR(t)) = R_DotsSymbol? %d\n",
49 CAR(CAR(t)) == R_DotsSymbol);
50 Rprintf("TYPEOF(CDR(CAR(t))) = %s, length(CDR(CAR(t))) = %d\n",
51 type2char(TYPEOF(CDR(CAR(t)))), length(CDR(CAR(t))));
52 }
53 if (TYPEOF(s) == LISTSXP || TYPEOF(s) == LANGSXP) {
54 Rprintf("TYPEOF(s) = %s, length(s) = %d\n",
55 type2char(TYPEOF(s)), length(s));
56 Rprintf("TYPEOF(CAR(s)) = %s, length(CAR(s)) = %d\n",
57 type2char(TYPEOF(CAR(s))), length(CAR(s)));
58 }
59f <- function(...) substitute(...(n = 1))
60invisible(f(hello, world, hello(world)))
61CAR(t) == R_DotsSymbol? 0
62TYPEOF(CAR(t)) = language, length(CAR(t)) = 2
63CAR(CAR(t)) = R_DotsSymbol? 1
64TYPEOF(CDR(CAR(t))) = pairlist, length(CDR(CAR(t))) = 1
65TYPEOF(s) = pairlist, length(s) = 1
66TYPEOF(CAR(s)) = pairlist, length(CAR(s)) = 4
67invisible(substitute(...()))
68CAR(t) == R_DotsSymbol? 0
69TYPEOF(CAR(t)) = language, length(CAR(t)) = 1
70CAR(CAR(t)) = R_DotsSymbol? 1
71TYPEOF(CDR(CAR(t))) = NULL, length(CDR(CAR(t))) = 0
72TYPEOF(s) = pairlist, length(s) = 1
73TYPEOF(CAR(s)) = language, length(CAR(s)) = 1
74
Obviously, compiling R with debugging symbols and running R under a debugger helps, too.
Another puzzleJust noticed this oddity:
1f = function(...) substitute(...()); f(a, b)
2[[1]]
3a
4[[2]]
5b
6# but, substitute returns ..1
7f2 = function(...) substitute(...); f2(a, b)
8a
9# \-substitute #R
10# \-do_substitute #C
11# \-substituteList #C recursive
12# \-substitute #C
13parse(text = "(\\(...) substitute(...()))(a, b)") |> getParseData() |> subset(text == "...", select = c(7, 9))
14
15#> token text
16#> 4 SYMBOL_FORMALS ...
17#> 10 SYMBOL_FUNCTION_CALL ...
18typeof(substitute)
19[1] "special"
20findVarInFrame3(rho, R_DotsSymbol, TRUE)
21f0 <- function() substitute(...(n = 1)); f0()
22## ...(n = 1)
23f1 <- function(...) substitute(...(n = 1)); f1()
24## $n
25## [1] 1
26g0 <- function() {... <- quote(x); substitute(...(n = 1))}; g0()
27## Error in g0() : '...' used in an incorrect context
28g1 <- function(...) {... <- quote(x); substitute(...(n = 1))}; g1()
29## Error in g1() : '...' used in an incorrect context
30h0 <- function() {... <- NULL; substitute(...(n = 1))}; h0()
31## $n
32## [1] 1
33h1 <- function(...) {... <- NULL; substitute(...(n = 1))}; h1()
34## $n
35## [1] 1
36f <- function(...) substitute(...(<exprs>))
37f <- function(...) substitute(...())
38is.null(f())
39## [1] TRUE
40f <- function(...) substitute(...(n = 1))
41identical(f(a = sin(x), b = zzz), pairlist(a = quote(sin(x)), b = quote(zzz), n = 1))
42## [1] TRUE
43 Rprintf("CAR(t) == R_DotsSymbol? %d\n",
44 CAR(t) == R_DotsSymbol);
45 if (TYPEOF(CAR(t)) == LISTSXP || TYPEOF(CAR(t)) == LANGSXP) {
46 Rprintf("TYPEOF(CAR(t)) = %s, length(CAR(t)) = %d\n",
47 type2char(TYPEOF(CAR(t))), length(CAR(t)));
48 Rprintf("CAR(CAR(t)) = R_DotsSymbol? %d\n",
49 CAR(CAR(t)) == R_DotsSymbol);
50 Rprintf("TYPEOF(CDR(CAR(t))) = %s, length(CDR(CAR(t))) = %d\n",
51 type2char(TYPEOF(CDR(CAR(t)))), length(CDR(CAR(t))));
52 }
53 if (TYPEOF(s) == LISTSXP || TYPEOF(s) == LANGSXP) {
54 Rprintf("TYPEOF(s) = %s, length(s) = %d\n",
55 type2char(TYPEOF(s)), length(s));
56 Rprintf("TYPEOF(CAR(s)) = %s, length(CAR(s)) = %d\n",
57 type2char(TYPEOF(CAR(s))), length(CAR(s)));
58 }
59f <- function(...) substitute(...(n = 1))
60invisible(f(hello, world, hello(world)))
61CAR(t) == R_DotsSymbol? 0
62TYPEOF(CAR(t)) = language, length(CAR(t)) = 2
63CAR(CAR(t)) = R_DotsSymbol? 1
64TYPEOF(CDR(CAR(t))) = pairlist, length(CDR(CAR(t))) = 1
65TYPEOF(s) = pairlist, length(s) = 1
66TYPEOF(CAR(s)) = pairlist, length(CAR(s)) = 4
67invisible(substitute(...()))
68CAR(t) == R_DotsSymbol? 0
69TYPEOF(CAR(t)) = language, length(CAR(t)) = 1
70CAR(CAR(t)) = R_DotsSymbol? 1
71TYPEOF(CDR(CAR(t))) = NULL, length(CDR(CAR(t))) = 0
72TYPEOF(s) = pairlist, length(s) = 1
73TYPEOF(CAR(s)) = language, length(CAR(s)) = 1
74g <- function(...) substitute(...(n = 1), new.env())
75gab <- g(a = sin(x), b = zzz)
76typeof(gab)
77## [1] "language"
78gab
79## ...(n = 1)
80
Someone here can do another deep dive to find out why the result is a LANGSXP
rather than a LISTSXP
when you supply env
different from environment()
(including env = NULL
).
QUESTION
Python 3.10 pattern matching (PEP 634) - wildcard in string
Asked 2021-Dec-17 at 10:43I got a large list of JSON objects that I want to parse depending on the start of one of the keys, and just wildcard the rest. A lot of the keys are similar, like "matchme-foo"
and "matchme-bar"
. There is a builtin wildcard, but it is only used for whole values, kinda like an else
.
I might be overlooking something but I can't find a solution anywhere in the proposal:
https://docs.python.org/3/whatsnew/3.10.html#pep-634-structural-pattern-matching
Also a bit more about it in PEP-636:
https://www.python.org/dev/peps/pep-0636/#going-to-the-cloud-mappings
My data looks like this:
1data = [{
2 "id" : "matchme-foo",
3 "message": "hallo this is a message",
4 },{
5 "id" : "matchme-bar",
6 "message": "goodbye",
7 },{
8 "id" : "anotherid",
9 "message": "completely diffrent event"
10 }, ...]
11
I want to do something that can match the id without having to make a long list of |
's.
Something like this:
1data = [{
2 "id" : "matchme-foo",
3 "message": "hallo this is a message",
4 },{
5 "id" : "matchme-bar",
6 "message": "goodbye",
7 },{
8 "id" : "anotherid",
9 "message": "completely diffrent event"
10 }, ...]
11for event in data:
12 match event:
13 case {'id':'matchme-*'}: # Match all 'matchme-' no matter what comes next
14 log.INFO(event['message'])
15 case {'id':'anotherid'}:
16 log.ERROR(event['message'])
17
It's a relatively new addition to Python so there aren't many guides on how to use it yet.
ANSWER
Answered 2021-Dec-17 at 10:43You can use a guard:
1data = [{
2 "id" : "matchme-foo",
3 "message": "hallo this is a message",
4 },{
5 "id" : "matchme-bar",
6 "message": "goodbye",
7 },{
8 "id" : "anotherid",
9 "message": "completely diffrent event"
10 }, ...]
11for event in data:
12 match event:
13 case {'id':'matchme-*'}: # Match all 'matchme-' no matter what comes next
14 log.INFO(event['message'])
15 case {'id':'anotherid'}:
16 log.ERROR(event['message'])
17for event in data:
18 match event:
19 case {'id': x} if x.startswith("matchme"): # guard
20 print(event["message"])
21 case {'id':'anotherid'}:
22 print(event["message"])
23
Quoting from the official documentation,
Guard
We can add an
if
clause to a pattern, known as a “guard”. If the guard isfalse
, match goes on to try the nextcase
block. Note that value capture happens before the guard is evaluated:
1data = [{
2 "id" : "matchme-foo",
3 "message": "hallo this is a message",
4 },{
5 "id" : "matchme-bar",
6 "message": "goodbye",
7 },{
8 "id" : "anotherid",
9 "message": "completely diffrent event"
10 }, ...]
11for event in data:
12 match event:
13 case {'id':'matchme-*'}: # Match all 'matchme-' no matter what comes next
14 log.INFO(event['message'])
15 case {'id':'anotherid'}:
16 log.ERROR(event['message'])
17for event in data:
18 match event:
19 case {'id': x} if x.startswith("matchme"): # guard
20 print(event["message"])
21 case {'id':'anotherid'}:
22 print(event["message"])
23match point:
24 case Point(x, y) if x == y:
25 print(f"The point is located on the diagonal Y=X at {x}.")
26 case Point(x, y):
27 print(f"Point is not on the diagonal.")
28
Community Discussions contain sources that include Stack Exchange Network
Tutorials and Learning Resources in Go
Tutorials and Learning Resources are not available at this moment for Go